From fdb9d76fbda8e1dd0cc9fd43c903c71702d77ad7 Mon Sep 17 00:00:00 2001 From: "Christiane (Tina) Heiligers" Date: Mon, 9 Nov 2020 10:31:21 -0700 Subject: [PATCH 01/21] Uses asCurrentUser in getClusterUuid (#82908) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../usage_collection/server/routes/stats/stats.ts | 14 +++++++++----- .../api_integration/apis/kibana/stats/stats.js | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/plugins/usage_collection/server/routes/stats/stats.ts b/src/plugins/usage_collection/server/routes/stats/stats.ts index ef64d15fabc2d..d38250067053c 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/x-pack/test/api_integration/apis/kibana/stats/stats.js b/x-pack/test/api_integration/apis/kibana/stats/stats.js index f0a41f1f008ba..ae4ddad66863b 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); }); }); From 83e51f56885f9629d6849ce5bad2c2569b6eb91f Mon Sep 17 00:00:00 2001 From: Lee Drengenberg Date: Mon, 9 Nov 2020 11:46:36 -0600 Subject: [PATCH 02/21] add alternate path for x-pack/Cloud test for Lens (#82634) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apps/management/_scripted_fields.js | 152 +++++++++++------- 1 file changed, 93 insertions(+), 59 deletions(-) diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js index 6da9ebed0538a..5ca01f239e762 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' + ); + } }); }); }); From 48dbf9d6535aa3aca01f6215b12ef424f24020a8 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 9 Nov 2020 14:16:18 -0500 Subject: [PATCH 03/21] Add captions to user and space grid pages (#82713) * Add captions to user and space grid pages * Address PR feedback: reword captions * remove unused i18n values Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/management/users/users_grid/users_grid_page.tsx | 4 ++++ .../spaces_grid/__snapshots__/spaces_grid_pages.test.tsx.snap | 2 ++ .../spaces/public/management/spaces_grid/spaces_grid_page.tsx | 4 ++++ 3 files changed, 10 insertions(+) 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 2b7ed0079f291..37747f9a1ccfa 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 b40f34273d99f..68c4a4ff02b94 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 { Date: Mon, 9 Nov 2020 14:43:44 -0500 Subject: [PATCH 04/21] Add alerting as codeowners to related documentation folder (#82777) * Add alerting as codeowners to related docs folders * Move up Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 84076f4c4fbe9..6da2d5d602186 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 From 729631a76d054d891d4de1ca7fef79de3aa3526b Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Mon, 9 Nov 2020 11:56:56 -0800 Subject: [PATCH 05/21] Update 8.0 breaking change template to gather information on how to programmatically detect it. (#82905) --- .github/ISSUE_TEMPLATE/v8_breaking_change.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/v8_breaking_change.md b/.github/ISSUE_TEMPLATE/v8_breaking_change.md index a64ce33b8f976..86e321990d05f 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?** From c6afc47f32e4630d032a7cf4a4c3ee02660ef40b Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Mon, 9 Nov 2020 13:01:22 -0700 Subject: [PATCH 06/21] Remove data <--> expressions circular dependencies. (#82685) --- ...gins-data-public.executioncontextsearch.md | 15 ++++ ...ns-data-public.expressionfunctionkibana.md | 11 +++ ...-public.expressionfunctionkibanacontext.md | 11 +++ ...ta-public.expressionvaluesearchcontext.md} | 2 +- ...ugin-plugins-data-public.kibanacontext.md} | 2 +- .../kibana-plugin-plugins-data-public.md | 5 ++ ...na-plugin-plugins-data-public.searchbar.md | 4 +- ...gins-data-server.executioncontextsearch.md | 15 ++++ ...ns-data-server.expressionfunctionkibana.md | 11 +++ ...-server.expressionfunctionkibanacontext.md | 11 +++ ...ta-server.expressionvaluesearchcontext.md} | 2 +- ...ugin-plugins-data-server.kibanacontext.md} | 2 +- .../kibana-plugin-plugins-data-server.md | 5 ++ ...plugin-plugins-data-server.plugin.setup.md | 4 +- ...plugin-plugins-data-server.plugin.start.md | 4 +- ...ins-expressions-public.executioncontext.md | 2 +- ...ic.expressionfunctiondefinitions.kibana.md | 11 --- ...ssionfunctiondefinitions.kibana_context.md | 11 --- ...ns-public.expressionfunctiondefinitions.md | 2 - ...essions-public.expressionfunctionkibana.md | 11 --- ...ressions-public.iexpressionloaderparams.md | 2 +- ...c.iexpressionloaderparams.searchcontext.md | 2 +- ...-expressions-public.kibana_context_name.md | 11 --- ...ibana-plugin-plugins-expressions-public.md | 4 - ...ins-expressions-server.executioncontext.md | 2 +- ...er.expressionfunctiondefinitions.kibana.md | 11 --- ...ssionfunctiondefinitions.kibana_context.md | 11 --- ...ns-server.expressionfunctiondefinitions.md | 2 - ...essions-server.expressionfunctionkibana.md | 11 --- ...-expressions-server.kibana_context_name.md | 11 --- ...ibana-plugin-plugins-expressions-server.md | 4 - ...ublic.uiactionsservice.addtriggeraction.md | 2 +- ...tions-public.uiactionsservice.getaction.md | 2 +- ...blic.uiactionsservice.gettriggeractions.md | 2 +- ...ionsservice.gettriggercompatibleactions.md | 2 +- ...gins-ui_actions-public.uiactionsservice.md | 10 +-- ...-public.uiactionsservice.registeraction.md | 2 +- .../__snapshots__/kibana.test.ts.snap | 0 .../data/common/search/expressions/esaggs.ts | 7 +- .../data/common/search/expressions/index.ts | 3 + .../common/search/expressions}/kibana.test.ts | 8 +- .../common/search/expressions}/kibana.ts | 10 ++- .../search/expressions}/kibana_context.ts | 21 ++--- .../expressions/kibana_context_type.ts} | 12 ++- .../expressions/utils/function_wrapper.ts | 34 ++++++++ .../common/search/expressions/utils/index.ts | 1 + src/plugins/data/common/utils/index.ts | 1 - src/plugins/data/kibana.json | 2 +- src/plugins/data/public/index.ts | 6 ++ src/plugins/data/public/public.api.md | 80 +++++++++++++------ .../search/errors/timeout_error.test.tsx | 2 +- .../data/public/search/expressions/esdsl.ts | 7 +- .../public/search/search_interceptor.test.ts | 2 +- .../data/public/search/search_interceptor.ts | 7 +- .../data/public/search/search_service.ts | 11 ++- src/plugins/data/server/index.ts | 6 ++ src/plugins/data/server/plugin.ts | 2 +- .../data/server/search/search_service.test.ts | 5 +- .../data/server/search/search_service.ts | 28 ++++--- src/plugins/data/server/server.api.md | 71 +++++++++++----- .../expressions/common/execution/execution.ts | 5 +- .../expressions/common/execution/types.ts | 14 ++-- .../expression_functions/specs/index.ts | 6 -- .../specs/tests/var.test.ts | 3 +- .../specs/tests/var_set.test.ts | 3 +- .../common/expression_functions/types.ts | 4 - .../common/expression_types/specs/index.ts | 3 - .../common/service/expressions_services.ts | 3 +- src/plugins/expressions/kibana.json | 3 +- src/plugins/expressions/public/index.ts | 4 - src/plugins/expressions/public/plugin.test.ts | 17 ---- src/plugins/expressions/public/public.api.md | 32 +------- src/plugins/expressions/public/types/index.ts | 4 +- src/plugins/expressions/server/index.ts | 4 - src/plugins/expressions/server/server.api.md | 30 +------ .../common}/abort_utils.test.ts | 26 +++--- .../common}/abort_utils.ts | 8 +- src/plugins/kibana_utils/common/index.ts | 1 + src/plugins/kibana_utils/public/index.ts | 3 + src/plugins/kibana_utils/server/index.ts | 3 + src/plugins/ui_actions/public/public.api.md | 10 +-- .../helpers/timelion_request_handler.ts | 5 +- .../public/timelion_vis_fn.ts | 8 +- .../vis_type_timeseries/public/metrics_fn.ts | 3 +- src/plugins/vis_type_vega/public/vega_fn.ts | 12 +-- x-pack/plugins/canvas/types/state.ts | 2 +- .../search/es_search/es_search_rxjs_utils.ts | 2 +- .../public/search/search_interceptor.test.ts | 3 +- .../public/search/search_interceptor.ts | 4 +- .../editor_frame/suggestion_panel.tsx | 3 +- .../workspace_panel/workspace_panel.tsx | 10 +-- .../embeddable/embeddable.tsx | 2 +- .../embeddable/expression_wrapper.tsx | 2 +- .../editor_frame_service/merge_tables.test.ts | 3 +- .../editor_frame_service/merge_tables.ts | 5 +- .../public/xy_visualization/expression.tsx | 6 +- .../events/last_event_time/index.ts | 2 +- .../containers/matrix_histogram/index.ts | 7 +- .../public/common/containers/source/index.tsx | 2 +- .../common/hooks/eql/use_eql_preview.ts | 2 +- .../containers/authentications/index.tsx | 7 +- .../hosts/containers/hosts/details/_index.tsx | 2 +- .../hosts/first_last_seen/index.tsx | 2 +- .../public/hosts/containers/hosts/index.tsx | 7 +- .../kpi_hosts/authentications/index.tsx | 2 +- .../containers/kpi_hosts/hosts/index.tsx | 2 +- .../containers/kpi_hosts/unique_ips/index.tsx | 2 +- .../containers/uncommon_processes/index.tsx | 7 +- .../network/containers/details/index.tsx | 7 +- .../containers/kpi_network/dns/index.tsx | 2 +- .../kpi_network/network_events/index.tsx | 2 +- .../kpi_network/tls_handshakes/index.tsx | 2 +- .../kpi_network/unique_flows/index.tsx | 2 +- .../kpi_network/unique_private_ips/index.tsx | 2 +- .../network/containers/network_dns/index.tsx | 7 +- .../network/containers/network_http/index.tsx | 7 +- .../network_top_countries/index.tsx | 7 +- .../containers/network_top_n_flow/index.tsx | 7 +- .../public/network/containers/tls/index.tsx | 7 +- .../public/network/containers/users/index.tsx | 7 +- .../containers/overview_host/index.tsx | 7 +- .../containers/overview_network/index.tsx | 7 +- .../translations/translations/ja-JP.json | 12 +-- .../translations/translations/zh-CN.json | 12 +-- 124 files changed, 472 insertions(+), 483 deletions(-) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.executioncontextsearch.md create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibana.md create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.expressionfunctionkibanacontext.md rename docs/development/plugins/{expressions/server/kibana-plugin-plugins-expressions-server.expressionvaluesearchcontext.md => data/public/kibana-plugin-plugins-data-public.expressionvaluesearchcontext.md} (54%) rename docs/development/plugins/{expressions/public/kibana-plugin-plugins-expressions-public.kibanacontext.md => data/public/kibana-plugin-plugins-data-public.kibanacontext.md} (51%) create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.executioncontextsearch.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibana.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.expressionfunctionkibanacontext.md rename docs/development/plugins/{expressions/public/kibana-plugin-plugins-expressions-public.expressionvaluesearchcontext.md => data/server/kibana-plugin-plugins-data-server.expressionvaluesearchcontext.md} (54%) rename docs/development/plugins/{expressions/server/kibana-plugin-plugins-expressions-server.kibanacontext.md => data/server/kibana-plugin-plugins-data-server.kibanacontext.md} (51%) delete mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana.md delete mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctiondefinitions.kibana_context.md delete mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionfunctionkibana.md delete mode 100644 docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.kibana_context_name.md delete mode 100644 docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana.md delete mode 100644 docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctiondefinitions.kibana_context.md delete mode 100644 docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionfunctionkibana.md delete mode 100644 docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.kibana_context_name.md rename src/plugins/{expressions/common/expression_functions/specs/tests => data/common/search/expressions}/__snapshots__/kibana.test.ts.snap (100%) rename src/plugins/{expressions/common/expression_functions/specs/tests => data/common/search/expressions}/kibana.test.ts (92%) rename src/plugins/{expressions/common/expression_functions/specs => data/common/search/expressions}/kibana.ts (82%) rename src/plugins/{expressions/common/expression_functions/specs => data/common/search/expressions}/kibana_context.ts (84%) rename src/plugins/{expressions/common/expression_types/specs/kibana_context.ts => data/common/search/expressions/kibana_context_type.ts} (79%) create mode 100644 src/plugins/data/common/search/expressions/utils/function_wrapper.ts rename src/plugins/{data/common/utils => kibana_utils/common}/abort_utils.test.ts (84%) rename src/plugins/{data/common/utils => kibana_utils/common}/abort_utils.ts (91%) 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 0000000000000..67dcb2fa44241 --- /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 0000000000000..c91f2e8144ead --- /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 0000000000000..97d2e81d45554 --- /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 6e38adde3ba91..4849d82b94a62 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/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 108533e8de357..cb8842c66761d 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 255a9947858f6..bafcd8bdffff9 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 d1d20291a6799..bb45222d096a0 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 0000000000000..2f94dbe970d44 --- /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 0000000000000..d80ff78dd803c --- /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 0000000000000..b67f7b8c4b60d --- /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 bf64dfe4c86f7..8015482ddec1e 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/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 023748173e7dd..1ddc43c633b26 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 82d0a5a3182b9..49cf12486cbb8 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 @@ -88,6 +88,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 +100,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.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index 139c5794f0146..43129891c5412 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 03d3485fce9ee..555a5c2374da7 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) => 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) => 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 2a1a78b8fcb1a..86d24534f7a44 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 abe8e0ae161ad..0000000000000 --- 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 4b58fd84e160d..0000000000000 --- 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 53f090ea30c3f..c6e00842a31e6 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 8ccf48ba28527..0000000000000 --- 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 e2ad6215e25d0..2dfc67d2af5fa 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 523d0c562f7ca..6b5fad950c4e9 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 e568db84f383d..0000000000000 --- 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 db09f966e2fa5..a03ea32482011 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 047879fd99255..e2547cc9470d1 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 8e6d189f8f450..0000000000000 --- 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 f9e248ad6d913..0000000000000 --- 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 6f152bb10b37e..219678244951b 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 aac2ae1c3ca4e..0000000000000 --- 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 bd47c52e0d5ce..0000000000000 --- 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 9e2189dad2732..5f7f373cd927f 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 ba9060e01e57d..5a1ab83551d34 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 3e433809f9471..5b0b3eea01cb1 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 83afcab29689d..2dda422046318 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 879f5a3d8628a..e087753726a8a 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 7fade7c4c841b..f9eb693b492f7 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 eeda7b503037d..bd340eb76fbac 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/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 4f65babdcd360..47d97a81a67b1 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 25839a805d8c5..28d892d091956 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 e5c4b92de4fdb..58fee1ee1f6a6 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 3ec4c23eab28d..c31219284760a 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 2b7d1b8ed9d76..7bf14ff02316e 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 3af7b990429c0..a5b459a607991 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 0000000000000..b5e45d9ca1de0 --- /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 75c1809770c78..39f88b0f13fee 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 33989f3ad50a7..8b8686c51b9c1 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 9cb9b1745373a..d6f2534bd5e3b 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 ce020a9742399..129addf3de70e 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/public.api.md b/src/plugins/data/public/public.api.md index d52edbe5b11dd..bc2bb2663f163 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) // @@ -1368,7 +1397,7 @@ export interface IndexPatternTypeMeta { // @public (undocumented) export const injectSearchSourceReferences: (searchSourceFields: SearchSourceFields & { indexRefName: string; -}, references: SavedObjectReference_2[]) => 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 ad3384c389fbf..2547ee41cbbd7 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 2efb21671b5b7..07e904928744f 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 472caa5e4f45f..60274261da25f 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 3584d75ab86bb..78e65802bcf99 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 e5a50077518af..96fb3f91ea85f 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 9a9b8b67730cc..0e9736c9e256a 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -206,6 +206,12 @@ export { OptionedParamType, OptionedValueProp, ParsedInterval, + // expressions + ExecutionContextSearch, + ExpressionFunctionKibana, + ExpressionFunctionKibanaContext, + ExpressionValueSearchContext, + KibanaContext, // search ISearchOptions, IEsSearchRequest, diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index 88f24b7ca5a70..3ec4e7e64e382 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/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index 2b513be147e9d..0700afd8d6c83 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 c500c62914c0b..c5a60c42a41c9 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); } }); diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index f62a70c9e4ce1..5b0e0499e29bf 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,18 @@ 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 { 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 +60,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 +228,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 +288,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) @@ -779,6 +807,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) @@ -885,7 +918,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 +927,7 @@ export class Plugin implements Plugin_2 Promise; }; indexPatterns: { - indexPatternsServiceFactory: (savedObjectsClient: Pick) => Promise; + indexPatternsServiceFactory: (savedObjectsClient: Pick) => Promise; }; search: ISearchStart>; }; @@ -1162,21 +1195,21 @@ 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.ts:241:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:256:5 - (ae-forgotten-export) The symbol "getTotalLoaded" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:257:5 - (ae-forgotten-export) The symbol "toSnakeCase" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:261:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:271:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:272:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:273:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:277:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:278:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:282:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:285: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/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/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index ba115a7538604..50a469c338d73 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 50475c3bd94ae..abe3e08fc20c2 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 11706f65dbd32..10ccd014fd7bd 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 762f34e3f5566..efcb5555cc63b 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 365ae5b89baea..17d9c4ab98c1a 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 4a93cfa9211ff..52e4b4d9facf3 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 00c52a2545cd6..ec8dee1f7fc52 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 01289ca1ae57a..c9cc0680360bb 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 67bbf4b6e5454..23c7fe722fdb3 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 893d68238747d..385055bc2fdc2 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 d9dde1f6def68..0b21fe354d3d3 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 773d61ebe2e28..17f8e6255f6bb 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 1643b5734ef1a..4af36fea169a1 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 cc22d4b500d97..287b91049b1ae 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 27a3193bf7894..e5b499206ebdd 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 358f00e5e82bd..8ccbf752b4d1b 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 81f30b7454c7b..dd8db34931693 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 e09290c811c7b..a49b7100594ba 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 9ba42d39139da..46a0cc4a10f00 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 bf3361d1e5369..d994a4940bdfd 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 8393f7480d4e4..3e40c94e116fb 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/vis_type_timelion/public/helpers/timelion_request_handler.ts b/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts index 1f0ac8b2b9392..7a630f36b51f4 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 a0cd410e197ff..2e8878b11e915 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/public/metrics_fn.ts b/src/plugins/vis_type_timeseries/public/metrics_fn.ts index b573225feaab1..8652d703f963e 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_vega/public/vega_fn.ts b/src/plugins/vis_type_vega/public/vega_fn.ts index 25d4e76c336b3..5a8113aeeea11 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/x-pack/plugins/canvas/types/state.ts b/x-pack/plugins/canvas/types/state.ts index 60407b78ab5e3..03bb931dc9b26 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 2d5d09fd0205e..f38bec6d1f59f 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 f47d2b39a89a9..044489d58eb0e 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 4cafcdb29ae8d..d36741ae6576d 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/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 2e24b64ecca26..97165a8513078 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 e0dd3b3fe01ae..00cb932a6d4e2 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 33e5dee99081f..8139631daa971 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 7479577805bdd..4a3ba971381fb 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 07c16665d11b4..02c07d809e09f 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 03ef7cf9cc637..109b30144fc20 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/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index d238e052a7c7f..730f8508e2889 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/security_solution/public/common/containers/events/last_event_time/index.ts b/x-pack/plugins/security_solution/public/common/containers/events/last_event_time/index.ts index 2d85c1d60a7b0..b6938bc18a88d 100644 --- a/x-pack/plugins/security_solution/public/common/containers/events/last_event_time/index.ts +++ b/x-pack/plugins/security_solution/public/common/containers/events/last_event_time/index.ts @@ -18,10 +18,10 @@ import { LastEventIndexKey, } from '../../../../../common/search_strategy/timeline'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import * as i18n from './translations'; import { DocValueFields } from '../../../../../common/search_strategy'; diff --git a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts index 8db513da1f3a1..a2cf59314d149 100644 --- a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts +++ b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts @@ -18,11 +18,8 @@ import { MatrixHistogramStrategyResponse, MatrixHistogramData, } from '../../../../common/search_strategy/security_solution'; -import { - AbortError, - isErrorResponse, - isCompleteResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isErrorResponse, isCompleteResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/common/containers/source/index.tsx b/x-pack/plugins/security_solution/public/common/containers/source/index.tsx index 47e550b2ced0f..7e73a40f2f748 100644 --- a/x-pack/plugins/security_solution/public/common/containers/source/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/source/index.tsx @@ -18,7 +18,7 @@ import { BrowserField, BrowserFields, } from '../../../../common/search_strategy/index_fields'; -import { AbortError } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { useShallowEqualSelector } from '../../../common/hooks/use_selector'; import * as i18n from './translations'; import { SourcererScopeName } from '../../store/sourcerer/model'; diff --git a/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts b/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts index 93236381753bf..1f4424a4f28b8 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts @@ -11,11 +11,11 @@ import { takeUntil } from 'rxjs/operators'; import * as i18n from '../translations'; import { useKibana } from '../../../common/lib/kibana'; import { - AbortError, isCompleteResponse, isErrorResponse, isPartialResponse, } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { EqlSearchStrategyRequest, EqlSearchStrategyResponse, diff --git a/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.tsx index 3cc87bdd275df..d964366dc5f3d 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.tsx @@ -8,11 +8,8 @@ import { noop } from 'lodash/fp'; import { useCallback, useEffect, useRef, useState } from 'react'; import deepEqual from 'fast-deep-equal'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { HostsQueries } from '../../../../common/search_strategy/security_solution'; import { diff --git a/x-pack/plugins/security_solution/public/hosts/containers/hosts/details/_index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/hosts/details/_index.tsx index 61c3f63bdb4aa..54381d1ffd836 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/hosts/details/_index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/details/_index.tsx @@ -21,10 +21,10 @@ import { import * as i18n from './translations'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/hosts/first_last_seen/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/hosts/first_last_seen/index.tsx index cc944a59571f1..1cb13da2048ad 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/hosts/first_last_seen/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/first_last_seen/index.tsx @@ -17,10 +17,10 @@ import { import * as i18n from './translations'; import { DocValueFields } from '../../../../../common/search_strategy'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; const ID = 'firstLastSeenHostQuery'; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx index 1228f94c7a39a..c1081d22e12a4 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx @@ -25,11 +25,8 @@ import { import { ESTermQuery } from '../../../../common/typed_json'; import * as i18n from './translations'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/authentications/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/authentications/index.tsx index d433fef98bece..281f8489fce0f 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/authentications/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/authentications/index.tsx @@ -19,7 +19,7 @@ import { import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; -import { AbortError } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/hosts/index.tsx index 13d9bf368fc3d..ff4539fd379ed 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/hosts/index.tsx @@ -19,7 +19,7 @@ import { import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; -import { AbortError } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/unique_ips/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/unique_ips/index.tsx index fb1d0e05dd2a0..906a1d2716513 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/unique_ips/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/kpi_hosts/unique_ips/index.tsx @@ -19,7 +19,7 @@ import { import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; -import { AbortError } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/uncommon_processes/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/uncommon_processes/index.tsx index ec792a6cad075..821b2895ac3f9 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/uncommon_processes/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/uncommon_processes/index.tsx @@ -9,11 +9,8 @@ import { noop } from 'lodash/fp'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { inputsModel, State } from '../../../common/store'; import { useKibana } from '../../../common/lib/kibana'; diff --git a/x-pack/plugins/security_solution/public/network/containers/details/index.tsx b/x-pack/plugins/security_solution/public/network/containers/details/index.tsx index 2d5ed093ca1e4..8a80d073d4beb 100644 --- a/x-pack/plugins/security_solution/public/network/containers/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/details/index.tsx @@ -18,11 +18,8 @@ import { NetworkDetailsRequestOptions, NetworkDetailsStrategyResponse, } from '../../../../common/search_strategy'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import * as i18n from './translations'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; diff --git a/x-pack/plugins/security_solution/public/network/containers/kpi_network/dns/index.tsx b/x-pack/plugins/security_solution/public/network/containers/kpi_network/dns/index.tsx index 65f10a03cf13d..39868af2ae14d 100644 --- a/x-pack/plugins/security_solution/public/network/containers/kpi_network/dns/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/kpi_network/dns/index.tsx @@ -20,10 +20,10 @@ import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/network/containers/kpi_network/network_events/index.tsx b/x-pack/plugins/security_solution/public/network/containers/kpi_network/network_events/index.tsx index a8f1a7abe2d44..3a4ce40fb8b80 100644 --- a/x-pack/plugins/security_solution/public/network/containers/kpi_network/network_events/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/kpi_network/network_events/index.tsx @@ -20,10 +20,10 @@ import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/network/containers/kpi_network/tls_handshakes/index.tsx b/x-pack/plugins/security_solution/public/network/containers/kpi_network/tls_handshakes/index.tsx index 61861de9c0033..40cd04207b2d9 100644 --- a/x-pack/plugins/security_solution/public/network/containers/kpi_network/tls_handshakes/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/kpi_network/tls_handshakes/index.tsx @@ -20,10 +20,10 @@ import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_flows/index.tsx b/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_flows/index.tsx index 594fc2a2adcfa..a2a64d0770558 100644 --- a/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_flows/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_flows/index.tsx @@ -20,10 +20,10 @@ import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_private_ips/index.tsx b/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_private_ips/index.tsx index 8484f1388caac..d183eb243e158 100644 --- a/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_private_ips/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/kpi_network/unique_private_ips/index.tsx @@ -21,10 +21,10 @@ import { ESTermQuery } from '../../../../../common/typed_json'; import * as i18n from './translations'; import { - AbortError, isCompleteResponse, isErrorResponse, } from '../../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../../helpers'; import { InspectResponse } from '../../../../types'; diff --git a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx index 92a8f8c49dfc6..fc00f8866ed2e 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx @@ -22,11 +22,8 @@ import { NetworkDnsStrategyResponse, MatrixOverOrdinalHistogramData, } from '../../../../common/search_strategy/security_solution/network'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import * as i18n from './translations'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; diff --git a/x-pack/plugins/security_solution/public/network/containers/network_http/index.tsx b/x-pack/plugins/security_solution/public/network/containers/network_http/index.tsx index e4fa68b75999f..8edb760429a7c 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_http/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_http/index.tsx @@ -23,11 +23,8 @@ import { NetworkHttpStrategyResponse, SortField, } from '../../../../common/search_strategy'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import * as i18n from './translations'; import { InspectResponse } from '../../../types'; import { getInspectResponse } from '../../../helpers'; diff --git a/x-pack/plugins/security_solution/public/network/containers/network_top_countries/index.tsx b/x-pack/plugins/security_solution/public/network/containers/network_top_countries/index.tsx index 4b0ea2b82855b..0676d5976e211 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_top_countries/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_top_countries/index.tsx @@ -23,11 +23,8 @@ import { NetworkTopCountriesStrategyResponse, PageInfoPaginated, } from '../../../../common/search_strategy'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/network/containers/network_top_n_flow/index.tsx b/x-pack/plugins/security_solution/public/network/containers/network_top_n_flow/index.tsx index 342fbbf67be4d..49ff6016900a5 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_top_n_flow/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_top_n_flow/index.tsx @@ -23,11 +23,8 @@ import { NetworkTopNFlowStrategyResponse, PageInfoPaginated, } from '../../../../common/search_strategy'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/network/containers/tls/index.tsx b/x-pack/plugins/security_solution/public/network/containers/tls/index.tsx index 336aaec1d4bc9..8abd91186465a 100644 --- a/x-pack/plugins/security_solution/public/network/containers/tls/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/tls/index.tsx @@ -21,11 +21,8 @@ import { NetworkTlsRequestOptions, NetworkTlsStrategyResponse, } from '../../../../common/search_strategy/security_solution/network'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import * as i18n from './translations'; import { getInspectResponse } from '../../../helpers'; diff --git a/x-pack/plugins/security_solution/public/network/containers/users/index.tsx b/x-pack/plugins/security_solution/public/network/containers/users/index.tsx index 8f21a23417aae..75f28773b89f6 100644 --- a/x-pack/plugins/security_solution/public/network/containers/users/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/users/index.tsx @@ -23,11 +23,8 @@ import { NetworkUsersRequestOptions, NetworkUsersStrategyResponse, } from '../../../../common/search_strategy/security_solution/network'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import * as i18n from './translations'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_host/index.tsx b/x-pack/plugins/security_solution/public/overview/containers/overview_host/index.tsx index 3c59ff7ba36c2..edf68750e2fdd 100644 --- a/x-pack/plugins/security_solution/public/overview/containers/overview_host/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_host/index.tsx @@ -17,11 +17,8 @@ import { useKibana } from '../../../common/lib/kibana'; import { inputsModel } from '../../../common/store/inputs'; import { createFilter } from '../../../common/containers/helpers'; import { ESQuery } from '../../../../common/typed_json'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/overview/containers/overview_network/index.tsx b/x-pack/plugins/security_solution/public/overview/containers/overview_network/index.tsx index 7f659db70277f..c414276c1a615 100644 --- a/x-pack/plugins/security_solution/public/overview/containers/overview_network/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/containers/overview_network/index.tsx @@ -17,11 +17,8 @@ import { useKibana } from '../../../common/lib/kibana'; import { inputsModel } from '../../../common/store/inputs'; import { createFilter } from '../../../common/containers/helpers'; import { ESQuery } from '../../../../common/typed_json'; -import { - AbortError, - isCompleteResponse, - isErrorResponse, -} from '../../../../../../../src/plugins/data/common'; +import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; +import { AbortError } from '../../../../../../../src/plugins/kibana_utils/common'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; import * as i18n from './translations'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d67cc06463942..e270996d62093 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1662,12 +1662,12 @@ "expressions.functions.font.invalidFontWeightErrorMessage": "無効なフォント太さ:'{weight}'", "expressions.functions.font.invalidTextAlignmentErrorMessage": "無効なテキストアラインメント:'{align}'", "expressions.functions.fontHelpText": "フォントスタイルを作成します。", - "expressions.functions.kibana_context.filters.help": "Kibana ジェネリックフィルターを指定します", - "expressions.functions.kibana_context.help": "Kibana グローバルコンテキストを更新します", - "expressions.functions.kibana_context.q.help": "自由形式の Kibana テキストクエリを指定します", - "expressions.functions.kibana_context.savedSearchId.help": "クエリとフィルターに使用する保存検索ID を指定します。", - "expressions.functions.kibana_context.timeRange.help": "Kibana 時間範囲フィルターを指定します", - "expressions.functions.kibana.help": "Kibana グローバルコンテキストを取得します", + "data.search.functions.kibana_context.filters.help": "Kibana ジェネリックフィルターを指定します", + "data.search.functions.kibana_context.help": "Kibana グローバルコンテキストを更新します", + "data.search.functions.kibana_context.q.help": "自由形式の Kibana テキストクエリを指定します", + "data.search.functions.kibana_context.savedSearchId.help": "クエリとフィルターに使用する保存検索ID を指定します。", + "data.search.functions.kibana_context.timeRange.help": "Kibana 時間範囲フィルターを指定します", + "data.search.functions.kibana.help": "Kibana グローバルコンテキストを取得します", "expressions.functions.theme.args.defaultHelpText": "テーマ情報がない場合のデフォルト値。", "expressions.functions.theme.args.variableHelpText": "読み取るテーマ変数名。", "expressions.functions.themeHelpText": "テーマ設定を読み取ります。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 103aef656c4e1..7bf0a22a4dce7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1663,12 +1663,12 @@ "expressions.functions.font.invalidFontWeightErrorMessage": "无效的字体粗细:“{weight}”", "expressions.functions.font.invalidTextAlignmentErrorMessage": "无效的文本对齐方式:“{align}”", "expressions.functions.fontHelpText": "创建字体样式。", - "expressions.functions.kibana_context.filters.help": "指定 Kibana 常规筛选", - "expressions.functions.kibana_context.help": "更新 kibana 全局上下文", - "expressions.functions.kibana_context.q.help": "指定 Kibana 自由格式文本查询", - "expressions.functions.kibana_context.savedSearchId.help": "指定要用于查询和筛选的已保存搜索 ID", - "expressions.functions.kibana_context.timeRange.help": "指定 Kibana 时间范围筛选", - "expressions.functions.kibana.help": "获取 kibana 全局上下文", + "data.search.functions.kibana_context.filters.help": "指定 Kibana 常规筛选", + "data.search.functions.kibana_context.help": "更新 kibana 全局上下文", + "data.search.functions.kibana_context.q.help": "指定 Kibana 自由格式文本查询", + "data.search.functions.kibana_context.savedSearchId.help": "指定要用于查询和筛选的已保存搜索 ID", + "data.search.functions.kibana_context.timeRange.help": "指定 Kibana 时间范围筛选", + "data.search.functions.kibana.help": "获取 kibana 全局上下文", "expressions.functions.theme.args.defaultHelpText": "主题信息不可用时的默认值。", "expressions.functions.theme.args.variableHelpText": "要读取的主题变量的名称。", "expressions.functions.themeHelpText": "读取主题设置。", From ae6f5afe8d4e1d8f8ee5af7712295d78ec4850be Mon Sep 17 00:00:00 2001 From: Lee Drengenberg Date: Mon, 9 Nov 2020 15:58:16 -0600 Subject: [PATCH 07/21] load empty_kibana in test to have clean starting point (#82772) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- test/functional/apps/management/_mgmt_import_saved_objects.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/functional/apps/management/_mgmt_import_saved_objects.js b/test/functional/apps/management/_mgmt_import_saved_objects.js index 3a9f8665fd33b..d479a7006d0f8 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(); }); From 04c583e2b0ccef54bd25803b021b8e580fee6c90 Mon Sep 17 00:00:00 2001 From: Constance Date: Mon, 9 Nov 2020 14:10:22 -0800 Subject: [PATCH 08/21] [App Search] Misc naming tech debt (#82770) * Rename `engine_overview` folder to `engines` - To better match ent-search folder structure - Also rename/clarify pluralization of "Engines" where possible, to distinguish between individual Engine Overview pages * DRY out Engines and Meta Engines titles * DRY out Credentials title * DRY out Settings title * DRY out Role Mappings title * Update localization keys to match changes Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/credentials/constants.ts | 6 ++++ .../components/credentials/credentials.tsx | 15 ++------- .../components/credentials/index.ts | 1 + .../app_search/components/engine/constants.ts | 4 --- .../components/engine/engine_nav.tsx | 2 +- .../assets/engine_icon.tsx | 0 .../assets/meta_engine_icon.tsx | 0 .../components/empty_state.scss | 0 .../components/empty_state.test.tsx | 0 .../components/empty_state.tsx | 4 +-- .../components/header.test.tsx | 8 ++--- .../components/header.tsx | 4 +-- .../components/index.ts | 2 +- .../components/loading_state.test.tsx | 0 .../components/loading_state.tsx | 4 +-- .../components/engines/constants.ts | 16 +++++++++ .../engines_overview.scss} | 2 +- .../engines_overview.test.tsx} | 24 +++++++------- .../engines_overview.tsx} | 29 +++++++--------- .../engines_table.test.tsx} | 11 ++++--- .../engines_table.tsx} | 16 ++++----- .../app_search/components/engines/index.ts | 8 +++++ .../components/role_mappings/constants.ts | 12 +++++++ .../index.ts | 2 +- .../components/settings/constants.ts | 11 +++++++ .../app_search/components/settings/index.ts | 1 + .../components/settings/settings.tsx | 17 +++------- .../applications/app_search/index.test.tsx | 4 +-- .../public/applications/app_search/index.tsx | 33 +++++-------------- .../translations/translations/ja-JP.json | 11 +++---- .../translations/translations/zh-CN.json | 11 +++---- 31 files changed, 135 insertions(+), 123 deletions(-) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/assets/engine_icon.tsx (100%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/assets/meta_engine_icon.tsx (100%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/empty_state.scss (100%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/empty_state.test.tsx (100%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/empty_state.tsx (96%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/header.test.tsx (82%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/header.tsx (93%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/index.ts (87%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/loading_state.test.tsx (100%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => engines}/components/loading_state.tsx (89%) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/constants.ts rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview/engine_overview.scss => engines/engines_overview.scss} (96%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview/engine_overview.test.tsx => engines/engines_overview.test.tsx} (80%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview/engine_overview.tsx => engines/engines_overview.tsx} (83%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview/engine_table.test.tsx => engines/engines_table.test.tsx} (91%) rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview/engine_table.tsx => engines/engines_table.tsx} (92%) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/constants.ts rename x-pack/plugins/enterprise_search/public/applications/app_search/components/{engine_overview => role_mappings}/index.ts (82%) create mode 100644 x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/constants.ts 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 decf1e2158744..ea4906ec08946 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 c8eae8cc13f5f..72b02dfdc1f61 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 bceda234175a7..0fc64a43ffa85 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 ee5b47eda490e..3c963e415f33b 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 e5ee392b34c01..f92fefc7124b8 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 b7ed1cc895097..95142782d2272 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 4bb69bafa0996..3faa74be11e98 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 794053f184f8c..cb2e0f825d455 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 832a133ed43c7..8e2166d2ef105 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 0000000000000..12545c59b40a0 --- /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 5e8a20ba425ad..c956f3da562f6 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 f87ea2d422780..61f783a8b6c2e 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 c0fd254567910..559fef695d63b 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 abeaf45e6aee8..a9cf64b3dffda 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/engines/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts new file mode 100644 index 0000000000000..76ca9239a3c7e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engines/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +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 0000000000000..133d8b604381b --- /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/enterprise_search/public/applications/app_search/components/engine_overview/index.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/role_mappings/index.ts similarity index 82% 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/role_mappings/index.ts index 48b7645dc39e8..662b91bb3e925 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/role_mappings/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EngineOverview } from './engine_overview'; +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 0000000000000..c7b22d740341c --- /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 db74dcb1a1846..3e162a4a2a1bc 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 e5e86f3e39734..13079bb380f13 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 700b903efe59b..11387734e9f9e 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 f32b0b256b898..4571ef10286e4 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/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e270996d62093..d8e136567564e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6930,8 +6930,8 @@ "xpack.enterpriseSearch.appSearch.emptyState.createFirstEngineCta": "エンジンを作成", "xpack.enterpriseSearch.appSearch.emptyState.description1": "App Searchエンジンは、検索エクスペリエンスのために、ドキュメントを格納します。", "xpack.enterpriseSearch.appSearch.emptyState.title": "初めてのエンジンの作成", - "xpack.enterpriseSearch.appSearch.enginesOverview.engines": "エンジン", - "xpack.enterpriseSearch.appSearch.enginesOverview.metaEngines": "メタエンジン", + "xpack.enterpriseSearch.appSearch.engines.title": "エンジン", + "xpack.enterpriseSearch.appSearch.metaEngines.title": "メタエンジン", "xpack.enterpriseSearch.appSearch.enginesOverview.table.action.manage": "管理", "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.actions": "アクション", "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.createdAt": "作成日時", @@ -6939,10 +6939,9 @@ "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.fieldCount": "フィールドカウント", "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.name": "名前", "xpack.enterpriseSearch.appSearch.enginesOverview.title": "エンジン概要", - "xpack.enterpriseSearch.appSearch.nav.credentials": "資格情報", - "xpack.enterpriseSearch.appSearch.nav.engines": "エンジン", - "xpack.enterpriseSearch.appSearch.nav.roleMappings": "ロールマッピング", - "xpack.enterpriseSearch.appSearch.nav.settings": "アカウント設定", + "xpack.enterpriseSearch.appSearch.credentials.title": "資格情報", + "xpack.enterpriseSearch.appSearch.roleMappings.title": "ロールマッピング", + "xpack.enterpriseSearch.appSearch.settings.title": "アカウント設定", "xpack.enterpriseSearch.appSearch.productCardDescription": "Elastic App Searchには、強力な検索を設計し、WebサイトやWeb/モバイルアプリケーションにデプロイするための使いやすいツールがあります。", "xpack.enterpriseSearch.appSearch.productCta": "App Searchの起動", "xpack.enterpriseSearch.appSearch.productDescription": "ダッシュボード、分析、APIを活用し、高度なアプリケーション検索をシンプルにします。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 7bf0a22a4dce7..84cc3510ce487 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6936,8 +6936,8 @@ "xpack.enterpriseSearch.appSearch.emptyState.createFirstEngineCta": "创建引擎", "xpack.enterpriseSearch.appSearch.emptyState.description1": "App Search 引擎存储文档以提升您的搜索体验。", "xpack.enterpriseSearch.appSearch.emptyState.title": "创建您的首个引擎", - "xpack.enterpriseSearch.appSearch.enginesOverview.engines": "引擎", - "xpack.enterpriseSearch.appSearch.enginesOverview.metaEngines": "元引擎", + "xpack.enterpriseSearch.appSearch.engines.title": "引擎", + "xpack.enterpriseSearch.appSearch.metaEngines.title": "元引擎", "xpack.enterpriseSearch.appSearch.enginesOverview.table.action.manage": "管理", "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.actions": "操作", "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.createdAt": "创建于", @@ -6945,10 +6945,9 @@ "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.fieldCount": "字段计数", "xpack.enterpriseSearch.appSearch.enginesOverview.table.column.name": "名称", "xpack.enterpriseSearch.appSearch.enginesOverview.title": "引擎概览", - "xpack.enterpriseSearch.appSearch.nav.credentials": "凭据", - "xpack.enterpriseSearch.appSearch.nav.engines": "引擎", - "xpack.enterpriseSearch.appSearch.nav.roleMappings": "角色映射", - "xpack.enterpriseSearch.appSearch.nav.settings": "帐户设置", + "xpack.enterpriseSearch.appSearch.credentials.title": "凭据", + "xpack.enterpriseSearch.appSearch.roleMappings.title": "角色映射", + "xpack.enterpriseSearch.appSearch.settings.title": "帐户设置", "xpack.enterpriseSearch.appSearch.productCardDescription": "Elastic App Search 提供用户友好的工具,用于设计强大的搜索功能,并将其部署到您的网站或 Web/移动应用程序。", "xpack.enterpriseSearch.appSearch.productCta": "启动 App Search", "xpack.enterpriseSearch.appSearch.productDescription": "利用仪表板、分析和 API 执行高级应用程序搜索简单易行。", From bf758312cdba1986a4cd99cc6c011185f66ec15e Mon Sep 17 00:00:00 2001 From: IgorG <56408662+IgorGuz2000@users.noreply.github.com> Date: Mon, 9 Nov 2020 14:35:16 -0800 Subject: [PATCH 09/21] New events resolver (#82170) * Added Test for event.library * renamed data directry and gzip data file * rename expectedData file * Changes per Charlie request * Changes for the enable_APM-ci branch * Update resolver.ts * Added comment per Charlie request * Update resolver.ts * Added Alert Test for Resolver and fix for the APM enabled Run fail * Added Alert Test for Resolver and fix for the APM enabled Run fail * removed commented out code * Fixing CI fail * Fixing CI fail * Removed Alert Resolver test * aAdding Alert test back * Adding Alert test back * Adding Alert test back * Adding info log for debuging * Adding info log for debuging * Adding info log for debuging * Adding info log for debuging * Adding info log for debuging * Adding info log for debuging * adding one more verification for Data * stripedd Data file Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../resolver_tree/alert_events/data.json.gz | Bin 0 -> 108120 bytes .../apps/endpoint/resolver.ts | 23 ++++++++++++++++++ .../test/security_solution_endpoint/config.ts | 1 - .../page_objects/hosts_page.ts | 2 ++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 x-pack/test/functional/es_archives/endpoint/resolver_tree/alert_events/data.json.gz 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 0000000000000000000000000000000000000000..997a7a5322a11545a2fb1cf33f051d964e35391c GIT binary patch literal 108120 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 { + 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 9ee9e061edf4c..9499c235a5f0d 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 988fadbbdfe33..c76a5a7c22f60 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(); From 7a67cffe37a7d922b8d74024c150a902c1a28539 Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Mon, 9 Nov 2020 17:11:21 -0600 Subject: [PATCH 10/21] Index patterns api - load field list on server (#82629) The server side index patterns api can now load the field list. Previously it would error if a field list refresh was required. The regular and rollup index pattern field list loading methods were merged. Rollup index patterns require additional functionality over regular index patterns when it comes to loading the field list, but this won't be necessary once rollups v2 is released. --- ...atternsservice.getfieldsforindexpattern.md | 2 +- ...dexpatternsservice.getfieldsforwildcard.md | 2 +- ...lugins-data-public.indexpatternsservice.md | 4 +- ...-server.getcapabilitiesforrollupindices.md | 28 ++++ ...dexpatternsfetcher.getfieldsforwildcard.md | 4 +- ...-data-server.indexpatternsservice.start.md | 4 +- .../kibana-plugin-plugins-data-server.md | 2 + ...data-server.mergecapabilitieswithfields.md | 15 ++ ...plugin-plugins-data-server.plugin.start.md | 4 +- .../index_patterns/index_patterns.ts | 19 +-- .../data/common/index_patterns/types.ts | 13 +- .../index_patterns_api_client.test.ts | 17 +-- .../index_patterns_api_client.ts | 37 ++--- src/plugins/data/public/public.api.md | 4 +- src/plugins/data/server/index.ts | 2 + .../server/index_patterns/fetcher/index.ts | 6 +- .../fetcher/index_patterns_fetcher.ts | 50 +++++- .../fetcher/lib/__tests__/fixtures/index.js | 20 +++ .../fetcher}/lib/__tests__/fixtures/jobs.js | 19 ++- .../lib/__tests__/jobs_compatibility.js | 20 ++- .../index_patterns/fetcher/lib/index.ts | 2 + .../fetcher}/lib/jobs_compatibility.ts | 19 ++- .../fetcher/lib/map_capabilities.ts | 37 +++++ .../lib/merge_capabilities_with_fields.ts | 26 +++- .../data/server/index_patterns/index.ts | 8 +- .../index_patterns_api_client.ts | 27 +++- .../index_patterns/index_patterns_service.ts | 19 ++- .../data/server/index_patterns/routes.ts | 6 +- .../server/search/aggs/aggs_service.test.ts | 20 ++- .../data/server/search/aggs/aggs_service.ts | 16 +- src/plugins/data/server/search/aggs/types.ts | 7 +- .../data/server/search/search_service.ts | 9 +- src/plugins/data/server/server.api.md | 61 +++++--- .../server/lib/get_fields.ts | 6 +- .../plugins/data_search/server/plugin.ts | 6 +- .../plugins/index_patterns/server/plugin.ts | 49 ++++-- .../test_suites/data_plugin/index_patterns.ts | 25 ++- .../rollup_index_pattern_creation_config.js | 4 +- .../server/lib/__tests__/fixtures/index.js | 7 - .../rollup/server/lib/map_capabilities.ts | 24 --- .../rollup_search_strategy.ts | 7 +- x-pack/plugins/rollup/server/plugin.ts | 4 +- .../server/routes/api/index_patterns/index.ts | 12 -- .../register_fields_for_wildcard_route.ts | 142 ------------------ x-pack/plugins/rollup/server/routes/index.ts | 2 - x-pack/plugins/rollup/server/types.ts | 4 +- .../apis/management/rollup/constants.js | 2 +- .../rollup/index_patterns_extensions.js | 55 +------ 48 files changed, 484 insertions(+), 394 deletions(-) create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getcapabilitiesforrollupindices.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.mergecapabilitieswithfields.md create mode 100644 src/plugins/data/server/index_patterns/fetcher/lib/__tests__/fixtures/index.js rename {x-pack/plugins/rollup/server => src/plugins/data/server/index_patterns/fetcher}/lib/__tests__/fixtures/jobs.js (65%) rename {x-pack/plugins/rollup/server => src/plugins/data/server/index_patterns/fetcher}/lib/__tests__/jobs_compatibility.js (81%) rename {x-pack/plugins/rollup/server => src/plugins/data/server/index_patterns/fetcher}/lib/jobs_compatibility.ts (79%) create mode 100644 src/plugins/data/server/index_patterns/fetcher/lib/map_capabilities.ts rename {x-pack/plugins/rollup/server => src/plugins/data/server/index_patterns/fetcher}/lib/merge_capabilities_with_fields.ts (70%) delete mode 100644 x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js delete mode 100644 x-pack/plugins/rollup/server/lib/map_capabilities.ts delete mode 100644 x-pack/plugins/rollup/server/routes/api/index_patterns/index.ts delete mode 100644 x-pack/plugins/rollup/server/routes/api/index_patterns/register_fields_for_wildcard_route.ts 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 c06c3c6f68492..f288573cd7abb 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 aec84866b9e58..32bf6fc13b02c 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 34df8656e9175..57bb98de09ebd 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/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 0000000000000..ba2efcc9b75ca --- /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 addd29916d81d..f0989097a727d 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 e7c331bad64e8..6528b1c213cca 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/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 49cf12486cbb8..8957f6d0f06b4 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) | | 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 0000000000000..2880e2d0d8f2c --- /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.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 555a5c2374da7..8a3dbe5a6350c 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/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index aae9b89cdc61f..19c6e9c7b8a7a 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 3387bc3b3c19e..b381cc0963333 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/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 37ee80c2c29e4..8c48ee44fba9c 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 377a3f7f91a50..ca0f35d6612b2 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 bc2bb2663f163..31b05bd4763a2 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -1367,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 { - 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 0000000000000..d675702ae54e9 --- /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 c03b7c33abe0a..39ebd9595eeaf 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 a67f67de859f5..e3c93ac1f8616 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 20e74d2b1a579..b2fd3a1a09a25 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 f5f54cf9a54e8..f21de8907ee24 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 0000000000000..6187174834012 --- /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 51111e9e45d0a..dd69f4b7ff007 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 683d1c445fd72..3305b1bb9a92f 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 2dc6f40c5a6f1..21a3bf6e73e61 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 d665e3715fa72..af2d4d6a73e0f 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 041eb235d01e0..f8af52954fc61 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/search/aggs/aggs_service.test.ts b/src/plugins/data/server/search/aggs/aggs_service.test.ts index cb4239cc339c4..e58420f6c2f07 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 c805c8af6694c..c23f748b1eeb5 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 1b21d948b25d9..2c28c970cbb84 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.ts b/src/plugins/data/server/search/search_service.ts index c5a60c42a41c9..d8aa588719e3e 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -177,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: { @@ -185,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 5b0e0499e29bf..131b3e4c39c6b 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -17,7 +17,8 @@ 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'; @@ -389,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) // @@ -688,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[]; @@ -701,6 +711,8 @@ export class IndexPatternsFetcher { fieldCapsOptions?: { allow_no_indices: boolean; }; + type?: string; + rollupIndex?: string; }): Promise; } @@ -715,7 +727,7 @@ export class IndexPatternsService implements Plugin_3 Promise; + indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract_2, elasticsearchClient: ElasticsearchClient_2) => Promise; }; } @@ -824,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) @@ -927,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>; }; @@ -1195,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:241:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:256:5 - (ae-forgotten-export) The symbol "getTotalLoaded" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:257:5 - (ae-forgotten-export) The symbol "toSnakeCase" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:261:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:271:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:272:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:273:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:277:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:278:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:282:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:285: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/vis_type_timeseries/server/lib/get_fields.ts b/src/plugins/vis_type_timeseries/server/lib/get_fields.ts index b52188129f77f..dc49e280a2bb7 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/test/plugin_functional/plugins/data_search/server/plugin.ts b/test/plugin_functional/plugins/data_search/server/plugin.ts index e016ef56802f3..ca22e82188403 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 a54502b740211..c05b71b834c70 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 2c846dc780311..2e94f61c7ded8 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/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 643cc3efb0136..e021831d2f438 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/__tests__/fixtures/index.js b/x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js deleted file mode 100644 index e97606c1fadfb..0000000000000 --- a/x-pack/plugins/rollup/server/lib/__tests__/fixtures/index.js +++ /dev/null @@ -1,7 +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. - */ - -export { jobs } from './jobs'; 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 233c6d1dd4b4b..0000000000000 --- 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 f439ac555aed9..dcf6629d35397 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 fe193150fc1ca..51920af7c8cbc 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 7bf525ca4aa98..0000000000000 --- 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 df9907fbf731a..0000000000000 --- 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 b25480855b4a2..322003c0ee325 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 b167806cf8d5d..89e13e69c4da2 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/test/api_integration/apis/management/rollup/constants.js b/x-pack/test/api_integration/apis/management/rollup/constants.js index fe899c4c10c88..0313434cf716c 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 357b952e7e66d..0a93e8b8bd1e3 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); From f193d9c96271d0ad7c1b3c721a9f82690e4751b6 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Mon, 9 Nov 2020 17:33:13 -0700 Subject: [PATCH 11/21] [data.search.aggs] Throw an error when trying to create an agg type that doesn't exist. (#81509) --- .../common/search/aggs/agg_config.test.ts | 10 --------- .../common/search/aggs/agg_configs.test.ts | 21 +++++++++++++++++++ .../data/common/search/aggs/agg_configs.ts | 19 +++++++++++++++-- 3 files changed, 38 insertions(+), 12 deletions(-) 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 f6fcc29805dc4..9bb47f5cb3575 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 803ccc70b98a7..d1c8e29a03cc7 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 282e6f3b538a4..368f44f161132 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, }); } From bafe9dfea1ca7c44b0e1283860659b08467bc3ef Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Tue, 10 Nov 2020 10:05:32 +0100 Subject: [PATCH 12/21] [Lens] Distinct icons for XY and pie chart value labels toolbar (#82927) --- x-pack/plugins/lens/public/pie_visualization/toolbar.tsx | 2 +- .../plugins/lens/public/shared_components/toolbar_popover.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx index ab7422c3eeb63..d69164de8a6aa 100644 --- a/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/toolbar.tsx @@ -125,7 +125,7 @@ export function PieToolbar(props: VisualizationToolbarProps 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 20837424dc7b5..cf2268c6eadf2 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', }; From 1de3a02a4620ba02151985a622647e6d8c95c3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yulia=20=C4=8Cech?= <6585477+yuliacech@users.noreply.github.com> Date: Tue, 10 Nov 2020 11:09:37 +0100 Subject: [PATCH 13/21] Fix ilm navigation (#81664) * Fix edit policy page navigation * Fix edit policy page navigation * Add links to PR for explanation * Added more tests and linked to a github issue about navigation issues * Fix decoding function for undefined values * Fix type check issues * Renamed dollar sign to percent sign, added a method for (double) encoded paths and better description in test names * Deleted Index Management from required bundles in ILM * Fixed merge conflicts * Revert "Deleted Index Management from required bundles in ILM" This reverts commit 5a735dfe Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/url/attempt_to_uri_decode.test.ts | 49 +++- .../public/url/attempt_to_uri_decode.ts | 8 +- .../client_integration/app/app.helpers.tsx | 74 +++++ .../client_integration/app/app.test.ts | 252 ++++++++++++++++++ .../edit_policy/constants.ts | 20 ++ .../edit_policy/edit_policy.test.ts | 3 +- .../client_integration/helpers/index.ts | 3 + .../public/application/app.tsx | 40 +-- .../public/application/index.tsx | 8 +- .../edit_policy/edit_policy.container.tsx | 6 +- .../sections/edit_policy/edit_policy.tsx | 2 +- .../public/shared_imports.ts | 2 + .../component_template_details.tsx | 2 +- .../component_template_list.tsx | 6 +- .../component_template_clone.tsx | 2 +- .../component_template_edit.tsx | 2 +- .../data_stream_list/data_stream_list.tsx | 2 +- .../home/template_list/template_list.tsx | 2 +- .../template_clone/template_clone.tsx | 2 +- .../sections/template_edit/template_edit.tsx | 2 +- .../pipelines_clone/pipelines_clone.tsx | 2 +- .../pipelines_edit/pipelines_edit.tsx | 2 +- 22 files changed, 448 insertions(+), 43 deletions(-) create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.helpers.tsx create mode 100644 x-pack/plugins/index_lifecycle_management/__jest__/client_integration/app/app.test.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 15750c7667800..6654611faa18b 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 65444b83f77bb..37e4761106e44 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/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 0000000000000..de7242a6c5ddf --- /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 0000000000000..9052cf2847baa --- /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 3d430cf31621e..00c7d705c1f44 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 4ee67d1ed8a19..c91ee3e2a1c06 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 e8ebc2963d16a..aff9151da61f9 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 856981fe5c4f9..20185b02064bc 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 3d4cc7dbbd1d4..bb1a4810ba2d2 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 ebef80871b83d..4c0cc2c8957e1 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 a127574d5bad0..a5844af0bf6dd 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 6d9aa58d6c86b..2fb16874cf943 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 00ea3ebf794ee..e8424ae46c6d2 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 6c03fcf5d9972..e6b403543f4b0 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 934f86f7d7590..500c84a97d222 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 ba79319b566bf..20b93d9d71d04 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 f3e82223c30e6..3689a875e28b2 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 3e62f7f880f74..e3cb40b3a36e1 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 9465117b6b589..df60907973156 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 7e2e85ab23fb3..2b53fdb6a6375 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); From 0503f873f8de1790e82f7adfc3bdd758c91f97bd Mon Sep 17 00:00:00 2001 From: Denis Maximov Date: Tue, 10 Nov 2020 12:25:28 +0200 Subject: [PATCH 14/21] [Lens] Do not reset formatting when switching between custom ranges and auto histogram (#82694) --- .../definitions/ranges/ranges.test.tsx | 30 +++++++++++++++++++ .../operations/definitions/ranges/ranges.tsx | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) 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 c8a8ffa7b128f..d43a905434c02 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 1050eef45a71c..46d9e4e6c22de 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 Date: Tue, 10 Nov 2020 13:24:07 +0200 Subject: [PATCH 15/21] [Visualizations] Make the icon buttons labels more descriptive (#82585) * [Visualizations] Make the icon buttons labels more descriptive on the Vis Editor * Fix jest test Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../__snapshots__/agg.test.tsx.snap | 4 ++-- .../public/components/agg.tsx | 19 +++++++++++++------ .../public/components/agg_add.tsx | 14 +++++++++----- .../translations/translations/ja-JP.json | 5 ----- .../translations/translations/zh-CN.json | 5 ----- 5 files changed, 24 insertions(+), 23 deletions(-) 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 2a521bc01219c..26173cddb3716 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 46d5af8cec680..e78f2fcc4453c 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/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index d8e136567564e..d9a113b69b473 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -3542,11 +3542,6 @@ "uiActions.triggers.valueClickTitle": "シングルクリック", "usageCollection.stats.notReadyMessage": "まだ統計が準備できていません。しばらくたってから再試行してください。", "visDefaultEditor.advancedToggle.advancedLinkLabel": "高度な設定", - "visDefaultEditor.agg.disableAggButtonTooltip": "集約を無効にする", - "visDefaultEditor.agg.enableAggButtonTooltip": "集約を有効にする", - "visDefaultEditor.agg.errorsAriaLabel": "集約にエラーがあります", - "visDefaultEditor.agg.modifyPriorityButtonTooltip": "ドラッグして優先順位を変更します", - "visDefaultEditor.agg.removeDimensionButtonTooltip": "次元を削除", "visDefaultEditor.agg.toggleEditorButtonAriaLabel": "{schema} エディターを切り替える", "visDefaultEditor.aggAdd.addButtonLabel": "追加", "visDefaultEditor.aggAdd.addGroupButtonLabel": "{groupNameLabel} を追加", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 84cc3510ce487..4a393f8a7a223 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3543,11 +3543,6 @@ "uiActions.triggers.valueClickTitle": "单击", "usageCollection.stats.notReadyMessage": "统计信息尚未准备就绪。请稍后重试。", "visDefaultEditor.advancedToggle.advancedLinkLabel": "高级", - "visDefaultEditor.agg.disableAggButtonTooltip": "禁用聚合", - "visDefaultEditor.agg.enableAggButtonTooltip": "启用聚合", - "visDefaultEditor.agg.errorsAriaLabel": "聚合有错误", - "visDefaultEditor.agg.modifyPriorityButtonTooltip": "通过拖动来修改优先级", - "visDefaultEditor.agg.removeDimensionButtonTooltip": "移除维度", "visDefaultEditor.agg.toggleEditorButtonAriaLabel": "切换 {schema} 编辑器", "visDefaultEditor.aggAdd.addButtonLabel": "添加", "visDefaultEditor.aggAdd.addGroupButtonLabel": "添加{groupNameLabel}", From 471c281fa2572860380d06b26420d694445d1e75 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 10 Nov 2020 13:34:05 +0200 Subject: [PATCH 16/21] [Visualizations] Remove kui usage (#82810) * [Visualize] Remove kui usage * Use EuiPromptButton istead of EuiCallout * Add a link to advanced settings for visualizations docs * Changes requested on code review Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/doc_links/doc_links_service.ts | 1 + .../public/embeddable/_index.scss | 1 - .../embeddable/_visualize_lab_disabled.scss | 13 ----- .../embeddable/disabled_lab_visualization.tsx | 51 ++++++++++++------- 4 files changed, 33 insertions(+), 33 deletions(-) delete mode 100644 src/plugins/visualizations/public/embeddable/_visualize_lab_disabled.scss diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 48187fe465392..0815df4b9b0c7 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/plugins/visualizations/public/embeddable/_index.scss b/src/plugins/visualizations/public/embeddable/_index.scss index c1e3809657bfa..9703e90159f48 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 914480ff8c777..0000000000000 --- 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 3d2af2c591a3c..ea7760f31d54c 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 ( -
-

+ } + iconType="beaker" + body={ + + } + actions={ + + + + } /> -
- {title} }} - /> -
-
- -
- + ); } From a7a83fd4215803d8b835bd4a97a8db4559ef3703 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 10 Nov 2020 13:42:12 +0200 Subject: [PATCH 17/21] [TSVB] Disable using top_hits in pipeline aggregations (#82278) * [TSVB] Disable using top_hits in bucket script aggregations * remove console message * Correct schema for metrics size * Chanhe hardcoded agg with the exported for the METRIC_TYPES var * Exclude top_hit agg from all Sibling Pipeline Aggregations and all Parent Pipeline Aggregations Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- src/plugins/vis_type_timeseries/common/vis_schema.ts | 2 +- .../public/application/components/aggs/calculation.js | 2 ++ .../public/application/components/aggs/cumulative_sum.js | 2 ++ .../public/application/components/aggs/derivative.js | 2 ++ .../public/application/components/aggs/moving_average.js | 2 ++ .../public/application/components/aggs/positive_only.js | 2 ++ .../public/application/components/aggs/serial_diff.js | 2 ++ .../public/application/components/aggs/std_sibling.js | 5 ++++- .../public/application/components/aggs/vars.js | 1 + 9 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/plugins/vis_type_timeseries/common/vis_schema.ts b/src/plugins/vis_type_timeseries/common/vis_schema.ts index 27f09fb574b0f..9ec5ae1424ae3 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 bb3d39797656f..5bf4fb55ee5e5 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 11b3e303e7e00..0b879adbd37ae 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 faf1a59adc4aa..fa1289dc74c72 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 316e0f9af43bd..fb945d2606bc8 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 1999862f7aa0e..6ca5fa8e7447f 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 10b3d551bb89f..e3a0c74273539 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 30e5c57ac90ba..bed5e9caa9f87 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) => { > From 446cffeccf9a19baee96aaf4b146547a3f7f721a Mon Sep 17 00:00:00 2001 From: Bill McConaghy Date: Tue, 10 Nov 2020 07:21:52 -0500 Subject: [PATCH 18/21] renaming built-in alerts to Stack Alerts (#82873) * renaming built-in alerts to Stack Alerts * responding to PR feedback and adding glossary definition for stack alerts * Update docs/glossary.asciidoc Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> --- docs/glossary.asciidoc | 5 +++++ docs/user/alerting/alert-types.asciidoc | 8 +++++--- docs/user/alerting/alerting-getting-started.asciidoc | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/glossary.asciidoc b/docs/glossary.asciidoc index be24402170bbe..ff03a60173961 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 f71e43c5defc7..7de5ff56228cc 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 2b22b49375676..53aef4aaa062e 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] From 451e387f40d211d1eb36589c7d8de95d4e6e94b6 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 10 Nov 2020 07:37:44 -0500 Subject: [PATCH 19/21] Fix SO query for searching across spaces (#83025) --- .../service/lib/search_dsl/query_params.test.ts | 5 ++--- .../service/lib/search_dsl/query_params.ts | 14 ++++++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) 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 c35ec809fcf8d..e78b944183df9 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 2ecba42e408e7..cb58db171681a 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' } }], }, }; From 6003cadce4abfa19dfec1d08b037d45ba11367d7 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 10 Nov 2020 12:43:39 +0000 Subject: [PATCH 20/21] skip flaky suite (#82804) --- .../security_and_spaces/tests/alerting/update.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index 0ad2ca226ed5d..8836bc2e4db2f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -31,7 +31,8 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { .then((response: SupertestResponse) => response.body); } - describe('update', () => { + // FLAKY: https://github.com/elastic/kibana/issues/82804 + describe.skip('update', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); From 0b99841310b804901827040aaf025468941710a3 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Tue, 10 Nov 2020 14:31:04 +0100 Subject: [PATCH 21/21] [Lens] Performance refactoring for indexpattern fast lookup and Operation support matrix computation (#82829) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../datapanel.test.tsx | 254 +++++++------- .../indexpattern_datasource/datapanel.tsx | 5 +- .../bucket_nesting_editor.test.tsx | 22 +- .../dimension_panel/bucket_nesting_editor.tsx | 15 +- .../dimension_panel/dimension_editor.tsx | 45 ++- .../dimension_panel/dimension_panel.test.tsx | 74 ++-- .../dimension_panel/droppable.test.ts | 91 +++-- .../dimension_panel/droppable.ts | 6 +- .../dimension_panel/field_select.tsx | 25 +- .../dimension_panel/operation_support.ts | 38 +- .../indexpattern.test.ts | 205 +++++------ .../indexpattern_suggestions.test.tsx | 326 ++++++++++-------- .../indexpattern_suggestions.ts | 32 +- .../layerpanel.test.tsx | 232 +++++++------ .../indexpattern_datasource/loader.test.ts | 13 +- .../public/indexpattern_datasource/loader.ts | 2 + .../public/indexpattern_datasource/mocks.ts | 117 ++++--- .../operations/definitions/cardinality.tsx | 2 +- .../definitions/date_histogram.test.tsx | 79 ++++- .../operations/definitions/date_histogram.tsx | 19 +- .../operations/definitions/metrics.tsx | 2 +- .../definitions/ranges/ranges.test.tsx | 4 + .../operations/definitions/ranges/ranges.tsx | 6 +- .../operations/definitions/terms/index.tsx | 2 +- .../definitions/terms/terms.test.tsx | 2 +- .../operations/operations.test.ts | 50 +-- .../indexpattern_datasource/pure_helpers.ts | 8 +- .../state_helpers.test.ts | 101 +++--- .../public/indexpattern_datasource/types.ts | 1 + .../public/indexpattern_datasource/utils.ts | 10 +- 30 files changed, 996 insertions(+), 792 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index c48bc3dc52404..d2ec1c81bbeec 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -18,6 +18,131 @@ import { ChangeIndexPattern } from './change_indexpattern'; import { EuiProgress, EuiLoadingSpinner } from '@elastic/eui'; import { documentField } from './document_field'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; +import { getFieldByNameFactory } from './pure_helpers'; + +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'amemory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'unsupported', + displayName: 'unsupported', + type: 'geo', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'client', + displayName: 'client', + type: 'ip', + aggregatable: true, + searchable: true, + }, + documentField, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + histogram: { + agg: 'histogram', + interval: 1000, + }, + max: { + agg: 'max', + }, + min: { + agg: 'min', + }, + sum: { + agg: 'sum', + }, + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, + documentField, +]; + +const fieldsThree = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + documentField, +]; const initialState: IndexPatternPrivateState = { indexPatternRefs: [], @@ -85,139 +210,24 @@ const initialState: IndexPatternPrivateState = { title: 'idx1', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'amemory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'unsupported', - displayName: 'unsupported', - type: 'geo', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'client', - displayName: 'client', - type: 'ip', - aggregatable: true, - searchable: true, - }, - documentField, - ], + fields: fieldsOne, + getFieldByName: getFieldByNameFactory(fieldsOne), }, '2': { id: '2', title: 'idx2', timeFieldName: 'timestamp', hasRestrictions: true, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - histogram: { - agg: 'histogram', - interval: 1000, - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - documentField, - ], + fields: fieldsTwo, + getFieldByName: getFieldByNameFactory(fieldsTwo), }, '3': { id: '3', title: 'idx3', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - documentField, - ], + fields: fieldsThree, + getFieldByName: getFieldByNameFactory(fieldsThree), }, }, isFirstExistenceFetch: false, @@ -330,6 +340,7 @@ describe('IndexPattern Data Panel', () => { title: 'aaa', timeFieldName: 'atime', fields: [], + getFieldByName: getFieldByNameFactory([]), hasRestrictions: false, }, b: { @@ -337,6 +348,7 @@ describe('IndexPattern Data Panel', () => { title: 'bbb', timeFieldName: 'btime', fields: [], + getFieldByName: getFieldByNameFactory([]), hasRestrictions: false, }, }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 28c5605f3bfc5..f2c7d7fc20926 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -5,7 +5,7 @@ */ import './datapanel.scss'; -import { uniq, keyBy, groupBy } from 'lodash'; +import { uniq, groupBy } from 'lodash'; import React, { useState, memo, useCallback, useMemo } from 'react'; import { EuiFlexGroup, @@ -266,9 +266,8 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ const fieldInfoUnavailable = existenceFetchFailed || currentIndexPattern.hasRestrictions; const unfilteredFieldGroups: FieldGroups = useMemo(() => { - const fieldByName = keyBy(allFields, 'name'); const containsData = (field: IndexPatternField) => { - const overallField = fieldByName[field.name]; + const overallField = currentIndexPattern.getFieldByName(field.name); return ( overallField && fieldExists(existingFields, currentIndexPattern.title, overallField.name) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx index 3696f3ad7b102..ee6a86072236c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.test.tsx @@ -10,12 +10,14 @@ import { BucketNestingEditor } from './bucket_nesting_editor'; import { IndexPatternColumn } from '../indexpattern'; import { IndexPatternField } from '../types'; -const fieldMap = { +const fieldMap: Record = { a: { displayName: 'a' } as IndexPatternField, b: { displayName: 'b' } as IndexPatternField, c: { displayName: 'c' } as IndexPatternField, }; +const getFieldByName = (name: string): IndexPatternField | undefined => fieldMap[name]; + describe('BucketNestingEditor', () => { function mockCol(col: Partial = {}): IndexPatternColumn { const result = { @@ -39,7 +41,7 @@ describe('BucketNestingEditor', () => { it('should display the top level grouping when at the root', () => { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const component = mount( { const setColumns = jest.fn(); const component = mount( , column: IndexPatternColumn) { - return hasField(column) ? fieldMap[column.sourceField]?.displayName || column.sourceField : ''; +function getFieldName( + column: IndexPatternColumn, + getFieldByName: (name: string) => IndexPatternField | undefined +) { + return hasField(column) + ? getFieldByName(column.sourceField)?.displayName || column.sourceField + : ''; } export function BucketNestingEditor({ columnId, layer, setColumns, - fieldMap, + getFieldByName, }: { columnId: string; layer: IndexPatternLayer; setColumns: (columns: string[]) => void; - fieldMap: Record; + getFieldByName: (name: string) => IndexPatternField | undefined; }) { const column = layer.columns[columnId]; const columns = Object.entries(layer.columns); @@ -42,7 +47,7 @@ export function BucketNestingEditor({ .map(([value, c]) => ({ value, text: c.label, - fieldName: getFieldName(fieldMap, c), + fieldName: getFieldName(c, getFieldByName), operationType: c.operationType, })); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index a18cb69db74cb..7cbfbc1749382 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -29,7 +29,7 @@ import { deleteColumn, changeColumn, updateColumnParam, mergeLayer } from '../st import { FieldSelect } from './field_select'; import { hasField, fieldIsInvalid } from '../utils'; import { BucketNestingEditor } from './bucket_nesting_editor'; -import { IndexPattern, IndexPatternField } from '../types'; +import { IndexPattern } from '../types'; import { trackUiEvent } from '../../lens_ui_telemetry'; import { FormatSelector } from './format_selector'; @@ -97,23 +97,13 @@ export function DimensionEditor(props: DimensionEditorProps) { const ParamEditor = selectedOperationDefinition?.paramEditor; - const fieldMap: Record = useMemo(() => { - const fields: Record = {}; - currentIndexPattern.fields.forEach((field) => { - fields[field.name] = field; - }); - return fields; - }, [currentIndexPattern]); - const possibleOperations = useMemo(() => { return Object.values(operationDefinitionMap) .sort((op1, op2) => { return op1.displayName.localeCompare(op2.displayName); }) .map((def) => def.type) - .filter( - (type) => fieldByOperation[type]?.length || operationWithoutField.indexOf(type) !== -1 - ); + .filter((type) => fieldByOperation[type]?.size || operationWithoutField.has(type)); }, [fieldByOperation, operationWithoutField]); // Operations are compatible if they match inputs. They are always compatible in @@ -128,7 +118,7 @@ export function DimensionEditor(props: DimensionEditorProps) { (selectedColumn && hasField(selectedColumn) && definition.input === 'field' && - fieldByOperation[operationType]?.indexOf(selectedColumn.sourceField) !== -1) || + fieldByOperation[operationType]?.has(selectedColumn.sourceField)) || (selectedColumn && !hasField(selectedColumn) && definition.input !== 'field'), }; }); @@ -198,9 +188,9 @@ export function DimensionEditor(props: DimensionEditorProps) { trackUiEvent(`indexpattern_dimension_operation_${operationType}`); return; } else if (!selectedColumn || !compatibleWithCurrentField) { - const possibleFields = fieldByOperation[operationType] || []; + const possibleFields = fieldByOperation[operationType] || new Set(); - if (possibleFields.length === 1) { + if (possibleFields.size === 1) { setState( changeColumn({ state, @@ -212,7 +202,7 @@ export function DimensionEditor(props: DimensionEditorProps) { layerId: props.layerId, op: operationType, indexPattern: currentIndexPattern, - field: fieldMap[possibleFields[0]], + field: currentIndexPattern.getFieldByName(possibleFields.values().next().value), previousColumn: selectedColumn, }), }) @@ -236,7 +226,9 @@ export function DimensionEditor(props: DimensionEditorProps) { layerId: props.layerId, op: operationType, indexPattern: currentIndexPattern, - field: hasField(selectedColumn) ? fieldMap[selectedColumn.sourceField] : undefined, + field: hasField(selectedColumn) + ? currentIndexPattern.getFieldByName(selectedColumn.sourceField) + : undefined, previousColumn: selectedColumn, }); @@ -297,7 +289,6 @@ export function DimensionEditor(props: DimensionEditorProps) { fieldIsInvalid={currentFieldIsInvalid} currentIndexPattern={currentIndexPattern} existingFields={state.existingFields} - fieldMap={fieldMap} operationSupportMatrix={operationSupportMatrix} selectedColumnOperationType={selectedColumn && selectedColumn.operationType} selectedColumnSourceField={ @@ -323,25 +314,29 @@ export function DimensionEditor(props: DimensionEditorProps) { ) { // If we just changed the field are not in an error state and the operation didn't change, // we use the operations onFieldChange method to calculate the new column. - column = changeField(selectedColumn, currentIndexPattern, fieldMap[choice.field]); + column = changeField( + selectedColumn, + currentIndexPattern, + currentIndexPattern.getFieldByName(choice.field)! + ); } else { // Otherwise we'll use the buildColumn method to calculate a new column const compatibleOperations = ('field' in choice && operationSupportMatrix.operationByField[choice.field]) || - []; + new Set(); let operation; - if (compatibleOperations.length > 0) { + if (compatibleOperations.size > 0) { operation = incompatibleSelectedOperationType && - compatibleOperations.includes(incompatibleSelectedOperationType) + compatibleOperations.has(incompatibleSelectedOperationType) ? incompatibleSelectedOperationType - : compatibleOperations[0]; + : compatibleOperations.values().next().value; } else if ('field' in choice) { operation = choice.operationType; } column = buildColumn({ columns: props.state.layers[props.layerId].columns, - field: fieldMap[choice.field], + field: currentIndexPattern.getFieldByName(choice.field), indexPattern: currentIndexPattern, layerId: props.layerId, suggestedPriority: props.suggestedPriority, @@ -417,12 +412,12 @@ export function DimensionEditor(props: DimensionEditorProps) { {!incompatibleSelectedOperationType && !hideGrouping && ( setState(mergeLayer({ state, layerId, newLayer: { columnOrder } })) } + getFieldByName={currentIndexPattern.getFieldByName} /> )} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx index 92a4dad14dd25..3ed04b08df58f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_panel.test.tsx @@ -22,6 +22,7 @@ import { IndexPatternColumn } from '../operations'; import { documentField } from '../document_field'; import { OperationMetadata } from '../../types'; import { DateHistogramIndexPatternColumn } from '../operations/definitions/date_histogram'; +import { getFieldByNameFactory } from '../pure_helpers'; jest.mock('../loader'); jest.mock('../state_helpers'); @@ -34,6 +35,42 @@ jest.mock('lodash', () => { }; }); +const fields = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + exists: true, + }, + documentField, +]; + const expectedIndexPatterns = { 1: { id: '1', @@ -41,41 +78,8 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasExistence: true, hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - exists: true, - }, - documentField, - ], + fields, + getFieldByName: getFieldByNameFactory(fields), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts index dd696f8be357f..1d85c1f8f78ca 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.test.ts @@ -15,9 +15,46 @@ import { IndexPatternPrivateState } from '../types'; import { documentField } from '../document_field'; import { OperationMetadata } from '../../types'; import { IndexPatternColumn } from '../operations'; +import { getFieldByNameFactory } from '../pure_helpers'; jest.mock('../state_helpers'); +const fields = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + exists: true, + }, + documentField, +]; + const expectedIndexPatterns = { 1: { id: '1', @@ -25,41 +62,8 @@ const expectedIndexPatterns = { timeFieldName: 'timestamp', hasExistence: true, hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - exists: true, - }, - documentField, - ], + fields, + getFieldByName: getFieldByNameFactory(fields), }, }; @@ -177,6 +181,23 @@ describe('IndexPatternDimensionEditorPanel', () => { type: 'string', }, ], + + getFieldByName: getFieldByNameFactory([ + { + aggregatable: true, + name: 'bar', + displayName: 'bar', + searchable: true, + type: 'number', + }, + { + aggregatable: true, + name: 'mystring', + displayName: 'mystring', + searchable: true, + type: 'string', + }, + ]), }, }, currentIndexPatternId: '1', diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts index 7f509cd0244f0..a6ff550af96e9 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable.ts @@ -137,9 +137,9 @@ export function onDrop(props: DatasourceDimensionDropHandlerProps { currentIndexPattern: IndexPattern; - fieldMap: Record; incompatibleSelectedOperationType: OperationType | null; selectedColumnOperationType?: OperationType; selectedColumnSourceField?: string; @@ -46,7 +45,6 @@ export interface FieldSelectProps extends EuiComboBoxProps<{}> { export function FieldSelect({ currentIndexPattern, - fieldMap, incompatibleSelectedOperationType, selectedColumnOperationType, selectedColumnSourceField, @@ -63,31 +61,32 @@ export function FieldSelect({ function isCompatibleWithCurrentOperation(fieldName: string) { if (incompatibleSelectedOperationType) { - return operationByField[fieldName]!.includes(incompatibleSelectedOperationType); + return operationByField[fieldName]!.has(incompatibleSelectedOperationType); } return ( !selectedColumnOperationType || - operationByField[fieldName]!.includes(selectedColumnOperationType) + operationByField[fieldName]!.has(selectedColumnOperationType) ); } const [specialFields, normalFields] = _.partition( fields, - (field) => fieldMap[field].type === 'document' + (field) => currentIndexPattern.getFieldByName(field)?.type === 'document' ); const containsData = (field: string) => - fieldMap[field].type === 'document' || + currentIndexPattern.getFieldByName(field)?.type === 'document' || fieldExists(existingFields, currentIndexPattern.title, field); function fieldNamesToOptions(items: string[]) { return items + .filter((field) => currentIndexPattern.getFieldByName(field)?.displayName) .map((field) => ({ - label: fieldMap[field].displayName, + label: currentIndexPattern.getFieldByName(field)?.displayName, value: { type: 'field', field, - dataType: fieldMap[field].type, + dataType: currentIndexPattern.getFieldByName(field)?.type, operationType: selectedColumnOperationType && isCompatibleWithCurrentOperation(field) ? selectedColumnOperationType @@ -118,7 +117,10 @@ export function FieldSelect({ })); } - const [metaFields, nonMetaFields] = _.partition(normalFields, (field) => fieldMap[field].meta); + const [metaFields, nonMetaFields] = _.partition( + normalFields, + (field) => currentIndexPattern.getFieldByName(field)?.meta + ); const [availableFields, emptyFields] = _.partition(nonMetaFields, containsData); const constructFieldsOptions = (fieldsArr: string[], label: string) => @@ -158,7 +160,6 @@ export function FieldSelect({ incompatibleSelectedOperationType, selectedColumnOperationType, currentIndexPattern, - fieldMap, operationByField, existingFields, ]); @@ -180,7 +181,7 @@ export function FieldSelect({ { label: fieldIsInvalid ? selectedColumnSourceField - : fieldMap[selectedColumnSourceField]?.displayName, + : currentIndexPattern.getFieldByName(selectedColumnSourceField)?.displayName, value: { type: 'field', field: selectedColumnSourceField }, }, ] diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts index 2ea28da201556..31fb5277d53ec 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/operation_support.ts @@ -11,9 +11,9 @@ import { getAvailableOperationsByMetadata } from '../operations'; import { IndexPatternPrivateState } from '../types'; export interface OperationSupportMatrix { - operationByField: Partial>; - operationWithoutField: OperationType[]; - fieldByOperation: Partial>; + operationByField: Partial>>; + operationWithoutField: Set; + fieldByOperation: Partial>>; } type Props = Pick< @@ -31,30 +31,30 @@ export const getOperationSupportMatrix = (props: Props): OperationSupportMatrix currentIndexPattern ).filter((operation) => props.filterOperations(operation.operationMetaData)); - const supportedOperationsByField: Partial> = {}; - const supportedOperationsWithoutField: OperationType[] = []; - const supportedFieldsByOperation: Partial> = {}; + const supportedOperationsByField: Partial>> = {}; + const supportedOperationsWithoutField: Set = new Set(); + const supportedFieldsByOperation: Partial>> = {}; filteredOperationsByMetadata.forEach(({ operations }) => { operations.forEach((operation) => { if (operation.type === 'field') { - supportedOperationsByField[operation.field] = [ - ...(supportedOperationsByField[operation.field] ?? []), - operation.operationType, - ]; - - supportedFieldsByOperation[operation.operationType] = [ - ...(supportedFieldsByOperation[operation.operationType] ?? []), - operation.field, - ]; + if (!supportedOperationsByField[operation.field]) { + supportedOperationsByField[operation.field] = new Set(); + } + supportedOperationsByField[operation.field]?.add(operation.operationType); + + if (!supportedFieldsByOperation[operation.operationType]) { + supportedFieldsByOperation[operation.operationType] = new Set(); + } + supportedFieldsByOperation[operation.operationType]?.add(operation.field); } else if (operation.type === 'none') { - supportedOperationsWithoutField.push(operation.operationType); + supportedOperationsWithoutField.add(operation.operationType); } }); }); return { - operationByField: _.mapValues(supportedOperationsByField, _.uniq), - operationWithoutField: _.uniq(supportedOperationsWithoutField), - fieldByOperation: _.mapValues(supportedFieldsByOperation, _.uniq), + operationByField: supportedOperationsByField, + operationWithoutField: supportedOperationsWithoutField, + fieldByOperation: supportedFieldsByOperation, }; }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index a3f48b162475a..51d95245adb25 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -12,121 +12,128 @@ import { IndexPatternPersistedState, IndexPatternPrivateState } from './types'; import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; import { Ast } from '@kbn/interpreter/common'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./loader'); jest.mock('../id_generator'); -const expectedIndexPatterns = { - 1: { - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'start_date', + displayName: 'start_date', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'dest', + displayName: 'dest', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', }, - { - name: 'start_date', - displayName: 'start_date', - type: 'date', - aggregatable: true, - searchable: true, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + // Ignored in the UI + histogram: { + agg: 'histogram', + interval: 1000, }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, + avg: { + agg: 'avg', }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, + max: { + agg: 'max', }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, + min: { + agg: 'min', }, - { - name: 'dest', - displayName: 'dest', - type: 'string', - aggregatable: true, - searchable: true, + sum: { + agg: 'sum', }, - ], + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, +]; + +const expectedIndexPatterns = { + 1: { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: fieldsOne, + getFieldByName: getFieldByNameFactory(fieldsOne), }, 2: { id: '2', title: 'my-fake-restricted-pattern', timeFieldName: 'timestamp', hasRestrictions: true, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - // Ignored in the UI - histogram: { - agg: 'histogram', - interval: 1000, - }, - avg: { - agg: 'avg', - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - ], + fields: fieldsTwo, + getFieldByName: getFieldByNameFactory(fieldsTwo), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx index c8cb9fcb33ba9..523a1be34ba3d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.test.tsx @@ -12,121 +12,128 @@ import { getDatasourceSuggestionsFromCurrentState, getDatasourceSuggestionsForVisualizeField, } from './indexpattern_suggestions'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./loader'); jest.mock('../id_generator'); -const expectedIndexPatterns = { - 1: { - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'start_date', + displayName: 'start_date', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'dest', + displayName: 'dest', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', }, - { - name: 'start_date', - displayName: 'start_date', - type: 'date', - aggregatable: true, - searchable: true, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + // Ignored in the UI + histogram: { + agg: 'histogram', + interval: 1000, }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, + avg: { + agg: 'avg', }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, + max: { + agg: 'max', }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, + min: { + agg: 'min', }, - { - name: 'dest', - displayName: 'dest', - type: 'string', - aggregatable: true, - searchable: true, + sum: { + agg: 'sum', + }, + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', }, - ], + }, + }, +]; + +const expectedIndexPatterns = { + 1: { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: fieldsOne, + getFieldByName: getFieldByNameFactory(fieldsOne), }, 2: { id: '2', title: 'my-fake-restricted-pattern', hasRestrictions: true, timeFieldName: 'timestamp', - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - // Ignored in the UI - histogram: { - agg: 'histogram', - interval: 1000, - }, - avg: { - agg: 'avg', - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - ], + fields: fieldsTwo, + getFieldByName: getFieldByNameFactory(fieldsTwo), }, }; @@ -335,6 +342,15 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + getFieldByName: getFieldByNameFactory([ + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]), }, }, layers: { @@ -546,6 +562,16 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + + getFieldByName: getFieldByNameFactory([ + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]), }, }, layers: { @@ -1531,6 +1557,43 @@ describe('IndexPattern Data Source suggestions', () => { it('returns simplified versions of table with more than 2 columns', () => { const initialState = testInitialState(); + const fields = [ + { + name: 'field1', + displayName: 'field1', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'field2', + displayName: 'field2', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'field3', + displayName: 'field3Label', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'field4', + displayName: 'field4', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'field5', + displayName: 'field5', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]; const state: IndexPatternPrivateState = { indexPatternRefs: [], existingFields: {}, @@ -1540,43 +1603,8 @@ describe('IndexPattern Data Source suggestions', () => { id: '1', title: 'my-fake-index-pattern', hasRestrictions: false, - fields: [ - { - name: 'field1', - displayName: 'field1', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'field2', - displayName: 'field2', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'field3', - displayName: 'field3Label', - type: 'string', - aggregatable: true, - searchable: true, - }, - { - name: 'field4', - displayName: 'field4', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'field5', - displayName: 'field5', - type: 'number', - aggregatable: true, - searchable: true, - }, - ], + fields, + getFieldByName: getFieldByNameFactory(fields), }, }, isFirstExistenceFetch: false, @@ -1700,6 +1728,23 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + + getFieldByName: getFieldByNameFactory([ + { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'field2', + displayName: 'field2', + type: 'date', + aggregatable: true, + searchable: true, + }, + ]), }, }, isFirstExistenceFetch: false, @@ -1756,6 +1801,15 @@ describe('IndexPattern Data Source suggestions', () => { searchable: true, }, ], + getFieldByName: getFieldByNameFactory([ + { + name: 'field1', + displayName: 'field1', + type: 'number', + aggregatable: true, + searchable: true, + }, + ]), }, }, isFirstExistenceFetch: false, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts index 098569d1f460a..c12d7d4be226b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts @@ -128,7 +128,7 @@ export function getDatasourceSuggestionsForVisualizeField( const layerIds = layers.filter((id) => state.layers[id].indexPatternId === indexPatternId); // Identify the field by the indexPatternId and the fieldName const indexPattern = state.indexPatterns[indexPatternId]; - const field = indexPattern.fields.find((fld) => fld.name === fieldName); + const field = indexPattern.getFieldByName(fieldName); if (layerIds.length !== 0 || !field) return []; const newId = generateId(); @@ -371,7 +371,7 @@ function createNewLayerWithMetricAggregation( indexPattern: IndexPattern, field: IndexPatternField ): IndexPatternLayer { - const dateField = indexPattern.fields.find((f) => f.name === indexPattern.timeFieldName)!; + const dateField = indexPattern.getFieldByName(indexPattern.timeFieldName!); const column = getMetricColumn(indexPattern, layerId, field); @@ -451,9 +451,8 @@ export function getDatasourceSuggestionsFromCurrentState( (columnId) => layer.columns[columnId].isBucketed && layer.columns[columnId].dataType === 'date' ); - const timeField = indexPattern.fields.find( - ({ name }) => name === indexPattern.timeFieldName - ); + const timeField = + indexPattern.timeFieldName && indexPattern.getFieldByName(indexPattern.timeFieldName); const hasNumericDimension = buckets.length === 1 && @@ -507,17 +506,17 @@ function createChangedNestingSuggestion(state: IndexPatternPrivateState, layerId const layer = state.layers[layerId]; const [firstBucket, secondBucket, ...rest] = layer.columnOrder; const updatedLayer = { ...layer, columnOrder: [secondBucket, firstBucket, ...rest] }; - const currentFields = state.indexPatterns[state.currentIndexPatternId].fields; + const indexPattern = state.indexPatterns[state.currentIndexPatternId]; + const firstBucketColumn = layer.columns[firstBucket]; const firstBucketLabel = - currentFields.find((field) => { - const column = layer.columns[firstBucket]; - return hasField(column) && column.sourceField === field.name; - })?.displayName || ''; + (hasField(firstBucketColumn) && + indexPattern.getFieldByName(firstBucketColumn.sourceField)?.displayName) || + ''; + const secondBucketColumn = layer.columns[secondBucket]; const secondBucketLabel = - currentFields.find((field) => { - const column = layer.columns[secondBucket]; - return hasField(column) && column.sourceField === field.name; - })?.displayName || ''; + (hasField(secondBucketColumn) && + indexPattern.getFieldByName(secondBucketColumn.sourceField)?.displayName) || + ''; return buildSuggestion({ state, @@ -604,7 +603,10 @@ function createAlternativeMetricSuggestions( if (!hasField(column)) { return; } - const field = indexPattern.fields.find(({ name }) => column.sourceField === name)!; + const field = indexPattern.getFieldByName(column.sourceField); + if (!field) { + return; + } const alternativeMetricOperations = getOperationTypesForField(field) .map((op) => buildColumn({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx index 92e35b257f24a..40eb52fe67c6d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/layerpanel.test.tsx @@ -11,6 +11,7 @@ import { shallowWithIntl as shallow } from 'test_utils/enzyme_helpers'; import { ShallowWrapper } from 'enzyme'; import { EuiSelectable } from '@elastic/eui'; import { ChangeIndexPattern } from './change_indexpattern'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./state_helpers'); @@ -19,6 +20,120 @@ interface IndexPatternPickerOption { checked?: 'on' | 'off'; } +const fieldsOne = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'unsupported', + displayName: 'unsupported', + type: 'geo', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + +const fieldsTwo = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, + }, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + histogram: { + agg: 'histogram', + interval: 1000, + }, + max: { + agg: 'max', + }, + min: { + agg: 'min', + }, + sum: { + agg: 'sum', + }, + }, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + terms: { + agg: 'terms', + }, + }, + }, +]; + +const fieldsThree = [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + const initialState: IndexPatternPrivateState = { indexPatternRefs: [ { id: '1', title: 'my-fake-index-pattern' }, @@ -63,129 +178,24 @@ const initialState: IndexPatternPrivateState = { title: 'my-fake-index-pattern', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'unsupported', - displayName: 'unsupported', - type: 'geo', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - ], + fields: fieldsOne, + getFieldByName: getFieldByNameFactory(fieldsOne), }, '2': { id: '2', title: 'my-fake-restricted-pattern', hasRestrictions: true, timeFieldName: 'timestamp', - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', - }, - }, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - histogram: { - agg: 'histogram', - interval: 1000, - }, - max: { - agg: 'max', - }, - min: { - agg: 'min', - }, - sum: { - agg: 'sum', - }, - }, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - aggregationRestrictions: { - terms: { - agg: 'terms', - }, - }, - }, - ], + fields: fieldsTwo, + getFieldByName: getFieldByNameFactory(fieldsTwo), }, '3': { id: '3', title: 'my-compatible-pattern', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'memory', - displayName: 'memory', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - ], + fields: fieldsThree, + getFieldByName: getFieldByNameFactory(fieldsThree), }, }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts index 4222c02388433..adb86253ab28c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts @@ -285,15 +285,10 @@ describe('loader', () => { } as unknown) as Pick, }); - expect( - cache.foo.fields.find((f: IndexPatternField) => f.name === 'bytes')!.aggregationRestrictions - ).toEqual({ + expect(cache.foo.getFieldByName('bytes')!.aggregationRestrictions).toEqual({ sum: { agg: 'sum' }, }); - expect( - cache.foo.fields.find((f: IndexPatternField) => f.name === 'timestamp')! - .aggregationRestrictions - ).toEqual({ + expect(cache.foo.getFieldByName('timestamp')!.aggregationRestrictions).toEqual({ date_histogram: { agg: 'date_histogram', fixed_interval: 'm' }, }); }); @@ -342,9 +337,7 @@ describe('loader', () => { } as unknown) as Pick, }); - expect(cache.foo.fields.find((f: IndexPatternField) => f.name === 'timestamp')!.meta).toEqual( - true - ); + expect(cache.foo.getFieldByName('timestamp')!.meta).toEqual(true); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts index 70079cce6cc46..fac5d7350e45e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts @@ -26,6 +26,7 @@ import { import { VisualizeFieldContext } from '../../../../../src/plugins/ui_actions/public'; import { documentField } from './document_field'; import { readFromStorage, writeToStorage } from '../settings_storage'; +import { getFieldByNameFactory } from './pure_helpers'; type SetState = StateSetter; type SavedObjectsClient = Pick; @@ -112,6 +113,7 @@ export async function loadIndexPatterns({ ]) ), fields: newFields, + getFieldByName: getFieldByNameFactory(newFields), hasRestrictions: !!typeMeta?.aggs, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts index 744a9f6743d09..2c6f42668d863 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts @@ -5,14 +5,11 @@ */ import { DragContextState } from '../drag_drop'; +import { getFieldByNameFactory } from './pure_helpers'; import { IndexPattern } from './types'; -export const createMockedIndexPattern = (): IndexPattern => ({ - id: '1', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasRestrictions: false, - fields: [ +export const createMockedIndexPattern = (): IndexPattern => { + const fields = [ { name: 'timestamp', displayName: 'timestampLabel', @@ -74,16 +71,19 @@ export const createMockedIndexPattern = (): IndexPattern => ({ lang: 'painless', script: '1234', }, - ], -}); + ]; + return { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields, + getFieldByName: getFieldByNameFactory(fields), + }; +}; -export const createMockedRestrictedIndexPattern = () => ({ - id: '2', - title: 'my-fake-restricted-pattern', - timeFieldName: 'timestamp', - hasRestrictions: true, - fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, - fields: [ +export const createMockedRestrictedIndexPattern = () => { + const fields = [ { name: 'timestamp', displayName: 'timestampLabel', @@ -109,54 +109,63 @@ export const createMockedRestrictedIndexPattern = () => ({ lang: 'painless', script: '1234', }, - ], - typeMeta: { - params: { - rollup_index: 'my-fake-index-pattern', - }, - aggs: { - terms: { - source: { - agg: 'terms', - }, + ]; + return { + id: '2', + title: 'my-fake-restricted-pattern', + timeFieldName: 'timestamp', + hasRestrictions: true, + fieldFormatMap: { bytes: { id: 'bytes', params: { pattern: '0.0' } } }, + fields, + getFieldByName: getFieldByNameFactory(fields), + typeMeta: { + params: { + rollup_index: 'my-fake-index-pattern', }, - date_histogram: { - timestamp: { - agg: 'date_histogram', - fixed_interval: '1d', - delay: '7d', - time_zone: 'UTC', + aggs: { + terms: { + source: { + agg: 'terms', + }, }, - }, - histogram: { - bytes: { - agg: 'histogram', - interval: 1000, + date_histogram: { + timestamp: { + agg: 'date_histogram', + fixed_interval: '1d', + delay: '7d', + time_zone: 'UTC', + }, }, - }, - avg: { - bytes: { - agg: 'avg', + histogram: { + bytes: { + agg: 'histogram', + interval: 1000, + }, }, - }, - max: { - bytes: { - agg: 'max', + avg: { + bytes: { + agg: 'avg', + }, }, - }, - min: { - bytes: { - agg: 'min', + max: { + bytes: { + agg: 'max', + }, }, - }, - sum: { - bytes: { - agg: 'sum', + min: { + bytes: { + agg: 'min', + }, + }, + sum: { + bytes: { + agg: 'sum', + }, }, }, }, - }, -}); + }; +}; export function createMockedDragDropContext(): jest.Mocked { return { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx index 65119d3978ee6..1cfa63511a45c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx @@ -43,7 +43,7 @@ export const cardinalityOperation: OperationDefinition { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index ac6bf63c37110..fc33b64ca508f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -18,6 +18,7 @@ import { } from '../../../../../../../src/plugins/data/public/mocks'; import { createMockedIndexPattern } from '../../mocks'; import { IndexPatternPrivateState } from '../../types'; +import { getFieldByNameFactory } from '../../pure_helpers'; const dataStart = dataPluginMock.createStartContract(); dataStart.search.aggs.calculateAutoTimeExpression = getCalculateAutoTimeExpression( @@ -66,6 +67,17 @@ describe('date_histogram', () => { searchable: true, }, ], + + getFieldByName: getFieldByNameFactory([ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + esTypes: ['date'], + aggregatable: true, + searchable: true, + }, + ]), }, 2: { id: '2', @@ -81,6 +93,16 @@ describe('date_histogram', () => { searchable: true, }, ], + getFieldByName: getFieldByNameFactory([ + { + name: 'other_timestamp', + displayName: 'other_timestamp', + type: 'date', + esTypes: ['date'], + aggregatable: true, + searchable: true, + }, + ]), }, }, layers: { @@ -267,6 +289,22 @@ describe('date_histogram', () => { }, }, ], + getFieldByName: getFieldByNameFactory([ + { + name: 'timestamp', + displayName: 'timestamp', + aggregatable: true, + searchable: true, + type: 'date', + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'UTC', + calendar_interval: '42w', + }, + }, + }, + ]), } ); expect(esAggsConfig).toEqual( @@ -294,7 +332,7 @@ describe('date_histogram', () => { }, }; const indexPattern = createMockedIndexPattern(); - const newDateField = indexPattern.fields.find((i) => i.name === 'start_date')!; + const newDateField = indexPattern.getFieldByName('start_date')!; const column = dateHistogramOperation.onFieldChange(oldColumn, indexPattern, newDateField); expect(column).toHaveProperty('sourceField', 'start_date'); @@ -314,7 +352,7 @@ describe('date_histogram', () => { }, }; const indexPattern = createMockedIndexPattern(); - const newDateField = indexPattern.fields.find((i) => i.name === 'start_date')!; + const newDateField = indexPattern.getFieldByName('start_date')!; const column = dateHistogramOperation.onFieldChange(oldColumn, indexPattern, newDateField); expect(column).toHaveProperty('sourceField', 'start_date'); @@ -356,6 +394,22 @@ describe('date_histogram', () => { }, }, ], + getFieldByName: getFieldByNameFactory([ + { + name: 'dateField', + displayName: 'dateField', + type: 'date', + aggregatable: true, + searchable: true, + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'CET', + calendar_interval: 'w', + }, + }, + }, + ]), } ); expect(transferedColumn).toEqual( @@ -393,6 +447,15 @@ describe('date_histogram', () => { searchable: true, }, ], + getFieldByName: getFieldByNameFactory([ + { + name: 'dateField', + displayName: 'dateField', + type: 'date', + aggregatable: true, + searchable: true, + }, + ]), } ); expect(transferedColumn).toEqual( @@ -609,6 +672,18 @@ describe('date_histogram', () => { }, }, ], + getFieldByName: getFieldByNameFactory([ + { + ...state.indexPatterns[1].fields[0], + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'UTC', + calendar_interval: '1h', + }, + }, + }, + ]), }, }, }} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx index 185f44405bb4b..19043c03e5a61 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.tsx @@ -81,7 +81,7 @@ export const dateHistogramOperation: OperationDefinition< }; }, isTransferable: (column, newIndexPattern) => { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && @@ -91,12 +91,9 @@ export const dateHistogramOperation: OperationDefinition< ); }, transfer: (column, newIndexPattern) => { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); - if ( - newField && - newField.aggregationRestrictions && - newField.aggregationRestrictions.date_histogram - ) { + const newField = newIndexPattern.getFieldByName(column.sourceField); + + if (newField?.aggregationRestrictions?.date_histogram) { const restrictions = newField.aggregationRestrictions.date_histogram; return { @@ -123,7 +120,7 @@ export const dateHistogramOperation: OperationDefinition< }; }, toEsAggsConfig: (column, columnId, indexPattern) => { - const usedField = indexPattern.fields.find((field) => field.name === column.sourceField); + const usedField = indexPattern.getFieldByName(column.sourceField); return { id: columnId, enabled: true, @@ -132,7 +129,7 @@ export const dateHistogramOperation: OperationDefinition< params: { field: column.sourceField, time_zone: column.params.timeZone, - useNormalizedEsInterval: !usedField || !usedField.aggregationRestrictions?.date_histogram, + useNormalizedEsInterval: !usedField?.aggregationRestrictions?.date_histogram, interval: column.params.interval, drop_partials: false, min_doc_count: 0, @@ -143,8 +140,8 @@ export const dateHistogramOperation: OperationDefinition< paramEditor: ({ state, setState, currentColumn, layerId, dateRange, data }) => { const field = currentColumn && - state.indexPatterns[state.layers[layerId].indexPatternId].fields.find( - (currentField) => currentField.name === currentColumn.sourceField + state.indexPatterns[state.layers[layerId].indexPatternId].getFieldByName( + currentColumn.sourceField ); const intervalIsRestricted = field!.aggregationRestrictions && field!.aggregationRestrictions.date_histogram; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx index 1d3ecc165ce74..fef575c61475c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx @@ -43,7 +43,7 @@ function buildMetricOperation>({ } }, isTransferable: (column, newIndexPattern) => { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && 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 d43a905434c02..ce015284e544b 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 @@ -30,6 +30,7 @@ import { } from './constants'; import { RangePopover } from './advanced_editor'; import { DragDropBuckets } from '../shared_components'; +import { getFieldByNameFactory } from '../../../pure_helpers'; const dataPluginMockValue = dataPluginMock.createStartContract(); // need to overwrite the formatter field first @@ -96,6 +97,9 @@ describe('ranges', () => { title: 'my_index_pattern', hasRestrictions: false, fields: [{ name: sourceField, type: 'number', displayName: sourceField }], + getFieldByName: getFieldByNameFactory([ + { name: sourceField, type: 'number', displayName: sourceField }, + ]), }, }, existingFields: {}, 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 46d9e4e6c22de..c6cc6ae13f178 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 @@ -140,7 +140,7 @@ export const rangeOperation: OperationDefinition { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && @@ -168,9 +168,7 @@ export const rangeOperation: OperationDefinition { const indexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; - const currentField = indexPattern.fields.find( - (field) => field.name === currentColumn.sourceField - ); + const currentField = indexPattern.getFieldByName(currentColumn.sourceField); const numberFormat = currentColumn.params.format; const numberFormatterPattern = numberFormat && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index dcb4646816e13..421068a5ad47f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -61,7 +61,7 @@ export const termsOperation: OperationDefinition { - const newField = newIndexPattern.fields.find((field) => field.name === column.sourceField); + const newField = newIndexPattern.getFieldByName(column.sourceField); return Boolean( newField && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx index 1341ca0587c75..bb1b13ba74cc5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx @@ -103,7 +103,7 @@ describe('terms', () => { }, }; const indexPattern = createMockedIndexPattern(); - const newNumberField = indexPattern.fields.find((i) => i.name === 'bytes')!; + const newNumberField = indexPattern.getFieldByName('bytes')!; const column = termsOperation.onFieldChange(oldColumn, indexPattern, newNumberField); expect(column).toHaveProperty('dataType', 'number'); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts index 6808bc724f26b..9767d4bdca688 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/operations.test.ts @@ -8,38 +8,42 @@ import { getOperationTypesForField, getAvailableOperationsByMetadata, buildColum import { AvgIndexPatternColumn } from './definitions/metrics'; import { IndexPatternPrivateState } from '../types'; import { documentField } from '../document_field'; +import { getFieldByNameFactory } from '../pure_helpers'; jest.mock('../loader'); +const fields = [ + { + name: 'timestamp', + displayName: 'timestamp', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, +]; + const expectedIndexPatterns = { 1: { id: '1', title: 'my-fake-index-pattern', timeFieldName: 'timestamp', hasRestrictions: false, - fields: [ - { - name: 'timestamp', - displayName: 'timestamp', - type: 'date', - aggregatable: true, - searchable: true, - }, - { - name: 'bytes', - displayName: 'bytes', - type: 'number', - aggregatable: true, - searchable: true, - }, - { - name: 'source', - displayName: 'source', - type: 'string', - aggregatable: true, - searchable: true, - }, - ], + fields, + getFieldByName: getFieldByNameFactory(fields), }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts index 9e81b5e0c5bf9..c5da3d0c5dcde 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/pure_helpers.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IndexPatternPrivateState } from './types'; +import { keyBy } from 'lodash'; +import { IndexPatternField, IndexPatternPrivateState } from './types'; export function fieldExists( existingFields: IndexPatternPrivateState['existingFields'], @@ -13,3 +14,8 @@ export function fieldExists( ) { return existingFields[indexPatternTitle] && existingFields[indexPatternTitle][fieldName]; } + +export function getFieldByNameFactory(newFields: IndexPatternField[]) { + const fieldsLookup = keyBy(newFields, 'name'); + return (name: string) => fieldsLookup[name]; +} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts index da90a2ce5fcec..45008b2d9439a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.test.ts @@ -16,6 +16,7 @@ import { TermsIndexPatternColumn } from './operations/definitions/terms'; import { DateHistogramIndexPatternColumn } from './operations/definitions/date_histogram'; import { AvgIndexPatternColumn } from './operations/definitions/metrics'; import { IndexPattern, IndexPatternPrivateState, IndexPatternLayer } from './types'; +import { getFieldByNameFactory } from './pure_helpers'; jest.mock('./operations'); @@ -585,59 +586,61 @@ describe('state_helpers', () => { }); describe('updateLayerIndexPattern', () => { - const indexPattern: IndexPattern = { - id: 'test', - title: '', - hasRestrictions: true, - fields: [ - { - name: 'fieldA', - displayName: 'fieldA', - aggregatable: true, - searchable: true, - type: 'string', - }, - { - name: 'fieldB', - displayName: 'fieldB', - aggregatable: true, - searchable: true, - type: 'number', - aggregationRestrictions: { - avg: { - agg: 'avg', - }, + const fields = [ + { + name: 'fieldA', + displayName: 'fieldA', + aggregatable: true, + searchable: true, + type: 'string', + }, + { + name: 'fieldB', + displayName: 'fieldB', + aggregatable: true, + searchable: true, + type: 'number', + aggregationRestrictions: { + avg: { + agg: 'avg', }, }, - { - name: 'fieldC', - displayName: 'fieldC', - aggregatable: false, - searchable: true, - type: 'date', - }, - { - name: 'fieldD', - displayName: 'fieldD', - aggregatable: true, - searchable: true, - type: 'date', - aggregationRestrictions: { - date_histogram: { - agg: 'date_histogram', - time_zone: 'CET', - calendar_interval: 'w', - }, + }, + { + name: 'fieldC', + displayName: 'fieldC', + aggregatable: false, + searchable: true, + type: 'date', + }, + { + name: 'fieldD', + displayName: 'fieldD', + aggregatable: true, + searchable: true, + type: 'date', + aggregationRestrictions: { + date_histogram: { + agg: 'date_histogram', + time_zone: 'CET', + calendar_interval: 'w', }, }, - { - name: 'fieldE', - displayName: 'fieldE', - aggregatable: true, - searchable: true, - type: 'date', - }, - ], + }, + { + name: 'fieldE', + displayName: 'fieldE', + aggregatable: true, + searchable: true, + type: 'date', + }, + ]; + const indexPattern: IndexPattern = { + id: 'test', + title: '', + hasRestrictions: true, + getFieldByName: getFieldByNameFactory(fields), + fields, }; it('should switch index pattern id in layer', () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts index a3c0e8aed7421..1e6fc5a5806b5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts @@ -11,6 +11,7 @@ import { IndexPatternAggRestrictions } from '../../../../../src/plugins/data/pub export interface IndexPattern { id: string; fields: IndexPatternField[]; + getFieldByName(name: string): IndexPatternField | undefined; title: string; timeFieldName?: string; fieldFormatMap?: Record< diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts b/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts index d3d65617f2253..d0ea81d135156 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/utils.ts @@ -87,15 +87,15 @@ export function fieldIsInvalid( indexPattern: IndexPattern ) { const operationDefinition = operationType && operationDefinitionMap[operationType]; + const field = sourceField ? indexPattern.getFieldByName(sourceField) : undefined; return Boolean( sourceField && operationDefinition && - !indexPattern.fields.some( - (field) => - field.name === sourceField && - operationDefinition?.input === 'field' && - operationDefinition.getPossibleOperationForField(field) !== undefined + !( + field && + operationDefinition?.input === 'field' && + operationDefinition.getPossibleOperationForField(field) !== undefined ) ); }