diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index ba928931f303a..a824aa7ea29e2 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -73,6 +73,7 @@ enabled: - test/functional/apps/discover/config.ts - test/functional/apps/getting_started/config.ts - test/functional/apps/home/config.ts + - test/functional/apps/kibana_overview/config.ts - test/functional/apps/management/config.ts - test/functional/apps/saved_objects_management/config.ts - test/functional/apps/status_page/config.ts diff --git a/.buildkite/pipelines/performance/daily.yml b/.buildkite/pipelines/performance/daily.yml index 4e243a23f1e02..fdc4ae17d69a2 100644 --- a/.buildkite/pipelines/performance/daily.yml +++ b/.buildkite/pipelines/performance/daily.yml @@ -25,6 +25,12 @@ steps: # queue: n2-2 # depends_on: tests + - label: ':chart_with_upwards_trend: Report performance metrics to ci-stats' + command: .buildkite/scripts/steps/functional/report_performance_metrics.sh + agents: + queue: n2-2 + depends_on: tests + - wait: ~ continue_on_failure: true diff --git a/.buildkite/scripts/build_kibana.sh b/.buildkite/scripts/build_kibana.sh index d450e988799bc..eb7adae732d79 100755 --- a/.buildkite/scripts/build_kibana.sh +++ b/.buildkite/scripts/build_kibana.sh @@ -2,6 +2,8 @@ set -euo pipefail +source .buildkite/scripts/common/util.sh + export KBN_NP_PLUGINS_BUILT=true echo "--- Build Kibana Distribution" diff --git a/.buildkite/scripts/steps/functional/report_performance_metrics.sh b/.buildkite/scripts/steps/functional/report_performance_metrics.sh new file mode 100644 index 0000000000000..66a5ac27a8dff --- /dev/null +++ b/.buildkite/scripts/steps/functional/report_performance_metrics.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/common/util.sh + +# TODO: Add new user and change lines accordingly +USER_FROM_VAULT="$(retry 5 5 vault read -field=username secret/kibana-issues/dev/ci_stats_performance_metrics)" +PASS_FROM_VAULT="$(retry 5 5 vault read -field=password secret/kibana-issues/dev/ci_stats_performance_metrics)" +APM_SERVER_URL="https://kibana-ops-e2e-perf.es.us-central1.gcp.cloud.es.io:9243/internal/apm" +BUILD_ID=${BUILDKITE_BUILD_ID} + +.buildkite/scripts/bootstrap.sh + +echo "--- Extract APM metrics & report them to ci-stats" + +node scripts/report_performance_metrics \ + --buildId "${BUILD_ID}" \ + --apm-url "${APM_SERVER_URL}" \ + --apm-username "${USER_FROM_VAULT}" \ + --apm-password "${PASS_FROM_VAULT}" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2682f1fc9c7c9..6813dcaa33c09 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -202,6 +202,7 @@ /x-pack/test/functional/apps/transform/ @elastic/ml-ui /x-pack/test/functional/services/transform/ @elastic/ml-ui /x-pack/test/functional_basic/apps/transform/ @elastic/ml-ui +/x-pack/packages/ml/ @elastic/ml-ui /packages/kbn-aiops-utils @elastic/ml-ui /examples/response_stream/ @elastic/ml-ui diff --git a/.i18nrc.json b/.i18nrc.json index 0ab8e6b490a12..8c98fc415c910 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -7,7 +7,7 @@ "bfetch": "src/plugins/bfetch", "charts": "src/plugins/charts", "console": "src/plugins/console", - "core": "src/core", + "core": ["src/core", "packages/core/i18n/core-i18n-browser-internal"], "customIntegrations": "src/plugins/custom_integrations", "dashboard": "src/plugins/dashboard", "controls": "src/plugins/controls", diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index d797669651470..aa8d70b3f87a3 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github summary: API docs for the actions plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 1b8402f59c88f..b4359ef0e6fac 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github summary: API docs for the advancedSettings plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index e970547c6ae93..b84273128b873 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github summary: API docs for the aiops plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 4cbf27c578880..c660f149a18f7 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github summary: API docs for the alerting plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 51bd8b5ba4213..6100122ca8cb1 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github summary: API docs for the apm plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 2bf8f6d1b2d51..9efb27bdf70d3 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github summary: API docs for the banners plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index b30e2db5d784f..75a4484d9dbca 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github summary: API docs for the bfetch plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 447683f585321..d15bfd331d410 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github summary: API docs for the canvas plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 01740e93b83fc..8e6b7ff04c30a 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github summary: API docs for the cases plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index e3255cd38c663..2d9fe262fab2b 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github summary: API docs for the charts plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 1e52786a522d5..015725fc4b46b 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github summary: API docs for the cloud plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 2886ff662f997..552c5f84bbb6a 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github summary: API docs for the cloudSecurityPosture plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/console.mdx b/api_docs/console.mdx index f9595356a14ce..ecd66045beb20 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github summary: API docs for the console plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 67009a44f3de8..67400c3730c05 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github summary: API docs for the controls plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/core.devdocs.json b/api_docs/core.devdocs.json index 78f4a5a65e08d..c1181b59c80c0 100644 --- a/api_docs/core.devdocs.json +++ b/api_docs/core.devdocs.json @@ -1583,13 +1583,7 @@ "{@link I18nStart}" ], "signature": [ - { - "pluginId": "core", - "scope": "public", - "docId": "kibCorePluginApi", - "section": "def-public.I18nStart", - "text": "I18nStart" - } + "I18nStart" ], "path": "src/core/public/index.ts", "deprecated": false @@ -2647,9 +2641,9 @@ "tags": [], "label": "I18nStart", "description": [ - "\nI18nStart.Context is required by any localizable React component from \\@kbn/i18n and \\@elastic/eui packages\nand is supposed to be used as the topmost component for any i18n-compatible React tree.\n" + "\r\nI18nStart.Context is required by any localizable React component from \\@kbn/i18n and \\@elastic/eui packages\r\nand is supposed to be used as the topmost component for any i18n-compatible React tree.\r\n" ], - "path": "src/core/public/i18n/i18n_service.tsx", + "path": "node_modules/@types/kbn__core-i18n-browser/index.d.ts", "deprecated": false, "children": [ { @@ -2659,12 +2653,12 @@ "tags": [], "label": "Context", "description": [ - "\nReact Context provider required as the topmost component for any i18n-compatible React tree." + "\r\nReact Context provider required as the topmost component for any i18n-compatible React tree." ], "signature": [ "({ children }: { children: React.ReactNode; }) => JSX.Element" ], - "path": "src/core/public/i18n/i18n_service.tsx", + "path": "node_modules/@types/kbn__core-i18n-browser/index.d.ts", "deprecated": false, "children": [ { @@ -2674,7 +2668,7 @@ "tags": [], "label": "{ children }", "description": [], - "path": "src/core/public/i18n/i18n_service.tsx", + "path": "node_modules/@types/kbn__core-i18n-browser/index.d.ts", "deprecated": false, "children": [ { @@ -2687,7 +2681,7 @@ "signature": [ "boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined" ], - "path": "src/core/public/i18n/i18n_service.tsx", + "path": "node_modules/@types/kbn__core-i18n-browser/index.d.ts", "deprecated": false } ] @@ -24176,7 +24170,7 @@ "tags": [], "label": "AnalyticsServicePreboot", "description": [ - "\nExposes the public APIs of the AnalyticsClient during the preboot phase\n{@link AnalyticsClient}" + "\r\nExposes the public APIs of the AnalyticsClient during the preboot phase\r\n{@link AnalyticsClient}" ], "signature": [ "{ optIn: (optInConfig: ", @@ -24197,7 +24191,7 @@ "ContextProviderOpts", ") => void; removeContextProvider: (contextProviderName: string) => void; }" ], - "path": "src/core/server/analytics/analytics_service.ts", + "path": "node_modules/@types/kbn__core-analytics-server/index.d.ts", "deprecated": false, "initialIsOpen": false }, @@ -24208,7 +24202,7 @@ "tags": [], "label": "AnalyticsServiceSetup", "description": [ - "\nExposes the public APIs of the AnalyticsClient during the setup phase.\n{@link AnalyticsClient}" + "\r\nExposes the public APIs of the AnalyticsClient during the setup phase.\r\n{@link AnalyticsClient}" ], "signature": [ "{ optIn: (optInConfig: ", @@ -24229,7 +24223,7 @@ "ContextProviderOpts", ") => void; removeContextProvider: (contextProviderName: string) => void; }" ], - "path": "src/core/server/analytics/analytics_service.ts", + "path": "node_modules/@types/kbn__core-analytics-server/index.d.ts", "deprecated": false, "initialIsOpen": false }, @@ -24240,7 +24234,7 @@ "tags": [], "label": "AnalyticsServiceStart", "description": [ - "\nExposes the public APIs of the AnalyticsClient during the start phase\n{@link AnalyticsClient}" + "\r\nExposes the public APIs of the AnalyticsClient during the start phase\r\n{@link AnalyticsClient}" ], "signature": [ "{ optIn: (optInConfig: ", @@ -24251,7 +24245,7 @@ "TelemetryCounter", ">; }" ], - "path": "src/core/server/analytics/analytics_service.ts", + "path": "node_modules/@types/kbn__core-analytics-server/index.d.ts", "deprecated": false, "initialIsOpen": false }, diff --git a/api_docs/core.mdx b/api_docs/core.mdx index 9bf639c6ceed3..e3b2da5c430d1 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github summary: API docs for the core plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2527 | 15 | 940 | 29 | +| 2527 | 15 | 938 | 29 | ## Client diff --git a/api_docs/core_application.mdx b/api_docs/core_application.mdx index 9b15a4c99728b..ccd83243240cc 100644 --- a/api_docs/core_application.mdx +++ b/api_docs/core_application.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/core-application title: "core.application" image: https://source.unsplash.com/400x175/?github summary: API docs for the core.application plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.application'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2527 | 15 | 940 | 29 | +| 2527 | 15 | 938 | 29 | ## Client diff --git a/api_docs/core_chrome.mdx b/api_docs/core_chrome.mdx index 8ecc59ccbebed..a9682a8e3b4a1 100644 --- a/api_docs/core_chrome.mdx +++ b/api_docs/core_chrome.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/core-chrome title: "core.chrome" image: https://source.unsplash.com/400x175/?github summary: API docs for the core.chrome plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.chrome'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2527 | 15 | 940 | 29 | +| 2527 | 15 | 938 | 29 | ## Client diff --git a/api_docs/core_http.mdx b/api_docs/core_http.mdx index e674a58a1557d..dbe127e3f003d 100644 --- a/api_docs/core_http.mdx +++ b/api_docs/core_http.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/core-http title: "core.http" image: https://source.unsplash.com/400x175/?github summary: API docs for the core.http plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.http'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2527 | 15 | 940 | 29 | +| 2527 | 15 | 938 | 29 | ## Client diff --git a/api_docs/core_saved_objects.mdx b/api_docs/core_saved_objects.mdx index 04a7d497d1b01..a4443c941dd86 100644 --- a/api_docs/core_saved_objects.mdx +++ b/api_docs/core_saved_objects.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/core-savedObjects title: "core.savedObjects" image: https://source.unsplash.com/400x175/?github summary: API docs for the core.savedObjects plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.savedObjects'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -18,7 +18,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2527 | 15 | 940 | 29 | +| 2527 | 15 | 938 | 29 | ## Client diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index f04be45f934fe..f7586442664bc 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github summary: API docs for the customIntegrations plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index 98dea779023b5..8dc6d7fdcfb6f 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github summary: API docs for the dashboard plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index cea698f443ce0..e8953c4281e28 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github summary: API docs for the dashboardEnhanced plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data.mdx b/api_docs/data.mdx index cc6c86fcb5f52..9e2ff20a26ccb 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github summary: API docs for the data plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index a7bb8fa4d9919..97cb36245b0df 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github summary: API docs for the data.query plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index bde8c91920935..badce42c47a6f 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github summary: API docs for the data.search plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index f62aa9f36c3c1..6ff647d20d447 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github summary: API docs for the dataViewEditor plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 0943418c1c5b2..ce0cac3a3ace3 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github summary: API docs for the dataViewFieldEditor plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 4297e16c393fc..8a0db6bb2066e 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github summary: API docs for the dataViewManagement plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 3d50dcf400d63..8d2ffe07ca1e9 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github summary: API docs for the dataViews plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index d545aa1752f9c..4761b678c4b82 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github summary: API docs for the dataVisualizer plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 97c708c366bd2..5683d95bd30fe 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -3,7 +3,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API summary: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index d4222f6c65916..75ca037c25bb2 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -3,7 +3,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin summary: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 9a995d287dcfe..38244e76f344c 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -3,7 +3,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team summary: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index b95162c73b70c..bca811b137130 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github summary: API docs for the devTools plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 92b15fa4eb518..738d6255dc1fd 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github summary: API docs for the discover plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 2615d10e20873..afd26d8f4c263 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github summary: API docs for the discoverEnhanced plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/elastic_apm_synthtrace.mdx b/api_docs/elastic_apm_synthtrace.mdx index 0dcc042b805fe..bf80df96fbcc5 100644 --- a/api_docs/elastic_apm_synthtrace.mdx +++ b/api_docs/elastic_apm_synthtrace.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/elastic-apm-synthtrace title: "@elastic/apm-synthtrace" image: https://source.unsplash.com/400x175/?github summary: API docs for the @elastic/apm-synthtrace plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@elastic/apm-synthtrace'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index b373d348d2e00..ae626a79b9444 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github summary: API docs for the embeddable plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 87ed46ed5618f..7a04080e707ce 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github summary: API docs for the embeddableEnhanced plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 5d0b699131f19..f80624d76f739 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github summary: API docs for the encryptedSavedObjects plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 2257e89887682..89c9d98c5a85b 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github summary: API docs for the enterpriseSearch plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 7c74fd18d9d7d..71748ba2c183e 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github summary: API docs for the esUiShared plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index db4361f4c71d2..5c7f4d4392176 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github summary: API docs for the eventAnnotation plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index ce71219c77661..c0f5673c3e4a5 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github summary: API docs for the eventLog plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index ea3154c081499..972a3099e2ee5 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionError plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 27f553c9df86f..c738384c60305 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionGauge plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index abff740b84120..aa27f9360b628 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionHeatmap plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 66c0685e867d2..452d5166377c2 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionImage plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index bfd39bb2af47f..ceb63f6fdc9d5 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionMetric plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index 218a7ee0ce7ef..be5ffab9f5e45 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionMetricVis plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 6469a974d591b..5260a7add6010 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionPartitionVis plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index e9892fab347b0..51bd5c3790838 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionRepeatImage plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index 55c6ed9527d46..7e9db0b0f0c70 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionRevealImage plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 202e4c6e2e365..cf4f2a7ae3ebb 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionShape plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index 142c613588dd3..4f8f87e51555d 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionTagcloud plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 6a2bb59b4fea3..bc48042555b6f 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressionXY plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 02e63b832df83..7ceb36224bb14 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github summary: API docs for the expressions plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/features.mdx b/api_docs/features.mdx index bde45470db66b..f66bc3d55d9a3 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github summary: API docs for the features plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index aee6e9622505a..5021dd2eea449 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github summary: API docs for the fieldFormats plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index ff81f3660218f..729b43555dc75 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github summary: API docs for the fileUpload plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 74ab074a74209..3bb51cbf90196 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github summary: API docs for the fleet plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index c9055be152e4c..2f2009cdb8a90 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github summary: API docs for the globalSearch plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 9bf1f688986f6..bc34d629ae8ac 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github summary: API docs for the home plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index f2e9c6bfc9a36..1f34605863969 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github summary: API docs for the indexLifecycleManagement plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 46baf65ed5268..29f9caea1d449 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github summary: API docs for the indexManagement plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index fb6ced4363fcf..fb3cb5242d85c 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github summary: API docs for the infra plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index a1fc5bd30b20e..95f83c9fa5bc1 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github summary: API docs for the inspector plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 6c47cc38b0f38..7edb48d5d7919 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github summary: API docs for the interactiveSetup plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index a4993cf778bb3..f78923593d2ec 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/ace plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index 37fc706f762bd..c44c318c2ff69 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/aiops-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 8007be27038fc..8226fde3fee3a 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/alerts plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 3e6c179cb6fd8..f44200ef97bfe 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/analytics plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index 4018c2960bb47..84315fff01c2c 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/analytics-client plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index f9efcde37ff5a..47602a63dcc83 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 20f03a5c1b9be..e061874d47be4 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 036dff2834a98..4fe9239d5d670 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index f20a328bbd061..72814b9f92bea 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 8c1d4205d47e4..e0ebf664398e4 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/apm-config-loader plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 7e4cc478ad446..fe2c5f5459cfb 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/apm-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index f88ba9abb50f1..c155bf54291d8 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/axe-config plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_bazel_packages.mdx b/api_docs/kbn_bazel_packages.mdx index 20abe35be350f..4fbac5adf9133 100644 --- a/api_docs/kbn_bazel_packages.mdx +++ b/api_docs/kbn_bazel_packages.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-bazel-packages title: "@kbn/bazel-packages" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/bazel-packages plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bazel-packages'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_bazel_runner.mdx b/api_docs/kbn_bazel_runner.mdx index 3fbcc63a1e034..82ceb55e52a60 100644 --- a/api_docs/kbn_bazel_runner.mdx +++ b/api_docs/kbn_bazel_runner.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-bazel-runner title: "@kbn/bazel-runner" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/bazel-runner plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bazel-runner'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 1a43b788c1825..319f32b8fcb66 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/ci-stats-core plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_ci_stats_performance_metrics.devdocs.json b/api_docs/kbn_ci_stats_performance_metrics.devdocs.json new file mode 100644 index 0000000000000..87ed9278a28f4 --- /dev/null +++ b/api_docs/kbn_ci_stats_performance_metrics.devdocs.json @@ -0,0 +1,75 @@ +{ + "id": "@kbn/ci-stats-performance-metrics", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/ci-stats-performance-metrics", + "id": "def-server.reporter", + "type": "Function", + "tags": [], + "label": "reporter", + "description": [], + "signature": [ + "(options: ReporterOptions) => Promise" + ], + "path": "packages/kbn-ci-stats-performance-metrics/src/reporter.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/ci-stats-performance-metrics", + "id": "def-server.reporter.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "ReporterOptions" + ], + "path": "packages/kbn-ci-stats-performance-metrics/src/reporter.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ci-stats-performance-metrics", + "id": "def-server.runCli", + "type": "Function", + "tags": [], + "label": "runCli", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-ci-stats-performance-metrics/src/cli.ts", + "deprecated": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx new file mode 100644 index 0000000000000..7c492a4f3179f --- /dev/null +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCiStatsPerformanceMetricsPluginApi +slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics +title: "@kbn/ci-stats-performance-metrics" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/ci-stats-performance-metrics plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 3 | 0 | 3 | 0 | + +## Server + +### Functions + + diff --git a/api_docs/kbn_ci_stats_reporter.devdocs.json b/api_docs/kbn_ci_stats_reporter.devdocs.json index 7c0232b6d81dd..195e8e8a5a429 100644 --- a/api_docs/kbn_ci_stats_reporter.devdocs.json +++ b/api_docs/kbn_ci_stats_reporter.devdocs.json @@ -309,6 +309,38 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/ci-stats-reporter", + "id": "def-server.CiStatsReporter.reportPerformanceMetrics", + "type": "Function", + "tags": [], + "label": "reportPerformanceMetrics", + "description": [], + "signature": [ + "(metrics: ", + "PerformanceMetrics", + ") => Promise" + ], + "path": "packages/kbn-ci-stats-reporter/src/ci_stats_reporter.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/ci-stats-reporter", + "id": "def-server.CiStatsReporter.reportPerformanceMetrics.$1", + "type": "Object", + "tags": [], + "label": "metrics", + "description": [], + "signature": [ + "PerformanceMetrics" + ], + "path": "packages/kbn-ci-stats-reporter/src/ci_stats_reporter.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index fd3d10a85a509..8bfd1bacb1ebc 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/ci-stats-reporter plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -18,7 +18,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 60 | 0 | 15 | 0 | +| 62 | 0 | 17 | 1 | ## Server diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index 43f72e4163575..d14d05cb69613 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/cli-dev-mode plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 0f68cb49dec35..1c1853a813f82 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/coloring plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index d33fb0ca31e26..de9304b37fa96 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/config plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index 4235898a4f5b2..43479e7f25abb 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/config-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 30f1f8636bdd8..dd452f8e7f0ba 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/config-schema plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 9d63767df02cb..34ca1ad7c523a 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-analytics-browser plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 7415fdfd045cd..415c5c8dbef4e 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 21657e30fdf16..06a3419da43d1 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_analytics_server.devdocs.json b/api_docs/kbn_core_analytics_server.devdocs.json new file mode 100644 index 0000000000000..d2f49935b878d --- /dev/null +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -0,0 +1,114 @@ +{ + "id": "@kbn/core-analytics-server", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-server.AnalyticsServicePreboot", + "type": "Type", + "tags": [], + "label": "AnalyticsServicePreboot", + "description": [ + "\nExposes the public APIs of the AnalyticsClient during the preboot phase\n{@link AnalyticsClient}" + ], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: >(eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; registerEventType: (eventTypeOps: ", + "EventTypeOpts", + ") => void; registerShipper: (Shipper: ", + "ShipperClassConstructor", + ", shipperConfig: ShipperConfig, opts?: ", + "RegisterShipperOpts", + " | undefined) => void; registerContextProvider: (contextProviderOpts: ", + "ContextProviderOpts", + ") => void; removeContextProvider: (contextProviderName: string) => void; }" + ], + "path": "packages/core/analytics/core-analytics-server/src/contracts.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-server.AnalyticsServiceSetup", + "type": "Type", + "tags": [], + "label": "AnalyticsServiceSetup", + "description": [ + "\nExposes the public APIs of the AnalyticsClient during the setup phase.\n{@link AnalyticsClient}" + ], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: >(eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; registerEventType: (eventTypeOps: ", + "EventTypeOpts", + ") => void; registerShipper: (Shipper: ", + "ShipperClassConstructor", + ", shipperConfig: ShipperConfig, opts?: ", + "RegisterShipperOpts", + " | undefined) => void; registerContextProvider: (contextProviderOpts: ", + "ContextProviderOpts", + ") => void; removeContextProvider: (contextProviderName: string) => void; }" + ], + "path": "packages/core/analytics/core-analytics-server/src/contracts.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-analytics-server", + "id": "def-server.AnalyticsServiceStart", + "type": "Type", + "tags": [], + "label": "AnalyticsServiceStart", + "description": [ + "\nExposes the public APIs of the AnalyticsClient during the start phase\n{@link AnalyticsClient}" + ], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: >(eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; }" + ], + "path": "packages/core/analytics/core-analytics-server/src/contracts.ts", + "deprecated": false, + "initialIsOpen": false + } + ], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx new file mode 100644 index 0000000000000..453ba67379d04 --- /dev/null +++ b/api_docs/kbn_core_analytics_server.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCoreAnalyticsServerPluginApi +slug: /kibana-dev-docs/api/kbn-core-analytics-server +title: "@kbn/core-analytics-server" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/core-analytics-server plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 3 | 0 | 0 | 0 | + +## Server + +### Consts, variables and types + + diff --git a/api_docs/kbn_core_analytics_server_internal.devdocs.json b/api_docs/kbn_core_analytics_server_internal.devdocs.json new file mode 100644 index 0000000000000..fda46f67f4a16 --- /dev/null +++ b/api_docs/kbn_core_analytics_server_internal.devdocs.json @@ -0,0 +1,134 @@ +{ + "id": "@kbn/core-analytics-server-internal", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [ + { + "parentPluginId": "@kbn/core-analytics-server-internal", + "id": "def-server.AnalyticsService", + "type": "Class", + "tags": [], + "label": "AnalyticsService", + "description": [], + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server-internal", + "id": "def-server.AnalyticsService.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server-internal", + "id": "def-server.AnalyticsService.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "CoreContext" + ], + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server-internal", + "id": "def-server.AnalyticsService.preboot", + "type": "Function", + "tags": [], + "label": "preboot", + "description": [], + "signature": [ + "() => ", + "AnalyticsServicePreboot" + ], + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server-internal", + "id": "def-server.AnalyticsService.setup", + "type": "Function", + "tags": [], + "label": "setup", + "description": [], + "signature": [ + "() => ", + "AnalyticsServiceSetup" + ], + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server-internal", + "id": "def-server.AnalyticsService.start", + "type": "Function", + "tags": [], + "label": "start", + "description": [], + "signature": [ + "() => ", + "AnalyticsServiceStart" + ], + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server-internal", + "id": "def-server.AnalyticsService.stop", + "type": "Function", + "tags": [], + "label": "stop", + "description": [], + "signature": [ + "() => void" + ], + "path": "packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts", + "deprecated": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx new file mode 100644 index 0000000000000..b033e3316a624 --- /dev/null +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCoreAnalyticsServerInternalPluginApi +slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal +title: "@kbn/core-analytics-server-internal" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/core-analytics-server-internal plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 7 | 0 | 7 | 0 | + +## Server + +### Classes + + diff --git a/api_docs/kbn_core_analytics_server_mocks.devdocs.json b/api_docs/kbn_core_analytics_server_mocks.devdocs.json new file mode 100644 index 0000000000000..6d6fe2b36e0e5 --- /dev/null +++ b/api_docs/kbn_core_analytics_server_mocks.devdocs.json @@ -0,0 +1,107 @@ +{ + "id": "@kbn/core-analytics-server-mocks", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "@kbn/core-analytics-server-mocks", + "id": "def-server.analyticsServiceMock", + "type": "Object", + "tags": [], + "label": "analyticsServiceMock", + "description": [], + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-analytics-server-mocks", + "id": "def-server.analyticsServiceMock.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => jest.Mocked" + ], + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts", + "deprecated": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server-mocks", + "id": "def-server.analyticsServiceMock.createAnalyticsServicePreboot", + "type": "Function", + "tags": [], + "label": "createAnalyticsServicePreboot", + "description": [], + "signature": [ + "() => jest.Mocked<", + "AnalyticsServicePreboot", + ">" + ], + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts", + "deprecated": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server-mocks", + "id": "def-server.analyticsServiceMock.createAnalyticsServiceSetup", + "type": "Function", + "tags": [], + "label": "createAnalyticsServiceSetup", + "description": [], + "signature": [ + "() => jest.Mocked<", + "AnalyticsServiceSetup", + ">" + ], + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts", + "deprecated": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-analytics-server-mocks", + "id": "def-server.analyticsServiceMock.createAnalyticsServiceStart", + "type": "Function", + "tags": [], + "label": "createAnalyticsServiceStart", + "description": [], + "signature": [ + "() => jest.Mocked<", + "AnalyticsServiceStart", + ">" + ], + "path": "packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts", + "deprecated": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx new file mode 100644 index 0000000000000..8df7dd430ee41 --- /dev/null +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCoreAnalyticsServerMocksPluginApi +slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks +title: "@kbn/core-analytics-server-mocks" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/core-analytics-server-mocks plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 5 | 0 | 5 | 0 | + +## Server + +### Objects + + diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 64f89ba035988..1d672c961f10d 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-base-browser-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 8f7fc1a42003c..e5e75b54734ce 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-base-common plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_base_server_internal.devdocs.json b/api_docs/kbn_core_base_server_internal.devdocs.json new file mode 100644 index 0000000000000..6cc5a5d30adc9 --- /dev/null +++ b/api_docs/kbn_core_base_server_internal.devdocs.json @@ -0,0 +1,123 @@ +{ + "id": "@kbn/core-base-server-internal", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [ + { + "parentPluginId": "@kbn/core-base-server-internal", + "id": "def-server.CriticalError", + "type": "Class", + "tags": [], + "label": "CriticalError", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-base-server-internal", + "scope": "server", + "docId": "kibKbnCoreBaseServerInternalPluginApi", + "section": "def-server.CriticalError", + "text": "CriticalError" + }, + " extends Error" + ], + "path": "packages/core/base/core-base-server-internal/src/errors.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-base-server-internal", + "id": "def-server.CriticalError.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/core/base/core-base-server-internal/src/errors.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-base-server-internal", + "id": "def-server.CriticalError.Unnamed.$1", + "type": "string", + "tags": [], + "label": "message", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/base/core-base-server-internal/src/errors.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-base-server-internal", + "id": "def-server.CriticalError.Unnamed.$2", + "type": "string", + "tags": [], + "label": "code", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/base/core-base-server-internal/src/errors.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-base-server-internal", + "id": "def-server.CriticalError.Unnamed.$3", + "type": "number", + "tags": [], + "label": "processExitCode", + "description": [], + "signature": [ + "number" + ], + "path": "packages/core/base/core-base-server-internal/src/errors.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-base-server-internal", + "id": "def-server.CriticalError.Unnamed.$4", + "type": "Object", + "tags": [], + "label": "cause", + "description": [], + "signature": [ + "Error | undefined" + ], + "path": "packages/core/base/core-base-server-internal/src/errors.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx new file mode 100644 index 0000000000000..86cb682ec482e --- /dev/null +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCoreBaseServerInternalPluginApi +slug: /kibana-dev-docs/api/kbn-core-base-server-internal +title: "@kbn/core-base-server-internal" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/core-base-server-internal plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 6 | 0 | 6 | 0 | + +## Server + +### Classes + + diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index be4d31b7e6153..5a9657f828551 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-base-server-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_config_server_internal.devdocs.json b/api_docs/kbn_core_config_server_internal.devdocs.json new file mode 100644 index 0000000000000..da4e89e53775a --- /dev/null +++ b/api_docs/kbn_core_config_server_internal.devdocs.json @@ -0,0 +1,260 @@ +{ + "id": "@kbn/core-config-server-internal", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.coreDeprecationProvider", + "type": "Function", + "tags": [], + "label": "coreDeprecationProvider", + "description": [], + "signature": [ + "() => ", + "ConfigDeprecation", + "[]" + ], + "path": "packages/core/config/core-config-server-internal/src/deprecation/core_deprecations.ts", + "deprecated": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.ensureValidConfiguration", + "type": "Function", + "tags": [], + "label": "ensureValidConfiguration", + "description": [], + "signature": [ + "(configService: ", + "ConfigService", + ", params: ", + "ConfigValidateParameters", + " | undefined) => Promise" + ], + "path": "packages/core/config/core-config-server-internal/src/ensure_valid_configuration.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.ensureValidConfiguration.$1", + "type": "Object", + "tags": [], + "label": "configService", + "description": [], + "signature": [ + "ConfigService" + ], + "path": "packages/core/config/core-config-server-internal/src/ensure_valid_configuration.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.ensureValidConfiguration.$2", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "ConfigValidateParameters", + " | undefined" + ], + "path": "packages/core/config/core-config-server-internal/src/ensure_valid_configuration.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsFor", + "type": "Function", + "tags": [], + "label": "getDeprecationsFor", + "description": [], + "signature": [ + "({ provider, settings, path, }: { provider: ", + "ConfigDeprecationProvider", + "; settings?: Record | undefined; path: string; }) => { messages: string[]; levels: string[]; migrated: Record; }" + ], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsFor.$1", + "type": "Object", + "tags": [], + "label": "{\n provider,\n settings = {},\n path,\n}", + "description": [], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsFor.$1.provider", + "type": "Function", + "tags": [], + "label": "provider", + "description": [], + "signature": [ + "(factory: ", + "ConfigDeprecationFactory", + ") => ", + "ConfigDeprecation", + "[]" + ], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsFor.$1.provider.$1", + "type": "Object", + "tags": [], + "label": "factory", + "description": [], + "signature": [ + "ConfigDeprecationFactory" + ], + "path": "node_modules/@types/kbn__config/index.d.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsFor.$1.settings", + "type": "Object", + "tags": [], + "label": "settings", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsFor.$1.path", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsForGlobalSettings", + "type": "Function", + "tags": [], + "label": "getDeprecationsForGlobalSettings", + "description": [], + "signature": [ + "({ provider, settings, }: { provider: ", + "ConfigDeprecationProvider", + "; settings?: Record | undefined; }) => { messages: string[]; levels: string[]; migrated: Record; }" + ], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsForGlobalSettings.$1", + "type": "Object", + "tags": [], + "label": "{\n provider,\n settings = {},\n}", + "description": [], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsForGlobalSettings.$1.provider", + "type": "Function", + "tags": [], + "label": "provider", + "description": [], + "signature": [ + "(factory: ", + "ConfigDeprecationFactory", + ") => ", + "ConfigDeprecation", + "[]" + ], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsForGlobalSettings.$1.provider.$1", + "type": "Object", + "tags": [], + "label": "factory", + "description": [], + "signature": [ + "ConfigDeprecationFactory" + ], + "path": "node_modules/@types/kbn__config/index.d.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "@kbn/core-config-server-internal", + "id": "def-server.getDeprecationsForGlobalSettings.$1.settings", + "type": "Object", + "tags": [], + "label": "settings", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "packages/core/config/core-config-server-internal/src/test_utils.ts", + "deprecated": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx new file mode 100644 index 0000000000000..b6cbf0d678888 --- /dev/null +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCoreConfigServerInternalPluginApi +slug: /kibana-dev-docs/api/kbn-core-config-server-internal +title: "@kbn/core-config-server-internal" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/core-config-server-internal plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 15 | 0 | 13 | 0 | + +## Server + +### Functions + + diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index cf5302dd72f77..619374b571b77 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-doc-links-browser plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 0e821cd157098..4dd6b03d0161c 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 3b3ca4bcaa5a3..b5343541902fb 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-doc-links-server plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 76c157aa5e054..d9d3756d07cbd 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_i18n_browser.devdocs.json b/api_docs/kbn_core_i18n_browser.devdocs.json new file mode 100644 index 0000000000000..28c1fd36c3064 --- /dev/null +++ b/api_docs/kbn_core_i18n_browser.devdocs.json @@ -0,0 +1,86 @@ +{ + "id": "@kbn/core-i18n-browser", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/core-i18n-browser", + "id": "def-common.I18nStart", + "type": "Interface", + "tags": [], + "label": "I18nStart", + "description": [ + "\nI18nStart.Context is required by any localizable React component from \\@kbn/i18n and \\@elastic/eui packages\nand is supposed to be used as the topmost component for any i18n-compatible React tree.\n" + ], + "path": "packages/core/i18n/core-i18n-browser/src/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-i18n-browser", + "id": "def-common.I18nStart.Context", + "type": "Function", + "tags": [], + "label": "Context", + "description": [ + "\nReact Context provider required as the topmost component for any i18n-compatible React tree." + ], + "signature": [ + "({ children }: { children: React.ReactNode; }) => JSX.Element" + ], + "path": "packages/core/i18n/core-i18n-browser/src/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-i18n-browser", + "id": "def-common.I18nStart.Context.$1", + "type": "Object", + "tags": [], + "label": "{ children }", + "description": [], + "path": "packages/core/i18n/core-i18n-browser/src/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-i18n-browser", + "id": "def-common.I18nStart.Context.$1.children", + "type": "CompoundType", + "tags": [], + "label": "children", + "description": [], + "signature": [ + "boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined" + ], + "path": "packages/core/i18n/core-i18n-browser/src/types.ts", + "deprecated": false + } + ] + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx new file mode 100644 index 0000000000000..fe2b0abb4b4cc --- /dev/null +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCoreI18nBrowserPluginApi +slug: /kibana-dev-docs/api/kbn-core-i18n-browser +title: "@kbn/core-i18n-browser" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/core-i18n-browser plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 4 | 0 | 2 | 0 | + +## Common + +### Interfaces + + diff --git a/api_docs/kbn_core_i18n_browser_mocks.devdocs.json b/api_docs/kbn_core_i18n_browser_mocks.devdocs.json new file mode 100644 index 0000000000000..7811c288caed5 --- /dev/null +++ b/api_docs/kbn_core_i18n_browser_mocks.devdocs.json @@ -0,0 +1,73 @@ +{ + "id": "@kbn/core-i18n-browser-mocks", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "@kbn/core-i18n-browser-mocks", + "id": "def-common.i18nServiceMock", + "type": "Object", + "tags": [], + "label": "i18nServiceMock", + "description": [], + "path": "packages/core/i18n/core-i18n-browser-mocks/src/i18n_service.mock.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-i18n-browser-mocks", + "id": "def-common.i18nServiceMock.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => jest.Mocked" + ], + "path": "packages/core/i18n/core-i18n-browser-mocks/src/i18n_service.mock.ts", + "deprecated": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-i18n-browser-mocks", + "id": "def-common.i18nServiceMock.createStartContract", + "type": "Function", + "tags": [], + "label": "createStartContract", + "description": [], + "signature": [ + "() => jest.Mocked<", + "I18nStart", + ">" + ], + "path": "packages/core/i18n/core-i18n-browser-mocks/src/i18n_service.mock.ts", + "deprecated": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + } + ] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx new file mode 100644 index 0000000000000..715b38c4aef94 --- /dev/null +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -0,0 +1,27 @@ +--- +id: kibKbnCoreI18nBrowserMocksPluginApi +slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks +title: "@kbn/core-i18n-browser-mocks" +image: https://source.unsplash.com/400x175/?github +summary: API docs for the @kbn/core-i18n-browser-mocks plugin +date: 2022-06-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] +warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. +--- +import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 3 | 0 | 3 | 0 | + +## Common + +### Objects + + diff --git a/api_docs/kbn_core_injected_metadata_browser.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index b3816f2d31255..0dfa95e8653ac 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-injected-metadata-browser plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index e5fde4fca46e0..18dd111b5bdea 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 4bd8571aa5858..b7d51a892cad4 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-logging-server plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 452fb9a6deda9..24787602fd826 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-logging-server-internal plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 93254645d2cc1..596ae2e2d0c87 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-logging-server-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 50ace4e85197f..73ec2992c6056 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-theme-browser plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 1d7f02a176b3e..fa6b098cf25ac 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index bd979a55a7b96..05421434cb5b9 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/crypto plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 2873ceafac55f..3507ad5af0a3f 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/datemath plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index a4686de799c9d..c7fc9e821a93f 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/dev-cli-errors plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 9247656496398..ccf27f5dc4907 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/dev-cli-runner plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 86b45e3b28215..613bddfbc0e6a 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/dev-proc-runner plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 3fa3295fe605d..80ede3a8f2ce5 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/dev-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index abb751f0b8964..f35f2a788324c 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/doc-links plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index c1d0ef70fb894..5425bf061fc86 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/docs-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index a65bbce6b7df5..fea0955a22e95 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/es-archiver plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index c71f7ac7ce64c..a6869f197252d 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/es-query plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 79cedb14c81e1..9bdfd637706b9 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/eslint-plugin-imports plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 79219f14c9a80..fd68af1589767 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/field-types plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index d74690a25741d..9c2f9020578e2 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/find-used-node-modules plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index d0a9254642187..4c8ed429da1c2 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/generate plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index ebb98181a03e3..321c9000cd1d7 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/handlebars plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 924a77a4dc73c..55782575d4a2d 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/i18n plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 689395ca46f78..cfc5f243f43d7 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/import-resolver plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 9f6abcfed25a9..4e73e2c5ace40 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/interpreter plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index c85e1c5161d3a..ef11b76adc992 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/io-ts-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 10d09ba774ead..1380af516f2d0 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/jest-serializers plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_kibana_json_schema.mdx b/api_docs/kbn_kibana_json_schema.mdx index 1c27bd1550d86..a3d937b8ee946 100644 --- a/api_docs/kbn_kibana_json_schema.mdx +++ b/api_docs/kbn_kibana_json_schema.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-json-schema title: "@kbn/kibana-json-schema" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/kibana-json-schema plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-json-schema'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index a10e412bf4f01..54487887fbc56 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/logging plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index 143b29a9f865d..b4188f4410c64 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/logging-mocks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index fa1f9f2c6ec41..d031ab2e997bd 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/mapbox-gl plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index bc92c78f29686..339350026a676 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/monaco plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index bb27ae64cb91a..d6c3951da8a48 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/optimizer plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index e484f0ead7a58..73e3151761d74 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 5359b6d6ca332..5be0ada3b19e4 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_plugin_discovery.mdx b/api_docs/kbn_plugin_discovery.mdx index 5a84642278865..90e958b824606 100644 --- a/api_docs/kbn_plugin_discovery.mdx +++ b/api_docs/kbn_plugin_discovery.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-discovery title: "@kbn/plugin-discovery" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/plugin-discovery plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-discovery'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index a134aaa626f0e..619141948aebe 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/plugin-generator plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 8c8c853b9d0ab..9030770483370 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/plugin-helpers plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_pm.mdx b/api_docs/kbn_pm.mdx index 8903529981b99..8ed75da929b79 100644 --- a/api_docs/kbn_pm.mdx +++ b/api_docs/kbn_pm.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-pm title: "@kbn/pm" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/pm plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/pm'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 97eaa4abd5079..429c623648380 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/react-field plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index f5b53a4c08a99..9c72ccef64e2f 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/rule-data-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_scalability_simulation_generator.mdx b/api_docs/kbn_scalability_simulation_generator.mdx index 9a7b205f79ab6..0c9777f519007 100644 --- a/api_docs/kbn_scalability_simulation_generator.mdx +++ b/api_docs/kbn_scalability_simulation_generator.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-scalability-simulation-generator title: "@kbn/scalability-simulation-generator" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/scalability-simulation-generator plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/scalability-simulation-generator'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index d9159b8c1b379..6a6308e1ffae9 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 944f24b63a6cc..2ee30c0656dcf 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-es-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index d8a77eaeeb160..dcc8bf31d9049 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 1c3ec9f3c5fa4..117a1eb2c5159 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 0535b4655d6dd..9c5752b203eb0 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 209109867e772..48fd0ca8ed815 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index cf783c9e2a9d7..571a2f9303ccb 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 4d54305c25a01..a0bcd043d61d4 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-list-api plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index d60c93054faec..993f080fcc193 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-list-constants plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index e7a4be15ba900..85234c585d286 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 548d3a6826a9f..c8d5be6aad2c5 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-list-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 24e05f4952126..96b51f9113c2e 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-rules plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index ff18a7f3135c7..789760a4208e4 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-t-grid plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 186f5106c9ecc..f07604490c02d 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/securitysolution-utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index 1bd0fc10274f0..3b15b68770eda 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/server-http-tools plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index ea8349c280bf2..af36112b1cda2 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/server-route-repository plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index b0bf3309241cd..f6f742628e522 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 4927ef7d422a6..baa5703955597 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_components.mdx b/api_docs/kbn_shared_ux_components.mdx index 90f9d0da202d6..c856e7de45b63 100644 --- a/api_docs/kbn_shared_ux_components.mdx +++ b/api_docs/kbn_shared_ux_components.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-components title: "@kbn/shared-ux-components" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-components plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-components'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 25263bf851522..4723ab64fc68e 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index e88217dcefe35..214a878423a93 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index b92aac33cf0aa..b7fb30739d2b8 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_services.mdx b/api_docs/kbn_shared_ux_services.mdx index f809536fb2f63..5f60e287b33d3 100644 --- a/api_docs/kbn_shared_ux_services.mdx +++ b/api_docs/kbn_shared_ux_services.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-services title: "@kbn/shared-ux-services" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-services plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-services'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_storybook.mdx b/api_docs/kbn_shared_ux_storybook.mdx index 60f18e4f85447..eb278f6594d12 100644 --- a/api_docs/kbn_shared_ux_storybook.mdx +++ b/api_docs/kbn_shared_ux_storybook.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook title: "@kbn/shared-ux-storybook" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-storybook plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 5dec81ad3ac9d..3cee3986320d0 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/shared-ux-utility plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index 22052b556d703..42b1a1ec4b1b1 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/sort-package-json plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index acfcc9383bb1c..7807dfb8faf19 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/std plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 191e64cdf1b15..dcdbeeba9fa5c 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/stdio-dev-helpers plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index 9915f6c0ffb52..72da8a866e68b 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/storybook plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 1d9a712006716..6af8cd22263d4 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/telemetry-tools plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_test.devdocs.json b/api_docs/kbn_test.devdocs.json index b049321dd2e41..5ef0d045fbc3f 100644 --- a/api_docs/kbn_test.devdocs.json +++ b/api_docs/kbn_test.devdocs.json @@ -958,6 +958,87 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/test", + "id": "def-server.KbnClientRequesterError", + "type": "Class", + "tags": [], + "label": "KbnClientRequesterError", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "server", + "docId": "kibKbnTestPluginApi", + "section": "def-server.KbnClientRequesterError", + "text": "KbnClientRequesterError" + }, + " extends Error" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-server.KbnClientRequesterError.axiosError", + "type": "Object", + "tags": [], + "label": "axiosError", + "description": [], + "signature": [ + "AxiosError", + " | undefined" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-server.KbnClientRequesterError.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-server.KbnClientRequesterError.Unnamed.$1", + "type": "string", + "tags": [], + "label": "message", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/test", + "id": "def-server.KbnClientRequesterError.Unnamed.$2", + "type": "Unknown", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/test", "id": "def-server.Lifecycle", diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 82c4660718088..5b96789883cea 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/test plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -18,7 +18,7 @@ Contact Operations for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 241 | 5 | 202 | 9 | +| 246 | 5 | 207 | 9 | ## Server diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index cbf66e2e32d12..8b3b115917f5f 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/test-jest-helpers plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index f58eea4717a3c..d5d72ee68eb46 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/tooling-log plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index 8ae22eea4c48f..d9a99bc918996 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/type-summarizer plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 5de17b41dda5d..0d47f81985c33 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/typed-react-router-config plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 2a9a98da12496..afad507cc268f 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/ui-theme plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index c0bf713a000c4..bd4ac2c281582 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/utility-types plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index f34e19084886d..ef3e2bead5c0e 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/utility-types-jest plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 68a8d863e92c8..09a812a5932a1 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github summary: API docs for the @kbn/utils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index f0b4a3c578ae9..6b55b014d810e 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github summary: API docs for the kibanaOverview plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kibana_react.devdocs.json b/api_docs/kibana_react.devdocs.json index 114c6531060a2..30705843ab0f9 100644 --- a/api_docs/kibana_react.devdocs.json +++ b/api_docs/kibana_react.devdocs.json @@ -4387,13 +4387,7 @@ "text": "SavedObjectsStart" }, " | undefined; i18n?: ", - { - "pluginId": "core", - "scope": "public", - "docId": "kibCorePluginApi", - "section": "def-public.I18nStart", - "text": "I18nStart" - }, + "I18nStart", " | undefined; notifications?: ", { "pluginId": "core", diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index bcdd5f22cab89..9a57e86eb9534 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github summary: API docs for the kibanaReact plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index aad503a434db1..e7d76168b35b4 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github summary: API docs for the kibanaUtils plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 4525bbe2e90ea..3533959bd49bd 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github summary: API docs for the kubernetesSecurity plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index f3a701a57c6f7..94aad70595690 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github summary: API docs for the lens plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index 20aa6358763ad..67ab1d0b38048 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github summary: API docs for the licenseApiGuard plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 672bf37cfefb7..b9ca3227c0186 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github summary: API docs for the licenseManagement plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 2d26f51d0b1d1..7768b99acd2d8 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github summary: API docs for the licensing plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index c9226f6423611..0ad5f14873cda 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github summary: API docs for the lists plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 85636d6db9aeb..f32d58cf2a204 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github summary: API docs for the management plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index e1a9268a4b430..c0ba7a0faca21 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github summary: API docs for the maps plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 6e53777799afe..9e2359a5d964e 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github summary: API docs for the mapsEms plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 90e4c001a78b0..c1df1686a8069 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github summary: API docs for the ml plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index fe91552cf5304..13e932aff2c8c 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github summary: API docs for the monitoring plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index efbb5010c6689..1cdd404bf76bf 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github summary: API docs for the monitoringCollection plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 8a635d95c6698..165f0f335d986 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github summary: API docs for the navigation plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index 39103b8cd170f..a39288cf3cd8d 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github summary: API docs for the newsfeed plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 8a3b10a8cce01..e2dcae516b104 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github summary: API docs for the observability plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 55bd58456c64a..f86a267e95cec 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github summary: API docs for the osquery plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 909b06aeb0f90..c71faef8e65e0 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -3,7 +3,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory summary: Directory of public APIs available through plugins or packages. -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- @@ -12,13 +12,13 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 292 | 235 | 35 | +| 300 | 243 | 35 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 26363 | 171 | 19041 | 1244 | +| 26416 | 171 | 19085 | 1248 | ## Plugin Directory @@ -38,7 +38,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Cloud Security Posture](https://github.com/orgs/elastic/teams/cloud-posture-security) | The cloud security posture plugin | 14 | 0 | 14 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 13 | 0 | 13 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 206 | 0 | 198 | 7 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2527 | 15 | 940 | 29 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2527 | 15 | 938 | 29 | | crossClusterReplication | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 101 | 0 | 82 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 143 | 0 | 141 | 12 | @@ -186,7 +186,8 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Owner missing] | - | 18 | 0 | 9 | 1 | | | [Owner missing] | - | 4 | 0 | 4 | 0 | | | [Owner missing] | - | 7 | 0 | 2 | 0 | -| | [Owner missing] | - | 60 | 0 | 15 | 0 | +| | [Owner missing] | - | 3 | 0 | 3 | 0 | +| | [Owner missing] | - | 62 | 0 | 17 | 1 | | | [Owner missing] | - | 2 | 0 | 2 | 0 | | | [Owner missing] | - | 106 | 0 | 80 | 1 | | | [Owner missing] | - | 73 | 0 | 44 | 1 | @@ -195,13 +196,20 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Owner missing] | - | 2 | 0 | 0 | 0 | | | [Owner missing] | - | 7 | 0 | 7 | 1 | | | [Owner missing] | - | 4 | 0 | 4 | 0 | +| | [Owner missing] | - | 3 | 0 | 0 | 0 | +| | [Owner missing] | - | 7 | 0 | 7 | 0 | +| | [Owner missing] | - | 5 | 0 | 5 | 0 | | | [Owner missing] | - | 3 | 0 | 3 | 0 | | | [Owner missing] | - | 12 | 0 | 3 | 0 | +| | [Owner missing] | - | 6 | 0 | 6 | 0 | | | [Owner missing] | - | 3 | 0 | 3 | 0 | +| | [Owner missing] | - | 15 | 0 | 13 | 0 | | | [Owner missing] | - | 4 | 0 | 4 | 0 | | | [Owner missing] | - | 4 | 0 | 4 | 0 | | | [Owner missing] | - | 5 | 0 | 2 | 0 | | | [Owner missing] | - | 4 | 0 | 4 | 0 | +| | [Owner missing] | - | 4 | 0 | 2 | 0 | +| | [Owner missing] | - | 3 | 0 | 3 | 0 | | | [Owner missing] | - | 8 | 2 | 6 | 0 | | | [Owner missing] | - | 4 | 0 | 4 | 0 | | | [Owner missing] | - | 56 | 0 | 30 | 0 | @@ -274,7 +282,7 @@ warning: This document is auto-generated and is meant to be viewed inside our ex | | [Owner missing] | - | 4 | 0 | 2 | 0 | | | Operations | - | 38 | 2 | 21 | 0 | | | [Owner missing] | - | 2 | 0 | 2 | 0 | -| | Operations | - | 241 | 5 | 202 | 9 | +| | Operations | - | 246 | 5 | 207 | 9 | | | [Owner missing] | - | 135 | 8 | 103 | 2 | | | [Owner missing] | - | 72 | 0 | 55 | 0 | | | [Owner missing] | - | 29 | 0 | 2 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index bf2fe7cfebf46..19052227c3c90 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github summary: API docs for the presentationUtil plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 170032a3bc4d2..3729b362ce583 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github summary: API docs for the remoteClusters plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index 5d3c8b0936a80..13556c6e80806 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github summary: API docs for the reporting plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index ca76c4653ec8e..f4fda7540b8a0 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github summary: API docs for the rollup plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 5472f6eaed6b8..272a8758c5ab1 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github summary: API docs for the ruleRegistry plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index 8f89583822b50..fabadde1d3537 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github summary: API docs for the runtimeFields plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index f51a2a70b2220..d9fac2851b6d2 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github summary: API docs for the savedObjects plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 0fbe05a13338f..79f1d2c7a2b4a 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github summary: API docs for the savedObjectsManagement plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 1b39a76ecf0b7..38e12b4aed2cf 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github summary: API docs for the savedObjectsTagging plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 94134caede2d8..400d7bca2e21b 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github summary: API docs for the savedObjectsTaggingOss plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index cff973e270d3e..97e6cd138ec62 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github summary: API docs for the screenshotMode plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index 263fbb99ec61f..2f4e0440757c1 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github summary: API docs for the screenshotting plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 0b87aeb636f9f..99283269165de 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github summary: API docs for the security plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 5b1e670ad236d..f9c4373d9fb2d 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github summary: API docs for the securitySolution plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index bfee9c84b1de8..47a076253b042 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github summary: API docs for the sessionView plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 2192eafe5e3f0..cd8bb647f2b8d 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github summary: API docs for the share plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/shared_u_x.mdx b/api_docs/shared_u_x.mdx index f64d2a3f4988b..d73c5303e9b74 100644 --- a/api_docs/shared_u_x.mdx +++ b/api_docs/shared_u_x.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/sharedUX title: "sharedUX" image: https://source.unsplash.com/400x175/?github summary: API docs for the sharedUX plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sharedUX'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 667c3941ee568..417c2500ed8cc 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github summary: API docs for the snapshotRestore plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 793c6097c28af..af5231f6d3cd3 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github summary: API docs for the spaces plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index c751bd1600098..4395c11d84e4c 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github summary: API docs for the stackAlerts plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index fbda9a1e539df..b734c5bfc99a0 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github summary: API docs for the taskManager plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index ccf398abc8dbe..b2a40aa42d368 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github summary: API docs for the telemetry plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 2f8e2e77085cf..a277dd510cb85 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github summary: API docs for the telemetryCollectionManager plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index 9fd053ad4b8db..fa058e7406b50 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github summary: API docs for the telemetryCollectionXpack plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 0704b8ce4782a..3e673801c2faf 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github summary: API docs for the telemetryManagementSection plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 3056d7d683c84..1f32392bafbb5 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github summary: API docs for the timelines plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 8de9d5e89de2d..2789c007d9ebd 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github summary: API docs for the transform plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index a987e4b4bc8f3..af6efe1d4420a 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github summary: API docs for the triggersActionsUi plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index c39a2718bf367..f242a77c877ca 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github summary: API docs for the uiActions plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 1ccc372c28f52..d59b3f8d53f0e 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github summary: API docs for the uiActionsEnhanced plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 426b8cf9fbf18..d6df7ac389983 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github summary: API docs for the unifiedSearch plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index cc30eb1fd7850..c2ea826c491b8 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github summary: API docs for the unifiedSearch.autocomplete plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index a7ec086e66b1e..016ef659b8ba9 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github summary: API docs for the urlForwarding plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 47778833e072e..de91ebeef3794 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github summary: API docs for the usageCollection plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 0058b11c6b0c8..6b85fe44c412e 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github summary: API docs for the ux plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 53a3915ea7687..d7f1cffbb3585 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github summary: API docs for the visDefaultEditor plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index a8243f4cdbc7e..e874cf81ef824 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeGauge plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 12ae5dddebc4a..724f26293f5e7 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeHeatmap plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index 88bafeff23ed5..1535dda901b09 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypePie plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index d97556bb2e801..eb1432e796dbd 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeTable plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 2055a6d670392..abebd148d2620 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeTimelion plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index d78d1cbbfbcb5..ef935085bd0e4 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeTimeseries plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 0275317068293..fde1cd3bcebd4 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeVega plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index b3be9dae57a24..e06824be95340 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeVislib plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 391ed29ea11d7..b34bd6b4905dd 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github summary: API docs for the visTypeXy plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index aa0a1affa5c38..a41c9bd8bbb59 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -4,7 +4,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github summary: API docs for the visualizations plugin -date: 2022-06-22 +date: 2022-06-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] warning: This document is auto-generated and is meant to be viewed inside our experimental, new docs system. Reach out in #docs-engineering for more info. --- diff --git a/dev_docs/key_concepts/data_views.mdx b/dev_docs/key_concepts/data_views.mdx index c514af21c0cf7..6a0c2a701fae2 100644 --- a/dev_docs/key_concepts/data_views.mdx +++ b/dev_docs/key_concepts/data_views.mdx @@ -27,3 +27,10 @@ Users can create data views via [Data view management](https://www.elastic.co/gu Additionally, they can be created through the data view API. Data views also allow formatters and custom labels to be defined for fields. + +### Services + +**hasData:** A standardized way to check the empty state for indices and data views. +- `hasESData: () => Promise; // Check to see if ES data exists` +- `hasDataView: () => Promise; // Check to see if any data view exists (managed or user created)` +- `hasUserDataView: () => Promise; // Check to see if user created data views exists` diff --git a/dev_docs/tutorials/data_views.mdx b/dev_docs/tutorials/data_views.mdx index 76c4bff8e51e3..eda4b34ac2fd4 100644 --- a/dev_docs/tutorials/data_views.mdx +++ b/dev_docs/tutorials/data_views.mdx @@ -84,3 +84,11 @@ await data.indexPatterns.delete(dataViewId); ### Data view HTTP API Rest-like HTTP CRUD+ API - [docs](https://www.elastic.co/guide/en/kibana/master/data-views-api.html) + + +### Services + +#### **hasData:** A standardized way to check the empty state for indices and data views. +- `hasESData: () => Promise; // Check to see if ES data exists` +- `hasDataView: () => Promise; // Check to see if any data view exists (managed or user created)` +- `hasUserDataView: () => Promise; // Check to see if user created data views exists` diff --git a/docs/api/alerting.asciidoc b/docs/api/alerting.asciidoc index fd5a23886cc5a..782b5aaaa77c7 100644 --- a/docs/api/alerting.asciidoc +++ b/docs/api/alerting.asciidoc @@ -33,9 +33,10 @@ For deprecated APIs, refer to <>. include::alerting/create_rule.asciidoc[leveloffset=+1] include::alerting/delete_rule.asciidoc[leveloffset=+1] +include::alerting/find_rules.asciidoc[leveloffset=+1] +include::alerting/health.asciidoc[leveloffset=+1] +include::alerting/get_rules.asciidoc[leveloffset=+1] include::alerting/update_rule.asciidoc[leveloffset=+1] -include::alerting/get_rules.asciidoc[] -include::alerting/find_rules.asciidoc[] include::alerting/list_rule_types.asciidoc[] include::alerting/enable_rule.asciidoc[] include::alerting/disable_rule.asciidoc[] @@ -43,5 +44,4 @@ include::alerting/mute_all_alerts.asciidoc[] include::alerting/mute_alert.asciidoc[] include::alerting/unmute_all_alerts.asciidoc[] include::alerting/unmute_alert.asciidoc[] -include::alerting/health.asciidoc[] include::alerting/legacy/index.asciidoc[] diff --git a/docs/api/alerting/create_rule.asciidoc b/docs/api/alerting/create_rule.asciidoc index 0b219ad00ebcb..86538499be010 100644 --- a/docs/api/alerting/create_rule.asciidoc +++ b/docs/api/alerting/create_rule.asciidoc @@ -16,10 +16,11 @@ Create {kib} rules. === {api-prereq-title} -You must have `all` privileges for the *Management* > *Stack Rules* feature or -for the *{ml-app}*, *{observability}*, or *Security* features, depending on the -`consumer` and `rule_type_id` of the rule you're creating. If the rule has -`actions`, you must also have `read` privileges for the *Management* > +You must have `all` privileges for the appropriate {kib} features, depending on +the `consumer` and `rule_type_id` of the rules you're creating. For example, the +*Management* > *Stack Rules* feature, *Analytics* > *Discover* and *{ml-app}* +features, *{observability}*, and *Security* features. If the rule has `actions`, +you must also have `read` privileges for the *Management* > *Actions and Connectors* feature. For more details, refer to <>. diff --git a/docs/api/alerting/delete_rule.asciidoc b/docs/api/alerting/delete_rule.asciidoc index 537b93872059c..12b07c5bb0f12 100644 --- a/docs/api/alerting/delete_rule.asciidoc +++ b/docs/api/alerting/delete_rule.asciidoc @@ -17,9 +17,11 @@ WARNING: After you delete a rule, you cannot recover it. === {api-prereq-title} -You must have `all` privileges for the *Management* > *Stack Rules* feature or -for the *{ml-app}*, *{observability}*, or *Security* features, depending on the -`consumer` and `rule_type_id` of the rule you're deleting. +You must have `all` privileges for the appropriate {kib} features, depending on +the `consumer` and `rule_type_id` of the rule you're deleting. For example, the +*Management* > *Stack Rules* feature, *Analytics* > *Discover* or *{ml-app}* +features, *{observability}*, or *Security* features. For more details, refer to +<>. [[delete-rule-api-path-params]] === {api-path-parms-title} diff --git a/docs/api/alerting/find_rules.asciidoc b/docs/api/alerting/find_rules.asciidoc index 48c4bb25e0eea..13b39db3f280b 100644 --- a/docs/api/alerting/find_rules.asciidoc +++ b/docs/api/alerting/find_rules.asciidoc @@ -1,77 +1,101 @@ [[find-rules-api]] -=== Find rules API +== Find rules API ++++ Find rules ++++ Retrieve a paginated set of rules based on condition. -NOTE: As rules change in {kib}, the results on each page of the response also -change. Use the find API for traditional paginated results, but avoid using it to export large amounts of data. - [[find-rules-api-request]] -==== Request +=== {api-request-title} `GET :/api/alerting/rules/_find` `GET :/s//api/alerting/rules/_find` +=== {api-prereq-title} + +You must have `read` privileges for the appropriate {kib} features, depending on +the `consumer` and `rule_type_id` of the rules you're seeking. For example, the +*Management* > *Stack Rules* feature, *Analytics* > *Discover* and *{ml-app}* +features, *{observability}*, and *Security* features. To find rules associated +with the *{stack-monitor-app}*, use the `monitoring_user` built-in role. + +For more details, refer to <>. + +=== {api-description-title} + +As rules change in {kib}, the results on each page of the response also change. +Use the find API for traditional paginated results, but avoid using it to export +large amounts of data. + +NOTE: Rule `params` are stored as a {ref}/flattened.html[flattened field type] +and analyzed as keywords. + [[find-rules-api-path-params]] -==== Path parameters +=== {api-path-parms-title} `space_id`:: - (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. +(Optional, string) An identifier for the space. If `space_id` is not provided in +the URL, the default space is used. [[find-rules-api-query-params]] -==== Query Parameters +=== {api-query-parms-title} -NOTE: Rule `params` are stored as a {ref}/flattened.html[flattened field type] and analyzed as keywords. +`default_search_operator`:: +(Optional, string) The operator to use for the `simple_query_string`. The +default is 'OR'. -`per_page`:: - (Optional, number) The number of rules to return per page. +`fields`:: +(Optional, array of strings) The fields to return in the `attributes` key of the +response. + +`filter`:: +(Optional, string) A <> string that you filter with an +attribute from your saved object. It should look like +`savedObjectType.attributes.title: "myTitle"`. However, If you used a direct +attribute of a saved object, such as `updatedAt`, you will have to define your +filter, for example, `savedObjectType.updatedAt > 2018-12-22`. + +`has_reference`:: +(Optional, object) Filters the rules that have a relation with the reference +objects with the specific "type" and "ID". `page`:: - (Optional, number) The page number. +(Optional, number) The page number. -`search`:: - (Optional, string) An Elasticsearch {ref}/query-dsl-simple-query-string-query.html[simple_query_string] query that filters the rules in the response. +`per_page`:: +(Optional, number) The number of rules to return per page. -`default_search_operator`:: - (Optional, string) The operator to use for the `simple_query_string`. The default is 'OR'. +`search`:: +(Optional, string) An {es} +{ref}/query-dsl-simple-query-string-query.html[simple_query_string] query that +filters the rules in the response. `search_fields`:: - (Optional, array|string) The fields to perform the `simple_query_string` parsed query against. - -`fields`:: - (Optional, array of strings) The fields to return in the `attributes` key of the response. +(Optional, array or string) The fields to perform the `simple_query_string` +parsed query against. `sort_field`:: - (Optional, string) Sorts the response. Could be a rule field returned in the `attributes` key of the response. +(Optional, string) Sorts the response. Could be a rule field returned in the +`attributes` key of the response. `sort_order`:: - (Optional, string) Sort direction, either `asc` or `desc`. - -`has_reference`:: - (Optional, object) Filters the rules that have a relation with the reference objects with the specific "type" and "ID". - -`filter`:: - (Optional, string) A <> string that you filter with an attribute from your saved object. - It should look like savedObjectType.attributes.title: "myTitle". However, If you used a direct attribute of a saved object, such as `updatedAt`, - you will have to define your filter, for example, savedObjectType.updatedAt > 2018-12-22. +(Optional, string) Sort direction, either `asc` or `desc`. [[find-rules-api-request-codes]] -==== Response code +=== {api-response-codes-title} `200`:: - Indicates a successful call. +Indicates a successful call. -==== Examples +=== {api-examples-title} Find rules with names that start with `my`: [source,sh] -------------------------------------------------- -$ curl -X GET api/alerting/rules/_find?search_fields=name&search=my* +GET api/alerting/rules/_find?search_fields=name&search=my* -------------------------------------------------- // KIBANA @@ -110,18 +134,19 @@ The API returns the following: "scheduled_task_id": "0b092d90-6b62-11eb-9e0d-85d233e3ee35", "execution_status": { "last_execution_date": "2021-02-10T17:55:14.262Z", - "status": "ok" + "status": "ok", + "last_duration": 384 } - }, + } ] } -------------------------------------------------- -For parameters that accept multiple values (e.g. `fields`), repeat the +For parameters that accept multiple values (such as `fields`), repeat the query parameter for each value: [source,sh] -------------------------------------------------- -$ curl -X GET api/alerting/rules/_find?fields=id&fields=name +GET api/alerting/rules/_find?fields=id&fields=name -------------------------------------------------- // KIBANA diff --git a/docs/api/alerting/get_rules.asciidoc b/docs/api/alerting/get_rules.asciidoc index 1594ec1fb7ae6..9c465b9f40ff8 100644 --- a/docs/api/alerting/get_rules.asciidoc +++ b/docs/api/alerting/get_rules.asciidoc @@ -1,5 +1,5 @@ [[get-rule-api]] -=== Get rule API +== Get rule API ++++ Get rule ++++ @@ -7,35 +7,46 @@ Retrieve a rule by ID. [[get-rule-api-request]] -==== Request +=== {api-request-title} `GET :/api/alerting/rule/` `GET :/s//api/alerting/rule/` +=== {api-prereq-title} + +You must have `read` privileges for the appropriate {kib} features, depending on +the `consumer` and `rule_type_id` of the rules you're seeking. For example, the +*Management* > *Stack Rules* feature, *Analytics* > *Discover* and *{ml-app}* +features, *{observability}*, and *Security* features. To get rules associated +with the *{stack-monitor-app}*, use the `monitoring_user` built-in role. + +For more details, refer to <>. + [[get-rule-api-params]] -==== Path parameters +=== {api-path-parms-title} `id`:: - (Required, string) The ID of the rule to retrieve. +(Required, string) The identifier of the rule to retrieve. `space_id`:: - (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. +(Optional, string) An identifier for the space. If `space_id` is not provided in +the URL, the default space is used. [[get-rule-api-codes]] -==== Response code +=== {api-response-codes-title} `200`:: - Indicates a successful call. +Indicates a successful call. [[get-rule-api-example]] -==== Example +=== {api-examples-title} Retrieve the rule object with the ID `41893910-6bca-11eb-9e0d-85d233e3ee35`: [source,sh] -------------------------------------------------- -$ curl -X GET api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35 +GET api/alerting/rule/41893910-6bca-11eb-9e0d-85d233e3ee35 -------------------------------------------------- // KIBANA @@ -69,7 +80,8 @@ The API returns the following: "scheduled_task_id": "0b092d90-6b62-11eb-9e0d-85d233e3ee35", "execution_status": { "last_execution_date": "2021-02-10T17:55:14.262Z", - "status": "ok" + "status": "ok", + "last_duration": 359 } } -------------------------------------------------- diff --git a/docs/api/alerting/health.asciidoc b/docs/api/alerting/health.asciidoc index 24955bb81fa98..1f0c8936419b5 100644 --- a/docs/api/alerting/health.asciidoc +++ b/docs/api/alerting/health.asciidoc @@ -1,38 +1,45 @@ [[get-alerting-framework-health-api]] -=== Get Alerting framework health API +== Get alerting framework health API ++++ -Get Alerting framework health +Get alerting framework health ++++ -Retrieve the health status of the Alerting framework. +Retrieve the health status of the alerting framework. [[get-alerting-framework-health-api-request]] -==== Request +=== {api-request-title} `GET :/api/alerting/_health` `GET :/s//api/alerting/_health` +=== {api-prereq-title} + +You must have `read` privileges for the *Management* > *Stack Rules* feature or +for at least one of the *Analytics* > *Discover*, *Analytics* > *{ml-app}*, +*{observability}*, or *Security* features. + [[get-alerting-framework-health-api-params]] -==== Path parameters +=== {api-path-parms-title} `space_id`:: - (Optional, string) An identifier for the space. If `space_id` is not provided in the URL, the default space is used. +(Optional, string) An identifier for the space. If `space_id` is not provided in +the URL, the default space is used. [[get-alerting-framework-health-api-codes]] -==== Response code +=== {api-response-codes-title} `200`:: - Indicates a successful call. +Indicates a successful call. [[get-alerting-framework-health-api-example]] -==== Example +=== {api-examples-title} -Retrieve the health status of the Alerting framework: +Retrieve the health status of the alerting framework: [source,sh] -------------------------------------------------- -$ curl -X GET api/alerting/_health +GET api/alerting/_health -------------------------------------------------- // KIBANA @@ -41,56 +48,46 @@ The API returns the following: [source,sh] -------------------------------------------------- { - "is_sufficiently_secure":true, - "has_permanent_encryption_key":true, - "alerting_framework_health":{ + "is_sufficiently_secure":true, <1> + "has_permanent_encryption_key":true, <2> + "alerting_framework_health":{ <3> "decryption_health":{ "status":"ok", - "timestamp":"2021-02-10T23:35:04.949Z" + "timestamp":"2022-06-21T21:46:15.023Z" + }, + "execution_health":{ + "status":"ok", + "timestamp":"2022-06-21T21:46:15.023Z" + }, + "read_health":{ + "status":"ok", + "timestamp":"2022-06-21T21:46:15.023Z" + } + }, + "alerting_framework_heath":{ <4> + "_deprecated":"This state property has a typo, use \"alerting_framework_health\" instead.","decryption_health":{ + "status":"ok", + "timestamp":"2022-06-21T21:46:15.023Z" }, "execution_health":{ "status":"ok", - "timestamp":"2021-02-10T23:35:04.949Z" + "timestamp":"2022-06-21T21:46:15.023Z" }, "read_health":{ "status":"ok", - "timestamp":"2021-02-10T23:35:04.949Z" + "timestamp":"2022-06-21T21:46:15.023Z" } } } -------------------------------------------------- - -The health API response contains the following properties: - -[cols="2*<"] -|=== - -| `is_sufficiently_secure` -| Returns `false` if security is enabled, but TLS is not. - -| `has_permanent_encryption_key` -| Return the state `false` if Encrypted Saved Object plugin has not a permanent encryption Key. - -| `alerting_framework_health` -| This state property has three substates that identify the health of the alerting framework API: `decryption_health`, `execution_health`, and `read_health`. - -| deprecated::`alerting_framework_heath` -| This state property has a typo, use `alerting_framework_health` instead. It has three substates that identify the health of the alerting framework API: `decryption_health`, `execution_health`, and `read_health`. - -|=== - -`alerting_framework_health` consists of the following properties: - -[cols="2*<"] -|=== - -| `decryption_health` -| Returns the timestamp and status of the rule decryption: `ok`, `warn` or `error` . - -| `execution_health` -| Returns the timestamp and status of the rule execution: `ok`, `warn` or `error`. - -| `read_health` -| Returns the timestamp and status of the rule reading events: `ok`, `warn` or `error`. - -|=== +<1> `is_sufficiently_secure` is `false` when security is enabled, but TLS is not. +<2> `has_permanent_encryption_key` is `false` when the encrypted saved object +plugin does not have a permanent encryption key. +<3> `alerting_framework_health` has three substates that identify the health of +the alerting framework: `decryption_health`, `execution_health`, and +`read_health`. `decryption_health` returns the timestamp and status of the rule +decryption: `ok`, `warn` or `error`. `execution_health` returns the timestamp +and status of the rule execution: `ok`, `warn` or `error`. `read_health` returns +the timestamp and status of the rule reading events: `ok`, `warn` or `error`. +<4> `alerting_framework_heath` has a typo, use `alerting_framework_health` +instead. deprecated:[8.0.0] diff --git a/docs/api/alerting/update_rule.asciidoc b/docs/api/alerting/update_rule.asciidoc index ecce62912939d..19a9c7c0144b0 100644 --- a/docs/api/alerting/update_rule.asciidoc +++ b/docs/api/alerting/update_rule.asciidoc @@ -15,9 +15,10 @@ Update the attributes for an existing rule. === {api-prereq-title} -You must have `all` privileges for the *Management* > *Stack Rules* feature or -for the *{ml-app}*, *{observability}*, or *Security* features, depending on the -`consumer` and `rule_type_id` of the rule you're updating. If the rule has +You must have `all` privileges for the appropriate {kib} features, depending on +the `consumer` and `rule_type_id` of the rule you're updating. For example, the +*Management* > *Stack Rules* feature, *Analytics* > *Discover* and *{ml-app}* +features, *{observability}*, or *Security* features. If the rule has `actions`, you must also have `read` privileges for the *Management* > *Actions and Connectors* feature. For more details, refer to <>. diff --git a/package.json b/package.json index 75ae3a7198703..717392523c956 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ }, "resolutions": { "**/@babel/runtime": "^7.17.9", - "**/@types/node": "16.11.7", + "**/@types/node": "16.11.41", "**/chokidar": "^3.4.3", "**/deepmerge": "^4.2.2", "**/fast-deep-equal": "^3.1.1", @@ -107,7 +107,7 @@ "@elastic/apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace", "@elastic/charts": "46.10.2", "@elastic/datemath": "5.0.3", - "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.2.0-canary.2", + "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.3.0-canary.1", "@elastic/ems-client": "8.3.3", "@elastic/eui": "59.0.1", "@elastic/filesaver": "1.1.2", @@ -142,6 +142,7 @@ "@kbn/analytics-shippers-fullstory": "link:bazel-bin/packages/analytics/shippers/fullstory", "@kbn/apm-config-loader": "link:bazel-bin/packages/kbn-apm-config-loader", "@kbn/apm-utils": "link:bazel-bin/packages/kbn-apm-utils", + "@kbn/ci-stats-performance-metrics": "link:bazel-bin/packages/kbn-ci-stats-performance-metrics", "@kbn/coloring": "link:bazel-bin/packages/kbn-coloring", "@kbn/config": "link:bazel-bin/packages/kbn-config", "@kbn/config-mocks": "link:bazel-bin/packages/kbn-config-mocks", @@ -149,18 +150,26 @@ "@kbn/core-analytics-browser": "link:bazel-bin/packages/core/analytics/core-analytics-browser", "@kbn/core-analytics-browser-internal": "link:bazel-bin/packages/core/analytics/core-analytics-browser-internal", "@kbn/core-analytics-browser-mocks": "link:bazel-bin/packages/core/analytics/core-analytics-browser-mocks", + "@kbn/core-analytics-server": "link:bazel-bin/packages/core/analytics/core-analytics-server", + "@kbn/core-analytics-server-internal": "link:bazel-bin/packages/core/analytics/core-analytics-server-internal", + "@kbn/core-analytics-server-mocks": "link:bazel-bin/packages/core/analytics/core-analytics-server-mocks", "@kbn/core-base-browser-internal": "link:bazel-bin/packages/core/base/core-base-browser-internal", "@kbn/core-base-browser-mocks": "link:bazel-bin/packages/core/base/core-base-browser-mocks", "@kbn/core-base-common": "link:bazel-bin/packages/core/base/core-base-common", "@kbn/core-base-common-internal": "link:bazel-bin/packages/core/base/core-base-common-internal", "@kbn/core-base-server-internal": "link:bazel-bin/packages/core/base/core-base-server-internal", "@kbn/core-base-server-mocks": "link:bazel-bin/packages/core/base/core-base-server-mocks", + "@kbn/core-config-server-internal": "link:bazel-bin/packages/core/config/core-config-server-internal", + "@kbn/core-config-server-mocks": "link:bazel-bin/packages/core/config/core-config-server-mocks", "@kbn/core-doc-links-browser": "link:bazel-bin/packages/core/doc-links/core-doc-links-browser", "@kbn/core-doc-links-browser-internal": "link:bazel-bin/packages/core/doc-links/core-doc-links-browser-internal", "@kbn/core-doc-links-browser-mocks": "link:bazel-bin/packages/core/doc-links/core-doc-links-browser-mocks", "@kbn/core-doc-links-server": "link:bazel-bin/packages/core/doc-links/core-doc-links-server", "@kbn/core-doc-links-server-internal": "link:bazel-bin/packages/core/doc-links/core-doc-links-server-internal", "@kbn/core-doc-links-server-mocks": "link:bazel-bin/packages/core/doc-links/core-doc-links-server-mocks", + "@kbn/core-i18n-browser": "link:bazel-bin/packages/core/i18n/core-i18n-browser", + "@kbn/core-i18n-browser-internal": "link:bazel-bin/packages/core/i18n/core-i18n-browser-internal", + "@kbn/core-i18n-browser-mocks": "link:bazel-bin/packages/core/i18n/core-i18n-browser-mocks", "@kbn/core-injected-metadata-browser": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser", "@kbn/core-injected-metadata-browser-internal": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser-internal", "@kbn/core-injected-metadata-browser-mocks": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser-mocks", @@ -183,10 +192,14 @@ "@kbn/i18n-react": "link:bazel-bin/packages/kbn-i18n-react", "@kbn/interpreter": "link:bazel-bin/packages/kbn-interpreter", "@kbn/io-ts-utils": "link:bazel-bin/packages/kbn-io-ts-utils", + "@kbn/kbn-ci-stats-performance-metrics": "link:bazel-bin/packages/kbn-kbn-ci-stats-performance-metrics", "@kbn/kibana-json-schema": "link:bazel-bin/packages/kbn-kibana-json-schema", "@kbn/logging": "link:bazel-bin/packages/kbn-logging", "@kbn/logging-mocks": "link:bazel-bin/packages/kbn-logging-mocks", "@kbn/mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl", + "@kbn/ml-agg-utils": "link:bazel-bin/x-pack/packages/ml/agg_utils", + "@kbn/ml-is-populated-object": "link:bazel-bin/x-pack/packages/ml/is_populated_object", + "@kbn/ml-string-hash": "link:bazel-bin/x-pack/packages/ml/string_hash", "@kbn/monaco": "link:bazel-bin/packages/kbn-monaco", "@kbn/plugin-discovery": "link:bazel-bin/packages/kbn-plugin-discovery", "@kbn/react-field": "link:bazel-bin/packages/kbn-react-field", @@ -385,6 +398,7 @@ "proxy-from-env": "1.0.0", "puid": "1.0.7", "puppeteer": "^10.2.0", + "qs": "^6.10.5", "query-string": "^6.13.2", "random-word-slugs": "^0.0.5", "raw-loader": "^3.1.0", @@ -661,6 +675,7 @@ "@types/kbn__bazel-packages": "link:bazel-bin/packages/kbn-bazel-packages/npm_module_types", "@types/kbn__bazel-runner": "link:bazel-bin/packages/kbn-bazel-runner/npm_module_types", "@types/kbn__ci-stats-core": "link:bazel-bin/packages/kbn-ci-stats-core/npm_module_types", + "@types/kbn__ci-stats-performance-metrics": "link:bazel-bin/packages/kbn-ci-stats-performance-metrics/npm_module_types", "@types/kbn__ci-stats-reporter": "link:bazel-bin/packages/kbn-ci-stats-reporter/npm_module_types", "@types/kbn__cli-dev-mode": "link:bazel-bin/packages/kbn-cli-dev-mode/npm_module_types", "@types/kbn__coloring": "link:bazel-bin/packages/kbn-coloring/npm_module_types", @@ -670,6 +685,9 @@ "@types/kbn__core-analytics-browser": "link:bazel-bin/packages/core/analytics/core-analytics-browser/npm_module_types", "@types/kbn__core-analytics-browser-internal": "link:bazel-bin/packages/core/analytics/core-analytics-browser-internal/npm_module_types", "@types/kbn__core-analytics-browser-mocks": "link:bazel-bin/packages/core/analytics/core-analytics-browser-mocks/npm_module_types", + "@types/kbn__core-analytics-server": "link:bazel-bin/packages/core/analytics/core-analytics-server/npm_module_types", + "@types/kbn__core-analytics-server-internal": "link:bazel-bin/packages/core/analytics/core-analytics-server-internal/npm_module_types", + "@types/kbn__core-analytics-server-mocks": "link:bazel-bin/packages/core/analytics/core-analytics-server-mocks/npm_module_types", "@types/kbn__core-base-browser": "link:bazel-bin/packages/core/base/core-base-browser/npm_module_types", "@types/kbn__core-base-browser-internal": "link:bazel-bin/packages/core/base/core-base-browser-internal/npm_module_types", "@types/kbn__core-base-browser-mocks": "link:bazel-bin/packages/core/base/core-base-browser-mocks/npm_module_types", @@ -679,12 +697,17 @@ "@types/kbn__core-base-server-internal": "link:bazel-bin/packages/core/base/core-base-server-internal/npm_module_types", "@types/kbn__core-base-server-mocks": "link:bazel-bin/packages/core/base/core-base-server-mocks/npm_module_types", "@types/kbn__core-common-internal-base": "link:bazel-bin/packages/core/common/internal-base/npm_module_types", + "@types/kbn__core-config-server-internal": "link:bazel-bin/packages/core/config/core-config-server-internal/npm_module_types", + "@types/kbn__core-config-server-mocks": "link:bazel-bin/packages/core/config/core-config-server-mocks/npm_module_types", "@types/kbn__core-doc-links-browser": "link:bazel-bin/packages/core/doc-links/core-doc-links-browser/npm_module_types", "@types/kbn__core-doc-links-browser-internal": "link:bazel-bin/packages/core/doc-links/core-doc-links-browser-internal/npm_module_types", "@types/kbn__core-doc-links-browser-mocks": "link:bazel-bin/packages/core/doc-links/core-doc-links-browser-mocks/npm_module_types", "@types/kbn__core-doc-links-server": "link:bazel-bin/packages/core/doc-links/core-doc-links-server/npm_module_types", "@types/kbn__core-doc-links-server-internal": "link:bazel-bin/packages/core/doc-links/core-doc-links-server-internal/npm_module_types", "@types/kbn__core-doc-links-server-mocks": "link:bazel-bin/packages/core/doc-links/core-doc-links-server-mocks/npm_module_types", + "@types/kbn__core-i18n-browser": "link:bazel-bin/packages/core/i18n/core-i18n-browser/npm_module_types", + "@types/kbn__core-i18n-browser-internal": "link:bazel-bin/packages/core/i18n/core-i18n-browser-internal/npm_module_types", + "@types/kbn__core-i18n-browser-mocks": "link:bazel-bin/packages/core/i18n/core-i18n-browser-mocks/npm_module_types", "@types/kbn__core-injected-metadata-browser": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser/npm_module_types", "@types/kbn__core-injected-metadata-browser-internal": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser-internal/npm_module_types", "@types/kbn__core-injected-metadata-browser-mocks": "link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser-mocks/npm_module_types", @@ -718,10 +741,14 @@ "@types/kbn__interpreter": "link:bazel-bin/packages/kbn-interpreter/npm_module_types", "@types/kbn__io-ts-utils": "link:bazel-bin/packages/kbn-io-ts-utils/npm_module_types", "@types/kbn__jest-serializers": "link:bazel-bin/packages/kbn-jest-serializers/npm_module_types", + "@types/kbn__kbn-ci-stats-performance-metrics": "link:bazel-bin/packages/kbn-kbn-ci-stats-performance-metrics/npm_module_types", "@types/kbn__kibana-json-schema": "link:bazel-bin/packages/kbn-kibana-json-schema/npm_module_types", "@types/kbn__logging": "link:bazel-bin/packages/kbn-logging/npm_module_types", "@types/kbn__logging-mocks": "link:bazel-bin/packages/kbn-logging-mocks/npm_module_types", "@types/kbn__mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl/npm_module_types", + "@types/kbn__ml-agg-utils": "link:bazel-bin/x-pack/packages/ml/agg_utils/npm_module_types", + "@types/kbn__ml-is-populated-object": "link:bazel-bin/x-pack/packages/ml/is_populated_object/npm_module_types", + "@types/kbn__ml-string-hash": "link:bazel-bin/x-pack/packages/ml/string_hash/npm_module_types", "@types/kbn__monaco": "link:bazel-bin/packages/kbn-monaco/npm_module_types", "@types/kbn__optimizer": "link:bazel-bin/packages/kbn-optimizer/npm_module_types", "@types/kbn__optimizer-webpack-helpers": "link:bazel-bin/packages/kbn-optimizer-webpack-helpers/npm_module_types", @@ -794,7 +821,7 @@ "@types/mustache": "^0.8.31", "@types/ncp": "^2.0.1", "@types/nock": "^10.0.3", - "@types/node": "16.11.7", + "@types/node": "16.11.41", "@types/node-fetch": "^2.6.0", "@types/node-forge": "^1.0.2", "@types/nodemailer": "^6.4.0", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index 6c65af1a97e91..253c5cc2b4fb3 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -17,18 +17,25 @@ filegroup( "//packages/core/analytics/core-analytics-browser-internal:build", "//packages/core/analytics/core-analytics-browser-mocks:build", "//packages/core/analytics/core-analytics-browser:build", + "//packages/core/analytics/core-analytics-server-internal:build", + "//packages/core/analytics/core-analytics-server-mocks:build", + "//packages/core/analytics/core-analytics-server:build", "//packages/core/base/core-base-browser-internal:build", "//packages/core/base/core-base-browser-mocks:build", "//packages/core/base/core-base-common-internal:build", "//packages/core/base/core-base-common:build", "//packages/core/base/core-base-server-internal:build", "//packages/core/base/core-base-server-mocks:build", + "//packages/core/config/core-config-server-internal:build", "//packages/core/doc-links/core-doc-links-browser-internal:build", "//packages/core/doc-links/core-doc-links-browser-mocks:build", "//packages/core/doc-links/core-doc-links-browser:build", "//packages/core/doc-links/core-doc-links-server-internal:build", "//packages/core/doc-links/core-doc-links-server-mocks:build", "//packages/core/doc-links/core-doc-links-server:build", + "//packages/core/i18n/core-i18n-browser-internal:build", + "//packages/core/i18n/core-i18n-browser-mocks:build", + "//packages/core/i18n/core-i18n-browser:build", "//packages/core/injected-metadata/core-injected-metadata-browser-internal:build", "//packages/core/injected-metadata/core-injected-metadata-browser-mocks:build", "//packages/core/injected-metadata/core-injected-metadata-browser:build", @@ -55,6 +62,7 @@ filegroup( "//packages/kbn-bazel-packages:build", "//packages/kbn-bazel-runner:build", "//packages/kbn-ci-stats-core:build", + "//packages/kbn-ci-stats-performance-metrics:build", "//packages/kbn-ci-stats-reporter:build", "//packages/kbn-cli-dev-mode:build", "//packages/kbn-coloring:build", @@ -151,6 +159,9 @@ filegroup( "//packages/shared-ux/page/analytics_no_data:build", "//packages/shared-ux/page/kibana_no_data:build", "//packages/shared-ux/prompt/no_data_views:build", + "//x-pack/packages/ml/agg_utils:build", + "//x-pack/packages/ml/is_populated_object:build", + "//x-pack/packages/ml/string_hash:build", ], ) @@ -166,18 +177,25 @@ filegroup( "//packages/core/analytics/core-analytics-browser-internal:build_types", "//packages/core/analytics/core-analytics-browser-mocks:build_types", "//packages/core/analytics/core-analytics-browser:build_types", + "//packages/core/analytics/core-analytics-server-internal:build_types", + "//packages/core/analytics/core-analytics-server-mocks:build_types", + "//packages/core/analytics/core-analytics-server:build_types", "//packages/core/base/core-base-browser-internal:build_types", "//packages/core/base/core-base-browser-mocks:build_types", "//packages/core/base/core-base-common-internal:build_types", "//packages/core/base/core-base-common:build_types", "//packages/core/base/core-base-server-internal:build_types", "//packages/core/base/core-base-server-mocks:build_types", + "//packages/core/config/core-config-server-internal:build_types", "//packages/core/doc-links/core-doc-links-browser-internal:build_types", "//packages/core/doc-links/core-doc-links-browser-mocks:build_types", "//packages/core/doc-links/core-doc-links-browser:build_types", "//packages/core/doc-links/core-doc-links-server-internal:build_types", "//packages/core/doc-links/core-doc-links-server-mocks:build_types", "//packages/core/doc-links/core-doc-links-server:build_types", + "//packages/core/i18n/core-i18n-browser-internal:build_types", + "//packages/core/i18n/core-i18n-browser-mocks:build_types", + "//packages/core/i18n/core-i18n-browser:build_types", "//packages/core/injected-metadata/core-injected-metadata-browser-internal:build_types", "//packages/core/injected-metadata/core-injected-metadata-browser-mocks:build_types", "//packages/core/injected-metadata/core-injected-metadata-browser:build_types", @@ -200,6 +218,7 @@ filegroup( "//packages/kbn-bazel-packages:build_types", "//packages/kbn-bazel-runner:build_types", "//packages/kbn-ci-stats-core:build_types", + "//packages/kbn-ci-stats-performance-metrics:build_types", "//packages/kbn-ci-stats-reporter:build_types", "//packages/kbn-cli-dev-mode:build_types", "//packages/kbn-coloring:build_types", @@ -285,6 +304,9 @@ filegroup( "//packages/shared-ux/page/analytics_no_data:build_types", "//packages/shared-ux/page/kibana_no_data:build_types", "//packages/shared-ux/prompt/no_data_views:build_types", + "//x-pack/packages/ml/agg_utils:build_types", + "//x-pack/packages/ml/is_populated_object:build_types", + "//x-pack/packages/ml/string_hash:build_types", ], ) diff --git a/packages/core/analytics/core-analytics-server-internal/BUILD.bazel b/packages/core/analytics/core-analytics-server-internal/BUILD.bazel new file mode 100644 index 0000000000000..f4fc5e7ae3818 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-internal/BUILD.bazel @@ -0,0 +1,101 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-analytics-server-internal" +PKG_REQUIRE_NAME = "@kbn/core-analytics-server-internal" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//rxjs", + "//packages/analytics/client", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//rxjs", + "//packages/analytics/client:npm_module_types", + "//packages/core/base/core-base-server-internal:npm_module_types", + "//packages/core/analytics/core-analytics-server:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/analytics/core-analytics-server-internal/README.md b/packages/core/analytics/core-analytics-server-internal/README.md new file mode 100644 index 0000000000000..669a7a428e0ac --- /dev/null +++ b/packages/core/analytics/core-analytics-server-internal/README.md @@ -0,0 +1,4 @@ +# @kbn/core-analytics-server-internal + +This package contains the internal types and implementation for Core's server-side analytics service. + diff --git a/packages/core/analytics/core-analytics-server-internal/jest.config.js b/packages/core/analytics/core-analytics-server-internal/jest.config.js new file mode 100644 index 0000000000000..d124015992400 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-internal/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/analytics/core-analytics-server-internal'], +}; diff --git a/packages/core/analytics/core-analytics-server-internal/package.json b/packages/core/analytics/core-analytics-server-internal/package.json new file mode 100644 index 0000000000000..12dc15e9633a4 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-internal/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/core-analytics-server-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/server/analytics/analytics_service.ts b/packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts similarity index 85% rename from src/core/server/analytics/analytics_service.ts rename to packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts index 7d091f5744800..0fa96ebe0ae51 100644 --- a/src/core/server/analytics/analytics_service.ts +++ b/packages/core/analytics/core-analytics-server-internal/src/analytics_service.ts @@ -10,28 +10,11 @@ import { of } from 'rxjs'; import type { AnalyticsClient } from '@kbn/analytics-client'; import { createAnalytics } from '@kbn/analytics-client'; import type { CoreContext } from '@kbn/core-base-server-internal'; - -/** - * Exposes the public APIs of the AnalyticsClient during the preboot phase - * {@link AnalyticsClient} - * @public - */ -export type AnalyticsServicePreboot = Omit; -/** - * Exposes the public APIs of the AnalyticsClient during the setup phase. - * {@link AnalyticsClient} - * @public - */ -export type AnalyticsServiceSetup = Omit; -/** - * Exposes the public APIs of the AnalyticsClient during the start phase - * {@link AnalyticsClient} - * @public - */ -export type AnalyticsServiceStart = Pick< - AnalyticsClient, - 'optIn' | 'reportEvent' | 'telemetryCounter$' ->; +import type { + AnalyticsServiceSetup, + AnalyticsServiceStart, + AnalyticsServicePreboot, +} from '@kbn/core-analytics-server'; export class AnalyticsService { private readonly analyticsClient: AnalyticsClient; @@ -59,6 +42,7 @@ export class AnalyticsService { telemetryCounter$: this.analyticsClient.telemetryCounter$, }; } + public setup(): AnalyticsServiceSetup { return { optIn: this.analyticsClient.optIn, @@ -70,6 +54,7 @@ export class AnalyticsService { telemetryCounter$: this.analyticsClient.telemetryCounter$, }; } + public start(): AnalyticsServiceStart { return { optIn: this.analyticsClient.optIn, diff --git a/packages/core/analytics/core-analytics-server-internal/src/index.ts b/packages/core/analytics/core-analytics-server-internal/src/index.ts new file mode 100644 index 0000000000000..23048526a8e70 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-internal/src/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { AnalyticsService } from './analytics_service'; diff --git a/packages/core/analytics/core-analytics-server-internal/tsconfig.json b/packages/core/analytics/core-analytics-server-internal/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-internal/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/core/analytics/core-analytics-server-mocks/BUILD.bazel b/packages/core/analytics/core-analytics-server-mocks/BUILD.bazel new file mode 100644 index 0000000000000..21f95820735f4 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-mocks/BUILD.bazel @@ -0,0 +1,100 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-analytics-server-mocks" +PKG_REQUIRE_NAME = "@kbn/core-analytics-server-mocks" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//rxjs", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//rxjs", + "//packages/kbn-utility-types:npm_module_types", + "//packages/core/analytics/core-analytics-server:npm_module_types", + "//packages/core/analytics/core-analytics-server-internal:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/analytics/core-analytics-server-mocks/README.md b/packages/core/analytics/core-analytics-server-mocks/README.md new file mode 100644 index 0000000000000..1b94135affb9b --- /dev/null +++ b/packages/core/analytics/core-analytics-server-mocks/README.md @@ -0,0 +1,4 @@ +# @kbn/core-analytics-server-mocks + +This package contains the mocks for Core's server-side analytics service. + diff --git a/packages/core/analytics/core-analytics-server-mocks/jest.config.js b/packages/core/analytics/core-analytics-server-mocks/jest.config.js new file mode 100644 index 0000000000000..5206ddb7da156 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-mocks/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/analytics/core-analytics-server-mocks'], +}; diff --git a/packages/core/analytics/core-analytics-server-mocks/package.json b/packages/core/analytics/core-analytics-server-mocks/package.json new file mode 100644 index 0000000000000..12b50433e7f62 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-mocks/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/core-analytics-server-mocks", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/server/analytics/analytics_service.mock.ts b/packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts similarity index 94% rename from src/core/server/analytics/analytics_service.mock.ts rename to packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts index 7a00e573f3e7b..44d3d04f25279 100644 --- a/src/core/server/analytics/analytics_service.mock.ts +++ b/packages/core/analytics/core-analytics-server-mocks/src/analytics_service.mock.ts @@ -6,14 +6,14 @@ * Side Public License, v 1. */ +import { Subject } from 'rxjs'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { - AnalyticsService, - AnalyticsServicePreboot, AnalyticsServiceSetup, AnalyticsServiceStart, -} from './analytics_service'; -import { Subject } from 'rxjs'; + AnalyticsServicePreboot, +} from '@kbn/core-analytics-server'; +import type { AnalyticsService } from '@kbn/core-analytics-server-internal'; type AnalyticsServiceContract = PublicMethodsOf; diff --git a/packages/core/analytics/core-analytics-server-mocks/src/index.ts b/packages/core/analytics/core-analytics-server-mocks/src/index.ts new file mode 100644 index 0000000000000..0cf55aeb9a349 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-mocks/src/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { analyticsServiceMock } from './analytics_service.mock'; diff --git a/packages/core/analytics/core-analytics-server-mocks/tsconfig.json b/packages/core/analytics/core-analytics-server-mocks/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/packages/core/analytics/core-analytics-server-mocks/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/core/analytics/core-analytics-server/BUILD.bazel b/packages/core/analytics/core-analytics-server/BUILD.bazel new file mode 100644 index 0000000000000..e59378e010127 --- /dev/null +++ b/packages/core/analytics/core-analytics-server/BUILD.bazel @@ -0,0 +1,96 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-analytics-server" +PKG_REQUIRE_NAME = "@kbn/core-analytics-server" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/analytics/client:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/analytics/core-analytics-server/README.md b/packages/core/analytics/core-analytics-server/README.md new file mode 100644 index 0000000000000..065d26a1d649c --- /dev/null +++ b/packages/core/analytics/core-analytics-server/README.md @@ -0,0 +1,4 @@ +# @kbn/core-analytics-server + +This package contains the public types for Core's server-side analytics service. + diff --git a/packages/core/analytics/core-analytics-server/jest.config.js b/packages/core/analytics/core-analytics-server/jest.config.js new file mode 100644 index 0000000000000..6b1d4596c8eb2 --- /dev/null +++ b/packages/core/analytics/core-analytics-server/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/analytics/core-analytics-server'], +}; diff --git a/packages/core/analytics/core-analytics-server/package.json b/packages/core/analytics/core-analytics-server/package.json new file mode 100644 index 0000000000000..f990017e75c39 --- /dev/null +++ b/packages/core/analytics/core-analytics-server/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/core-analytics-server", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/analytics/core-analytics-server/src/contracts.ts b/packages/core/analytics/core-analytics-server/src/contracts.ts new file mode 100644 index 0000000000000..1b297b197374d --- /dev/null +++ b/packages/core/analytics/core-analytics-server/src/contracts.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { AnalyticsClient } from '@kbn/analytics-client'; + +/** + * Exposes the public APIs of the AnalyticsClient during the preboot phase + * {@link AnalyticsClient} + * @public + */ +export type AnalyticsServicePreboot = Omit; + +/** + * Exposes the public APIs of the AnalyticsClient during the setup phase. + * {@link AnalyticsClient} + * @public + */ +export type AnalyticsServiceSetup = Omit; + +/** + * Exposes the public APIs of the AnalyticsClient during the start phase + * {@link AnalyticsClient} + * @public + */ +export type AnalyticsServiceStart = Pick< + AnalyticsClient, + 'optIn' | 'reportEvent' | 'telemetryCounter$' +>; diff --git a/src/core/server/analytics/index.ts b/packages/core/analytics/core-analytics-server/src/index.ts similarity index 54% rename from src/core/server/analytics/index.ts rename to packages/core/analytics/core-analytics-server/src/index.ts index 8a2f08d65bf9e..b070f744f831f 100644 --- a/src/core/server/analytics/index.ts +++ b/packages/core/analytics/core-analytics-server/src/index.ts @@ -6,24 +6,8 @@ * Side Public License, v 1. */ -export { AnalyticsService } from './analytics_service'; export type { - AnalyticsServicePreboot, AnalyticsServiceSetup, AnalyticsServiceStart, -} from './analytics_service'; - -export type { - AnalyticsClient, - Event, - EventContext, - EventType, - EventTypeOpts, - IShipper, - ShipperClassConstructor, - OptInConfig, - ContextProviderOpts, - TelemetryCounter, -} from '@kbn/analytics-client'; - -export { TelemetryCounterType } from '@kbn/analytics-client'; + AnalyticsServicePreboot, +} from './contracts'; diff --git a/packages/core/analytics/core-analytics-server/tsconfig.json b/packages/core/analytics/core-analytics-server/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/packages/core/analytics/core-analytics-server/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/src/core/server/errors.ts b/packages/core/base/core-base-server-internal/src/errors.ts similarity index 100% rename from src/core/server/errors.ts rename to packages/core/base/core-base-server-internal/src/errors.ts diff --git a/packages/core/base/core-base-server-internal/src/index.ts b/packages/core/base/core-base-server-internal/src/index.ts index 2cfa86145ce7b..ddf7a27886484 100644 --- a/packages/core/base/core-base-server-internal/src/index.ts +++ b/packages/core/base/core-base-server-internal/src/index.ts @@ -8,3 +8,4 @@ export type { CoreContext } from './core_context'; export type { CoreService, ServiceConfigDescriptor } from './services'; +export { CriticalError } from './errors'; diff --git a/packages/core/config/core-config-server-internal/BUILD.bazel b/packages/core/config/core-config-server-internal/BUILD.bazel new file mode 100644 index 0000000000000..e05a2c280a063 --- /dev/null +++ b/packages/core/config/core-config-server-internal/BUILD.bazel @@ -0,0 +1,103 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-config-server-internal" +PKG_REQUIRE_NAME = "@kbn/core-config-server-internal" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "//packages/elastic-safer-lodash-set", + "//packages/kbn-config", + "//packages/core/base/core-base-server-internal", + "//packages/kbn-config-mocks", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/elastic-safer-lodash-set:npm_module_types", + "//packages/kbn-config:npm_module_types", + "//packages/kbn-config-mocks:npm_module_types", + "//packages/core/base/core-base-server-internal:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/config/core-config-server-internal/README.md b/packages/core/config/core-config-server-internal/README.md new file mode 100644 index 0000000000000..157f5cc4727b6 --- /dev/null +++ b/packages/core/config/core-config-server-internal/README.md @@ -0,0 +1,3 @@ +# @kbn/core-config-server-internal + +This package contains the internal types and implementation for Core's server-side configuration. diff --git a/packages/core/config/core-config-server-internal/jest.config.js b/packages/core/config/core-config-server-internal/jest.config.js new file mode 100644 index 0000000000000..2ec41b98be493 --- /dev/null +++ b/packages/core/config/core-config-server-internal/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/config/core-config-server-internal'], +}; diff --git a/packages/core/config/core-config-server-internal/package.json b/packages/core/config/core-config-server-internal/package.json new file mode 100644 index 0000000000000..92cdc3fe27d1f --- /dev/null +++ b/packages/core/config/core-config-server-internal/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/core-config-server-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/server/config/deprecation/core_deprecations.test.ts b/packages/core/config/core-config-server-internal/src/deprecation/core_deprecations.test.ts similarity index 100% rename from src/core/server/config/deprecation/core_deprecations.test.ts rename to packages/core/config/core-config-server-internal/src/deprecation/core_deprecations.test.ts diff --git a/src/core/server/config/deprecation/core_deprecations.ts b/packages/core/config/core-config-server-internal/src/deprecation/core_deprecations.ts similarity index 96% rename from src/core/server/config/deprecation/core_deprecations.ts rename to packages/core/config/core-config-server-internal/src/deprecation/core_deprecations.ts index 2c30ab490db65..237ba1f5e8493 100644 --- a/src/core/server/config/deprecation/core_deprecations.ts +++ b/packages/core/config/core-config-server-internal/src/deprecation/core_deprecations.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { ConfigDeprecationProvider, ConfigDeprecation } from '@kbn/config'; +import type { ConfigDeprecationProvider, ConfigDeprecation } from '@kbn/config'; const rewriteBasePathDeprecation: ConfigDeprecation = (settings, fromPath, addDeprecation) => { if (settings.server?.basePath && !settings.server?.rewriteBasePath) { diff --git a/src/core/server/config/deprecation/index.ts b/packages/core/config/core-config-server-internal/src/deprecation/index.ts similarity index 100% rename from src/core/server/config/deprecation/index.ts rename to packages/core/config/core-config-server-internal/src/deprecation/index.ts diff --git a/src/core/server/config/ensure_valid_configuration.test.ts b/packages/core/config/core-config-server-internal/src/ensure_valid_configuration.test.ts similarity index 98% rename from src/core/server/config/ensure_valid_configuration.test.ts rename to packages/core/config/core-config-server-internal/src/ensure_valid_configuration.test.ts index 9161ffefaf5d3..c2ed9523c5050 100644 --- a/src/core/server/config/ensure_valid_configuration.test.ts +++ b/packages/core/config/core-config-server-internal/src/ensure_valid_configuration.test.ts @@ -8,7 +8,7 @@ import { configServiceMock } from '@kbn/config-mocks'; import { ensureValidConfiguration } from './ensure_valid_configuration'; -import { CriticalError } from '../errors'; +import { CriticalError } from '@kbn/core-base-server-internal'; describe('ensureValidConfiguration', () => { let configService: ReturnType; diff --git a/src/core/server/config/ensure_valid_configuration.ts b/packages/core/config/core-config-server-internal/src/ensure_valid_configuration.ts similarity index 95% rename from src/core/server/config/ensure_valid_configuration.ts rename to packages/core/config/core-config-server-internal/src/ensure_valid_configuration.ts index 040cb23e07988..ddf4573b8de22 100644 --- a/src/core/server/config/ensure_valid_configuration.ts +++ b/packages/core/config/core-config-server-internal/src/ensure_valid_configuration.ts @@ -7,7 +7,7 @@ */ import { ConfigService, ConfigValidateParameters } from '@kbn/config'; -import { CriticalError } from '../errors'; +import { CriticalError } from '@kbn/core-base-server-internal'; const ignoredPaths = ['dev.', 'elastic.apm.']; diff --git a/src/core/server/config/index.ts b/packages/core/config/core-config-server-internal/src/index.ts similarity index 85% rename from src/core/server/config/index.ts rename to packages/core/config/core-config-server-internal/src/index.ts index a873c593660af..cefac583eb249 100644 --- a/src/core/server/config/index.ts +++ b/packages/core/config/core-config-server-internal/src/index.ts @@ -8,3 +8,4 @@ export { coreDeprecationProvider } from './deprecation'; export { ensureValidConfiguration } from './ensure_valid_configuration'; +export { getDeprecationsFor, getDeprecationsForGlobalSettings } from './test_utils'; diff --git a/src/core/server/config/test_utils.ts b/packages/core/config/core-config-server-internal/src/test_utils.ts similarity index 100% rename from src/core/server/config/test_utils.ts rename to packages/core/config/core-config-server-internal/src/test_utils.ts diff --git a/packages/core/config/core-config-server-internal/tsconfig.json b/packages/core/config/core-config-server-internal/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/packages/core/config/core-config-server-internal/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/core/i18n/core-i18n-browser-internal/BUILD.bazel b/packages/core/i18n/core-i18n-browser-internal/BUILD.bazel new file mode 100644 index 0000000000000..edc404266491b --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-internal/BUILD.bazel @@ -0,0 +1,110 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-i18n-browser-internal" +PKG_REQUIRE_NAME = "@kbn/core-i18n-browser-internal" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + "src/**/*.tsx", + ], + exclude = [ + "**/__snapshots__/**/*", + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + '//packages/kbn-i18n-react' +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//@types/react", + "//packages/kbn-i18n:npm_module_types", + "//packages/kbn-i18n-react:npm_module_types", + "//packages/core/injected-metadata/core-injected-metadata-browser-internal:npm_module_types", + "//packages/core/i18n/core-i18n-browser:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/i18n/core-i18n-browser-internal/README.md b/packages/core/i18n/core-i18n-browser-internal/README.md new file mode 100644 index 0000000000000..a222a9317cdbb --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-internal/README.md @@ -0,0 +1,3 @@ +# @kbn/core-i18n-browser-internal + +This package contains the internal types and implementation for the i18n service. \ No newline at end of file diff --git a/packages/core/i18n/core-i18n-browser-internal/jest.config.js b/packages/core/i18n/core-i18n-browser-internal/jest.config.js new file mode 100644 index 0000000000000..573f9f6c6c598 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-internal/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/i18n/core-i18n-browser-internal'], +}; diff --git a/packages/core/i18n/core-i18n-browser-internal/package.json b/packages/core/i18n/core-i18n-browser-internal/package.json new file mode 100644 index 0000000000000..ceb27969df9c5 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-internal/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-i18n-browser-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/public/i18n/__snapshots__/i18n_service.test.tsx.snap b/packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap similarity index 100% rename from src/core/public/i18n/__snapshots__/i18n_service.test.tsx.snap rename to packages/core/i18n/core-i18n-browser-internal/src/__snapshots__/i18n_service.test.tsx.snap diff --git a/src/core/public/i18n/i18n_eui_mapping.test.ts b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.test.ts similarity index 97% rename from src/core/public/i18n/i18n_eui_mapping.test.ts rename to packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.test.ts index a2d35b37ac569..2520e06b20242 100644 --- a/src/core/public/i18n/i18n_eui_mapping.test.ts +++ b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.test.ts @@ -15,6 +15,10 @@ import { getEuiContextMapping } from './i18n_eui_mapping'; /** Regexp to find {values} usage */ const VALUES_REGEXP = /\{\w+\}/; +type I18nTranslateCall = [ + string, + { defaultMessage: string; values?: object; description?: string } +]; describe('@elastic/eui i18n tokens', () => { const i18nTranslateActual = jest.requireActual('@kbn/i18n').i18n.translate; @@ -47,11 +51,7 @@ describe('@elastic/eui i18n tokens', () => { i18ntokens.forEach(({ token, defString }) => { describe(`Token "${token}"`, () => { - let i18nTranslateCall: [ - string, - { defaultMessage: string; values?: object; description?: string } - ]; - + let i18nTranslateCall: I18nTranslateCall; beforeAll(() => { // If it's a function, call it, so we have the mock to register the call. const entry = euiContextMapping[token as keyof typeof euiContextMapping]; diff --git a/src/core/public/i18n/i18n_eui_mapping.tsx b/packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx similarity index 100% rename from src/core/public/i18n/i18n_eui_mapping.tsx rename to packages/core/i18n/core-i18n-browser-internal/src/i18n_eui_mapping.tsx diff --git a/src/core/public/i18n/i18n_service.test.tsx b/packages/core/i18n/core-i18n-browser-internal/src/i18n_service.test.tsx similarity index 100% rename from src/core/public/i18n/i18n_service.test.tsx rename to packages/core/i18n/core-i18n-browser-internal/src/i18n_service.test.tsx diff --git a/src/core/public/i18n/i18n_service.tsx b/packages/core/i18n/core-i18n-browser-internal/src/i18n_service.tsx similarity index 76% rename from src/core/public/i18n/i18n_service.tsx rename to packages/core/i18n/core-i18n-browser-internal/src/i18n_service.tsx index 640dec6321184..c42662ae9cd32 100644 --- a/src/core/public/i18n/i18n_service.tsx +++ b/packages/core/i18n/core-i18n-browser-internal/src/i18n_service.tsx @@ -10,6 +10,7 @@ import React from 'react'; import { EuiContext } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n-react'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { getEuiContextMapping } from './i18n_eui_mapping'; /** @@ -50,17 +51,3 @@ export class I18nService { // nothing to do here currently } } - -/** - * I18nStart.Context is required by any localizable React component from \@kbn/i18n and \@elastic/eui packages - * and is supposed to be used as the topmost component for any i18n-compatible React tree. - * - * @public - * - */ -export interface I18nStart { - /** - * React Context provider required as the topmost component for any i18n-compatible React tree. - */ - Context: ({ children }: { children: React.ReactNode }) => JSX.Element; -} diff --git a/src/core/public/i18n/index.ts b/packages/core/i18n/core-i18n-browser-internal/src/index.ts similarity index 89% rename from src/core/public/i18n/index.ts rename to packages/core/i18n/core-i18n-browser-internal/src/index.ts index 791920dd31372..6c2bc79fe50b7 100644 --- a/src/core/public/i18n/index.ts +++ b/packages/core/i18n/core-i18n-browser-internal/src/index.ts @@ -7,4 +7,3 @@ */ export { I18nService } from './i18n_service'; -export type { I18nStart } from './i18n_service'; diff --git a/packages/core/i18n/core-i18n-browser-internal/tsconfig.json b/packages/core/i18n/core-i18n-browser-internal/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-internal/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/core/i18n/core-i18n-browser-mocks/BUILD.bazel b/packages/core/i18n/core-i18n-browser-mocks/BUILD.bazel new file mode 100644 index 0000000000000..4a3b9ec38e879 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-mocks/BUILD.bazel @@ -0,0 +1,109 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-i18n-browser-mocks" +PKG_REQUIRE_NAME = "@kbn/core-i18n-browser-mocks" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + "src/**/*.tsx", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "//packages/core/injected-metadata/core-injected-metadata-browser-mocks", + "//packages/core/i18n/core-i18n-browser-internal", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/kbn-utility-types:npm_module_types", + "//packages/core/injected-metadata/core-injected-metadata-browser-mocks:npm_module_types", + "//packages/core/i18n/core-i18n-browser:npm_module_types", + "//packages/core/i18n/core-i18n-browser-internal:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/i18n/core-i18n-browser-mocks/README.md b/packages/core/i18n/core-i18n-browser-mocks/README.md new file mode 100644 index 0000000000000..18275d785215e --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-mocks/README.md @@ -0,0 +1,3 @@ +# @kbn/core-i18n-browser-mocks + +This package contains the mocks for Core's browser-side i18n service. diff --git a/packages/core/i18n/core-i18n-browser-mocks/jest.config.js b/packages/core/i18n/core-i18n-browser-mocks/jest.config.js new file mode 100644 index 0000000000000..3e15cf7870c1a --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-mocks/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/i18n/core-i18n-browser-mocks'], +}; diff --git a/packages/core/i18n/core-i18n-browser-mocks/package.json b/packages/core/i18n/core-i18n-browser-mocks/package.json new file mode 100644 index 0000000000000..45424b4938ade --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-mocks/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-i18n-browser-mocks", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/public/i18n/i18n_service.mock.ts b/packages/core/i18n/core-i18n-browser-mocks/src/i18n_service.mock.ts similarity index 91% rename from src/core/public/i18n/i18n_service.mock.ts rename to packages/core/i18n/core-i18n-browser-mocks/src/i18n_service.mock.ts index be28a2d565cb2..ed4e4891ff1d7 100644 --- a/src/core/public/i18n/i18n_service.mock.ts +++ b/packages/core/i18n/core-i18n-browser-mocks/src/i18n_service.mock.ts @@ -8,8 +8,8 @@ import React from 'react'; import type { PublicMethodsOf } from '@kbn/utility-types'; - -import { I18nService, I18nStart } from './i18n_service'; +import { I18nService } from '@kbn/core-i18n-browser-internal'; +import type { I18nStart } from '@kbn/core-i18n-browser'; const PassThroughComponent = ({ children }: { children: React.ReactNode }) => children; diff --git a/packages/core/i18n/core-i18n-browser-mocks/src/index.ts b/packages/core/i18n/core-i18n-browser-mocks/src/index.ts new file mode 100644 index 0000000000000..2d174cdf989aa --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-mocks/src/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { i18nServiceMock } from './i18n_service.mock'; diff --git a/packages/core/i18n/core-i18n-browser-mocks/tsconfig.json b/packages/core/i18n/core-i18n-browser-mocks/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser-mocks/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/core/i18n/core-i18n-browser/BUILD.bazel b/packages/core/i18n/core-i18n-browser/BUILD.bazel new file mode 100644 index 0000000000000..6c44bae7866b0 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser/BUILD.bazel @@ -0,0 +1,105 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-i18n-browser" +PKG_REQUIRE_NAME = "@kbn/core-i18n-browser" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + "src/**/*.tsx", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//@types/react", + "//packages/kbn-i18n:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +jsts_transpiler( + name = "target_web", + srcs = SRCS, + build_pkg_name = package_name(), + web = True, +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node", ":target_web"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/i18n/core-i18n-browser/README.md b/packages/core/i18n/core-i18n-browser/README.md new file mode 100644 index 0000000000000..f7a31f0b471c3 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser/README.md @@ -0,0 +1,3 @@ +# @kbn/core-i18n-browser + +This package contains the public types for Core's browser-side i18n service. diff --git a/packages/core/i18n/core-i18n-browser/jest.config.js b/packages/core/i18n/core-i18n-browser/jest.config.js new file mode 100644 index 0000000000000..c2d008e3eec5f --- /dev/null +++ b/packages/core/i18n/core-i18n-browser/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/packages/core/i18n/core-i18n-browser'], +}; diff --git a/packages/core/i18n/core-i18n-browser/package.json b/packages/core/i18n/core-i18n-browser/package.json new file mode 100644 index 0000000000000..88382aca19615 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-i18n-browser", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "browser": "./target_web/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/i18n/core-i18n-browser/src/index.ts b/packages/core/i18n/core-i18n-browser/src/index.ts new file mode 100644 index 0000000000000..53a4a886bd5d3 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser/src/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { I18nStart } from './types'; diff --git a/packages/core/i18n/core-i18n-browser/src/types.ts b/packages/core/i18n/core-i18n-browser/src/types.ts new file mode 100644 index 0000000000000..3d469bf9d458e --- /dev/null +++ b/packages/core/i18n/core-i18n-browser/src/types.ts @@ -0,0 +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 + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +/** + * I18nStart.Context is required by any localizable React component from \@kbn/i18n and \@elastic/eui packages + * and is supposed to be used as the topmost component for any i18n-compatible React tree. + * + * @public + */ +export interface I18nStart { + /** + * React Context provider required as the topmost component for any i18n-compatible React tree. + */ + Context: ({ children }: { children: React.ReactNode }) => JSX.Element; +} diff --git a/packages/core/i18n/core-i18n-browser/tsconfig.json b/packages/core/i18n/core-i18n-browser/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/packages/core/i18n/core-i18n-browser/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/kbn-bazel-packages/src/bazel_package_dirs.ts b/packages/kbn-bazel-packages/src/bazel_package_dirs.ts index 5c0bfb5d4595b..ed295cffd7ede 100644 --- a/packages/kbn-bazel-packages/src/bazel_package_dirs.ts +++ b/packages/kbn-bazel-packages/src/bazel_package_dirs.ts @@ -27,6 +27,7 @@ export const BAZEL_PACKAGE_DIRS = [ 'packages/analytics/shippers', 'packages/analytics/shippers/elastic_v3', 'packages/core/*', + 'x-pack/packages/ml', ]; /** diff --git a/packages/kbn-ci-stats-performance-metrics/BUILD.bazel b/packages/kbn-ci-stats-performance-metrics/BUILD.bazel new file mode 100644 index 0000000000000..ff475252a3e99 --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/BUILD.bazel @@ -0,0 +1,124 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "kbn-ci-stats-performance-metrics" +PKG_REQUIRE_NAME = "@kbn/ci-stats-performance-metrics" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +# In this array place runtime dependencies, including other packages and NPM packages +# which must be available for this code to run. +# +# To reference other packages use: +# "//repo/relative/path/to/package" +# eg. "//packages/kbn-utils" +# +# To reference a NPM package use: +# "@npm//name-of-package" +# eg. "@npm//lodash" +RUNTIME_DEPS = [ + "//packages/kbn-dev-cli-errors", + "//packages/kbn-dev-cli-runner", + "//packages/kbn-test", + "//packages/kbn-tooling-log", + "//packages/kbn-ci-stats-reporter", +] + +# In this array place dependencies necessary to build the types, which will include the +# :npm_module_types target of other packages and packages from NPM, including @types/* +# packages. +# +# To reference the types for another package use: +# "//repo/relative/path/to/package:npm_module_types" +# eg. "//packages/kbn-utils:npm_module_types" +# +# References to NPM packages work the same as RUNTIME_DEPS +TYPES_DEPS = [ + "//packages/kbn-dev-cli-errors:npm_module_types", + "//packages/kbn-dev-cli-runner:npm_module_types", + "//packages/kbn-test:npm_module_types", + "//packages/kbn-tooling-log:npm_module_types", + "//packages/kbn-ci-stats-reporter:npm_module_types", + "@npm//@types/node", + "@npm//@types/jest", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-ci-stats-performance-metrics/README.md b/packages/kbn-ci-stats-performance-metrics/README.md new file mode 100644 index 0000000000000..8b1390e8dc7ab --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/README.md @@ -0,0 +1,3 @@ +# @kbn/ci-stats-performance-metrics + +Empty package generated by @kbn/generate diff --git a/packages/kbn-ci-stats-performance-metrics/jest.config.js b/packages/kbn-ci-stats-performance-metrics/jest.config.js new file mode 100644 index 0000000000000..98fc60a9a052a --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-ci-stats-performance-metrics'], +}; diff --git a/packages/kbn-ci-stats-performance-metrics/package.json b/packages/kbn-ci-stats-performance-metrics/package.json new file mode 100644 index 0000000000000..0801174ab4a02 --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/ci-stats-performance-metrics", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/kbn-ci-stats-performance-metrics/src/apm_client.ts b/packages/kbn-ci-stats-performance-metrics/src/apm_client.ts new file mode 100644 index 0000000000000..ac72b79dc5fb4 --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/src/apm_client.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; +import { ToolingLog } from '@kbn/tooling-log'; +import { getYearAgoIso } from './utils'; + +type Environment = 'ENVIRONMENT_ALL' | 'ci' | 'development'; +type LatencyAggregationType = 'avg' | 'p95' | 'p99'; +type TransactionType = 'page-load' | 'app-change' | 'user-interaction' | 'http-request'; + +interface MainStatisticsRequestOptions { + ciBuildId: string; + start?: string; + end?: string; + environment?: Environment; + transactionType?: TransactionType; + latencyAggregationType?: LatencyAggregationType; +} + +export interface TransactionGroup { + name: string; + latency: number; + throughput: number; + errorRate?: any; + impact: number; + transactionType: TransactionType; +} + +export interface MainStatisticsResponse { + transactionGroups: TransactionGroup[]; + isAggregationAccurate: boolean; + bucketSize: number; +} + +const DEFAULT_BASE_URL = + 'https://kibana-ops-e2e-perf.kb.us-central1.gcp.cloud.es.io:9243/internal/apm'; +const DEFAULT_CLIENT_TIMEOUT = 120 * 1000; + +export class ApmClient { + private readonly client: AxiosInstance; + private readonly logger: ToolingLog; + + constructor(config: AxiosRequestConfig, logger: ToolingLog) { + const { baseURL = DEFAULT_BASE_URL, timeout = DEFAULT_CLIENT_TIMEOUT, auth } = config; + + this.client = axios.create({ + auth, + baseURL, + timeout, + }); + + this.logger = logger || console; + } + + public get baseUrl(): string | undefined { + return this.client.defaults.baseURL; + } + + public async mainStatistics(queryParams: MainStatisticsRequestOptions) { + const { now, yearAgo } = getYearAgoIso(); + + const { + ciBuildId, + start = yearAgo, + end = now, + environment = 'ENVIRONMENT_ALL', + transactionType = 'page-load', + latencyAggregationType = 'avg', + } = queryParams; + + try { + const responseRaw = await this.client.get( + `services/kibana-frontend/transactions/groups/main_statistics`, + { + params: { + kuery: `labels.ciBuildId:${ciBuildId}`, + environment, + start, + end, + transactionType, + latencyAggregationType, + }, + } + ); + return responseRaw.data; + } catch (error) { + this.logger.error( + `Error fetching main statistics from APM, ci build ${ciBuildId}, error message ${error.message}` + ); + } + } +} diff --git a/packages/kbn-ci-stats-performance-metrics/src/cli.ts b/packages/kbn-ci-stats-performance-metrics/src/cli.ts new file mode 100644 index 0000000000000..49af12a48bb19 --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/src/cli.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** *********************************************************** + * + * Run `node scripts/extract_performance_testing_dataset --help` for usage information + * + *************************************************************/ + +import { run } from '@kbn/dev-cli-runner'; +import { createFlagError } from '@kbn/dev-cli-errors'; +import { reporter } from './reporter'; + +export async function runCli() { + run( + async ({ log, flags }) => { + const apmBaseUrl = flags['apm-url']; + if (apmBaseUrl && typeof apmBaseUrl !== 'string') { + throw createFlagError('--apm-url must be a string'); + } + if (!apmBaseUrl) { + throw createFlagError('--apm-url must be defined'); + } + + const apmUsername = flags['apm-username']; + if (apmUsername && typeof apmUsername !== 'string') { + throw createFlagError('--apm-username must be a string'); + } + if (!apmUsername) { + throw createFlagError('--apm-username must be defined'); + } + + const apmPassword = flags['apm-password']; + if (apmPassword && typeof apmPassword !== 'string') { + throw createFlagError('--apm-password must be a string'); + } + if (!apmPassword) { + throw createFlagError('--apm-password must be defined'); + } + + const buildId = flags.buildId; + if (buildId && typeof buildId !== 'string') { + throw createFlagError('--buildId must be a string'); + } + if (!buildId) { + throw createFlagError('--buildId must be defined'); + } + + return reporter({ + apmClient: { + auth: { + username: apmUsername, + password: apmPassword, + }, + baseURL: apmBaseUrl, + }, + param: { + ciBuildId: buildId, + }, + log, + }); + }, + { + description: `CLI to fetch performance metrics and report those to ci-stats`, + flags: { + string: ['buildId', 'apm-url', 'apm-username', 'apm-password'], + help: ` + --buildId BUILDKITE_JOB_ID or uuid generated locally, stored in APM-based document as label: 'labels.testBuildId' + --apm-url url for APM cluster + --apm-username username for Apm + --apm-password password for Apm + `, + }, + } + ); +} diff --git a/packages/kbn-ci-stats-performance-metrics/src/index.ts b/packages/kbn-ci-stats-performance-metrics/src/index.ts new file mode 100644 index 0000000000000..0da7aee1a6ef2 --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/src/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { reporter } from './reporter'; +export { runCli } from './cli'; diff --git a/packages/kbn-ci-stats-performance-metrics/src/reporter.ts b/packages/kbn-ci-stats-performance-metrics/src/reporter.ts new file mode 100644 index 0000000000000..904eff2393e96 --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/src/reporter.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog } from '@kbn/tooling-log'; +import { CiStatsReporter } from '@kbn/ci-stats-reporter'; + +import { ApmClient } from './apm_client'; + +interface ReporterOptions { + param: { + ciBuildId: string; + }; + apmClient: { + baseURL: string; + auth: { + username: string; + password: string; + }; + }; + log: ToolingLog; +} + +export async function reporter(options: ReporterOptions) { + const { + param: { ciBuildId }, + apmClient: apmClientOptions, + log, + } = options; + + const apm = new ApmClient(apmClientOptions, log); + + const performanceMainStats = await apm.mainStatistics({ ciBuildId }); + + if (performanceMainStats) { + const { transactionGroups: tg } = performanceMainStats; + + const loginStats = tg.find((e) => e.name === '/login'); + const appHomeStats = tg.find((e) => e.name === '/app/home'); + const appDashboardsStats = tg.find((e) => e.name === '/app/dashboards'); + + const ciStatsReporter = CiStatsReporter.fromEnv(log); + + const body = { + ...(loginStats && { page_load_login: loginStats.latency }), + ...(appHomeStats && { page_load_app_home: appHomeStats.latency }), + ...(appDashboardsStats && { page_load_app_dashboards: appDashboardsStats.latency }), + }; + + await ciStatsReporter.reportPerformanceMetrics(body); + } +} diff --git a/packages/kbn-ci-stats-performance-metrics/src/utils.ts b/packages/kbn-ci-stats-performance-metrics/src/utils.ts new file mode 100644 index 0000000000000..bd22c0569b247 --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/src/utils.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export function getYearAgoIso() { + const d = new Date(); + const nowIso = d.toISOString(); + d.setMonth(d.getMonth() - 12); + const yearAgoIso = d.toISOString(); + + return { + now: nowIso, + yearAgo: yearAgoIso, + }; +} diff --git a/packages/kbn-ci-stats-performance-metrics/tsconfig.json b/packages/kbn-ci-stats-performance-metrics/tsconfig.json new file mode 100644 index 0000000000000..a8cfc2cceb08b --- /dev/null +++ b/packages/kbn-ci-stats-performance-metrics/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/kbn-ci-stats-reporter/src/ci_stats_reporter.ts b/packages/kbn-ci-stats-reporter/src/ci_stats_reporter.ts index 5d3f17a76f687..7a23f20143d94 100644 --- a/packages/kbn-ci-stats-reporter/src/ci_stats_reporter.ts +++ b/packages/kbn-ci-stats-reporter/src/ci_stats_reporter.ts @@ -57,6 +57,8 @@ export interface CiStatsMetric { meta?: CiStatsMetadata; } +export type PerformanceMetrics = Record; + /** A ci-stats timing event */ export interface CiStatsTiming { /** Top-level categorization for the timing, e.g. "scripts/foo", process type, etc. */ @@ -306,6 +308,24 @@ export class CiStatsReporter { } } + async reportPerformanceMetrics(metrics: PerformanceMetrics) { + if (!this.hasBuildConfig()) { + return; + } + + const buildId = this.config?.buildId; + if (!buildId) { + throw new Error(`Performance metrics can't be reported without a buildId`); + } + + return !!(await this.req({ + auth: true, + path: `/v1/performance_metrics_report?buildId=${buildId}`, + body: { metrics }, + bodyDesc: `performance metrics: ${metrics}`, + })); + } + /** * In order to allow this code to run before @kbn/utils is built, @kbn/pm will pass * in the upstreamBranch when calling the timings() method. Outside of @kbn/pm diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 329bd18e33952..3df97ff607ad8 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -1806,6 +1806,29 @@ class CiStatsReporter { await flushBuffer(); } } + + async reportPerformanceMetrics(metrics) { + var _this$config9; + + if (!this.hasBuildConfig()) { + return; + } + + const buildId = (_this$config9 = this.config) === null || _this$config9 === void 0 ? void 0 : _this$config9.buildId; + + if (!buildId) { + throw new Error(`Performance metrics can't be reported without a buildId`); + } + + return !!(await this.req({ + auth: true, + path: `/v1/performance_metrics_report?buildId=${buildId}`, + body: { + metrics + }, + bodyDesc: `performance metrics: ${metrics}` + })); + } /** * In order to allow this code to run before @kbn/utils is built, @kbn/pm will pass * in the upstreamBranch when calling the timings() method. Outside of @kbn/pm @@ -61948,12 +61971,14 @@ const BootstrapCommand = { ms: Date.now() - start }); } - }; // Force install is set in case a flag is passed into yarn kbn bootstrap + }; // Force install is set in case a flag is passed into yarn kbn bootstrap or + // our custom logic have determined there is a chance node_modules have been manually deleted and as such bazel + // tracking mechanism is no longer valid - const forceInstall = !!options && options['force-install'] === true; // Install bazel machinery tools if needed + const forceInstall = !!options && options['force-install'] === true || (await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_8__[/* haveNodeModulesBeenManuallyDeleted */ "c"])(kibanaProjectPath)); // Install bazel machinery tools if needed - await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_8__[/* installBazelTools */ "c"])(rootPath); // Setup remote cache settings in .bazelrc.cache if needed + await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_8__[/* installBazelTools */ "d"])(rootPath); // Setup remote cache settings in .bazelrc.cache if needed await Object(_utils_bazel_setup_remote_cache__WEBPACK_IMPORTED_MODULE_9__[/* setupRemoteCache */ "a"])(rootPath); // Bootstrap process for Bazel packages // Bazel is now managing dependencies so yarn install @@ -61967,7 +61992,7 @@ const BootstrapCommand = { if (forceInstall) { await time('force install dependencies', async () => { - await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_8__[/* removeYarnIntegrityFileIfExists */ "e"])(path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(kibanaProjectPath, 'node_modules')); + await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_8__[/* removeYarnIntegrityFileIfExists */ "f"])(path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(kibanaProjectPath, 'node_modules')); await Object(_kbn_bazel_runner__WEBPACK_IMPORTED_MODULE_2__["runBazel"])({ bazelArgs: ['clean', '--expunge'], log: _utils_log__WEBPACK_IMPORTED_MODULE_3__[/* log */ "a"] @@ -62148,7 +62173,7 @@ const CleanCommand = { } // Runs Bazel soft clean - if (await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_5__[/* isBazelBinAvailable */ "d"])(kbn.getAbsolute())) { + if (await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_5__[/* isBazelBinAvailable */ "e"])(kbn.getAbsolute())) { await Object(_kbn_bazel_runner__WEBPACK_IMPORTED_MODULE_4__["runBazel"])({ bazelArgs: ['clean'], log: _utils_log__WEBPACK_IMPORTED_MODULE_7__[/* log */ "a"] @@ -62308,7 +62333,7 @@ const ResetCommand = { } // Runs Bazel hard clean and deletes Bazel Cache Folders - if (await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_5__[/* isBazelBinAvailable */ "d"])(kbn.getAbsolute())) { + if (await Object(_utils_bazel__WEBPACK_IMPORTED_MODULE_5__[/* isBazelBinAvailable */ "e"])(kbn.getAbsolute())) { // Hard cleaning bazel await Object(_kbn_bazel_runner__WEBPACK_IMPORTED_MODULE_4__["runBazel"])({ bazelArgs: ['clean', '--expunge'], @@ -62776,12 +62801,14 @@ async function getBazelRepositoryCacheFolder() { /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "b", function() { return _get_cache_folders__WEBPACK_IMPORTED_MODULE_0__["b"]; }); /* harmony import */ var _install_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/utils/bazel/install_tools.ts"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "c", function() { return _install_tools__WEBPACK_IMPORTED_MODULE_1__["a"]; }); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "d", function() { return _install_tools__WEBPACK_IMPORTED_MODULE_1__["a"]; }); + +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "e", function() { return _install_tools__WEBPACK_IMPORTED_MODULE_1__["b"]; }); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "d", function() { return _install_tools__WEBPACK_IMPORTED_MODULE_1__["b"]; }); +/* harmony import */ var _yarn__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./src/utils/bazel/yarn.ts"); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "c", function() { return _yarn__WEBPACK_IMPORTED_MODULE_2__["a"]; }); -/* harmony import */ var _yarn_integrity__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./src/utils/bazel/yarn_integrity.ts"); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "e", function() { return _yarn_integrity__WEBPACK_IMPORTED_MODULE_2__["a"]; }); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "f", function() { return _yarn__WEBPACK_IMPORTED_MODULE_2__["b"]; }); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one @@ -62984,11 +63011,12 @@ async function setupRemoteCache(repoRootPath) { /***/ }), -/***/ "./src/utils/bazel/yarn_integrity.ts": +/***/ "./src/utils/bazel/yarn.ts": /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return removeYarnIntegrityFileIfExists; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return removeYarnIntegrityFileIfExists; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return haveNodeModulesBeenManuallyDeleted; }); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("path"); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/utils/fs.ts"); @@ -63000,6 +63028,7 @@ async function setupRemoteCache(repoRootPath) { * Side Public License, v 1. */ + // yarn integrity file checker async function removeYarnIntegrityFileIfExists(nodeModulesPath) { try { @@ -63011,6 +63040,26 @@ async function removeYarnIntegrityFileIfExists(nodeModulesPath) { } } catch {// no-op } +} // yarn and bazel integration checkers + +async function areNodeModulesPresent(kbnRootPath) { + try { + return await Object(_fs__WEBPACK_IMPORTED_MODULE_1__[/* isDirectory */ "c"])(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(kbnRootPath, 'node_modules')); + } catch { + return false; + } +} + +async function haveBazelFoldersBeenCreatedBefore(kbnRootPath) { + try { + return (await Object(_fs__WEBPACK_IMPORTED_MODULE_1__[/* isDirectory */ "c"])(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(kbnRootPath, 'bazel-bin', 'packages'))) || (await Object(_fs__WEBPACK_IMPORTED_MODULE_1__[/* isDirectory */ "c"])(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(kbnRootPath, 'bazel-kibana', 'packages'))) || (await Object(_fs__WEBPACK_IMPORTED_MODULE_1__[/* isDirectory */ "c"])(Object(path__WEBPACK_IMPORTED_MODULE_0__["resolve"])(kbnRootPath, 'bazel-out', 'host'))); + } catch { + return false; + } +} + +async function haveNodeModulesBeenManuallyDeleted(kbnRootPath) { + return !(await areNodeModulesPresent(kbnRootPath)) && (await haveBazelFoldersBeenCreatedBefore(kbnRootPath)); } /***/ }), diff --git a/packages/kbn-pm/src/commands/bootstrap.ts b/packages/kbn-pm/src/commands/bootstrap.ts index 3f9275cff8e61..8ac55b3478363 100644 --- a/packages/kbn-pm/src/commands/bootstrap.ts +++ b/packages/kbn-pm/src/commands/bootstrap.ts @@ -16,7 +16,11 @@ import { linkProjectExecutables } from '../utils/link_project_executables'; import { ICommand } from '.'; import { readYarnLock } from '../utils/yarn_lock'; import { validateDependencies } from '../utils/validate_dependencies'; -import { installBazelTools, removeYarnIntegrityFileIfExists } from '../utils/bazel'; +import { + installBazelTools, + haveNodeModulesBeenManuallyDeleted, + removeYarnIntegrityFileIfExists, +} from '../utils/bazel'; import { setupRemoteCache } from '../utils/bazel/setup_remote_cache'; export const BootstrapCommand: ICommand = { @@ -46,8 +50,12 @@ export const BootstrapCommand: ICommand = { } }; - // Force install is set in case a flag is passed into yarn kbn bootstrap - const forceInstall = !!options && options['force-install'] === true; + // Force install is set in case a flag is passed into yarn kbn bootstrap or + // our custom logic have determined there is a chance node_modules have been manually deleted and as such bazel + // tracking mechanism is no longer valid + const forceInstall = + (!!options && options['force-install'] === true) || + (await haveNodeModulesBeenManuallyDeleted(kibanaProjectPath)); // Install bazel machinery tools if needed await installBazelTools(rootPath); diff --git a/packages/kbn-pm/src/utils/bazel/index.ts b/packages/kbn-pm/src/utils/bazel/index.ts index 39b3cb9c61f00..d1460d5598f55 100644 --- a/packages/kbn-pm/src/utils/bazel/index.ts +++ b/packages/kbn-pm/src/utils/bazel/index.ts @@ -8,4 +8,4 @@ export * from './get_cache_folders'; export * from './install_tools'; -export * from './yarn_integrity'; +export * from './yarn'; diff --git a/packages/kbn-pm/src/utils/bazel/yarn.ts b/packages/kbn-pm/src/utils/bazel/yarn.ts new file mode 100644 index 0000000000000..24e44be3b3cdf --- /dev/null +++ b/packages/kbn-pm/src/utils/bazel/yarn.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { join, resolve } from 'path'; +import { isDirectory, isFile, tryRealpath, unlink } from '../fs'; + +// yarn integrity file checker +export async function removeYarnIntegrityFileIfExists(nodeModulesPath: string) { + try { + const nodeModulesRealPath = await tryRealpath(nodeModulesPath); + const yarnIntegrityFilePath = join(nodeModulesRealPath, '.yarn-integrity'); + + // check if the file exists and delete it in that case + if (await isFile(yarnIntegrityFilePath)) { + await unlink(yarnIntegrityFilePath); + } + } catch { + // no-op + } +} + +// yarn and bazel integration checkers +async function areNodeModulesPresent(kbnRootPath: string) { + try { + return await isDirectory(resolve(kbnRootPath, 'node_modules')); + } catch { + return false; + } +} + +async function haveBazelFoldersBeenCreatedBefore(kbnRootPath: string) { + try { + return ( + (await isDirectory(resolve(kbnRootPath, 'bazel-bin', 'packages'))) || + (await isDirectory(resolve(kbnRootPath, 'bazel-kibana', 'packages'))) || + (await isDirectory(resolve(kbnRootPath, 'bazel-out', 'host'))) + ); + } catch { + return false; + } +} + +export async function haveNodeModulesBeenManuallyDeleted(kbnRootPath: string) { + return ( + !(await areNodeModulesPresent(kbnRootPath)) && + (await haveBazelFoldersBeenCreatedBefore(kbnRootPath)) + ); +} diff --git a/packages/kbn-pm/src/utils/bazel/yarn_integrity.ts b/packages/kbn-pm/src/utils/bazel/yarn_integrity.ts deleted file mode 100644 index 1ac9bfeba1e3b..0000000000000 --- a/packages/kbn-pm/src/utils/bazel/yarn_integrity.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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { join } from 'path'; -import { isFile, tryRealpath, unlink } from '../fs'; - -export async function removeYarnIntegrityFileIfExists(nodeModulesPath: string) { - try { - const nodeModulesRealPath = await tryRealpath(nodeModulesPath); - const yarnIntegrityFilePath = join(nodeModulesRealPath, '.yarn-integrity'); - - // check if the file exists and delete it in that case - if (await isFile(yarnIntegrityFilePath)) { - await unlink(yarnIntegrityFilePath); - } - } catch { - // no-op - } -} diff --git a/packages/kbn-test/src/index.ts b/packages/kbn-test/src/index.ts index c9f0e67c558f1..ea4cfb0cd0fba 100644 --- a/packages/kbn-test/src/index.ts +++ b/packages/kbn-test/src/index.ts @@ -15,6 +15,8 @@ import { // @ts-ignore not typed yet } from './functional_tests/cli'; +export { KbnClientRequesterError } from './kbn_client/kbn_client_requester_error'; + // @internal export { runTestsCli, processRunTestsCliOptions, startServersCli, processStartServersCliOptions }; diff --git a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts index a57515474faf9..36a007c1c0d1c 100644 --- a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts +++ b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts @@ -13,6 +13,7 @@ import Qs from 'querystring'; import Axios, { AxiosResponse, ResponseType } from 'axios'; import { isAxiosRequestError, isAxiosResponseError } from '@kbn/dev-utils'; import { ToolingLog } from '@kbn/tooling-log'; +import { KbnClientRequesterError } from './kbn_client_requester_error'; const isConcliftOnGetError = (error: any) => { return ( @@ -166,7 +167,7 @@ export class KbnClientRequester { continue; } - throw new Error(`${errorMessage} -- and ran out of retries`); + throw new KbnClientRequesterError(`${errorMessage} -- and ran out of retries`, error); } } } diff --git a/packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts b/packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts new file mode 100644 index 0000000000000..d338b24cd16ad --- /dev/null +++ b/packages/kbn-test/src/kbn_client/kbn_client_requester_error.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { AxiosError } from 'axios'; + +export class KbnClientRequesterError extends Error { + axiosError?: AxiosError; + constructor(message: string, error: unknown) { + super(message); + this.name = 'KbnClientRequesterError'; + + if (error instanceof AxiosError) { + this.axiosError = error; + } + } +} diff --git a/scripts/report_performance_metrics.js b/scripts/report_performance_metrics.js new file mode 100644 index 0000000000000..8fc7e5c4b52a3 --- /dev/null +++ b/scripts/report_performance_metrics.js @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +require('../src/setup_node_env'); +require('@kbn/ci-stats-performance-metrics').runCli(); diff --git a/src/core/public/core_system.test.mocks.ts b/src/core/public/core_system.test.mocks.ts index e2b9d361abe85..25bbe39ddcc25 100644 --- a/src/core/public/core_system.test.mocks.ts +++ b/src/core/public/core_system.test.mocks.ts @@ -14,7 +14,7 @@ import { applicationServiceMock } from './application/application_service.mock'; import { chromeServiceMock } from './chrome/chrome_service.mock'; import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock'; import { httpServiceMock } from './http/http_service.mock'; -import { i18nServiceMock } from './i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { notificationServiceMock } from './notifications/notifications_service.mock'; import { overlayServiceMock } from './overlays/overlay_service.mock'; import { pluginsServiceMock } from './plugins/plugins_service.mock'; @@ -54,7 +54,7 @@ jest.doMock('./fatal_errors', () => ({ export const MockI18nService = i18nServiceMock.create(); export const I18nServiceConstructor = jest.fn().mockImplementation(() => MockI18nService); -jest.doMock('./i18n', () => ({ +jest.doMock('@kbn/core-i18n-browser-internal', () => ({ I18nService: I18nServiceConstructor, })); diff --git a/src/core/public/core_system.test.ts b/src/core/public/core_system.test.ts index 2a57364c9f93f..76f972d174ce8 100644 --- a/src/core/public/core_system.test.ts +++ b/src/core/public/core_system.test.ts @@ -70,6 +70,19 @@ const defaultCoreSystemParams = { beforeEach(() => { jest.clearAllMocks(); MockPluginsService.getOpaqueIds.mockReturnValue(new Map()); + + window.performance.mark = jest.fn(); + window.performance.clearMarks = jest.fn(); + window.performance.getEntriesByName = jest.fn().mockReturnValue([ + { + detail: 'load_started', + startTime: 456, + }, + { + detail: 'bootstrap_started', + startTime: 123, + }, + ]); }); function createCoreSystem(params = {}) { @@ -221,7 +234,9 @@ describe('#start()', () => { }); await core.setup(); - await core.start(); + + const services = await core.start(); + await services?.application.navigateToApp('home'); } it('clears the children of the rootDomElement and appends container for rendering service with #kibana-body, notifications, overlays', async () => { @@ -233,16 +248,22 @@ describe('#start()', () => { ); }); - it('reports the event Loaded Kibana', async () => { + it('reports the event Loaded Kibana and clears marks', async () => { await startCore(); expect(analyticsServiceStartMock.reportEvent).toHaveBeenCalledTimes(1); expect(analyticsServiceStartMock.reportEvent).toHaveBeenCalledWith('Loaded Kibana', { kibana_version: '1.2.3', + load_started: 456, + bootstrap_started: 123, }); + + expect(window.performance.clearMarks).toHaveBeenCalledTimes(1); }); it('reports the event Loaded Kibana (with memory)', async () => { fetchOptionalMemoryInfoMock.mockReturnValue({ + load_started: 456, + bootstrap_started: 123, memory_js_heap_size_limit: 3, memory_js_heap_size_total: 2, memory_js_heap_size_used: 1, @@ -251,6 +272,8 @@ describe('#start()', () => { await startCore(); expect(analyticsServiceStartMock.reportEvent).toHaveBeenCalledTimes(1); expect(analyticsServiceStartMock.reportEvent).toHaveBeenCalledWith('Loaded Kibana', { + load_started: 456, + bootstrap_started: 123, kibana_version: '1.2.3', memory_js_heap_size_limit: 3, memory_js_heap_size_total: 2, diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index b49849d84eccd..bdf94d953b659 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -15,13 +15,13 @@ import { } from '@kbn/core-injected-metadata-browser-internal'; import { DocLinksService } from '@kbn/core-doc-links-browser-internal'; import { ThemeService } from '@kbn/core-theme-browser-internal'; -import type { AnalyticsServiceSetup } from '@kbn/core-analytics-browser'; +import type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-analytics-browser'; import { AnalyticsService } from '@kbn/core-analytics-browser-internal'; +import { I18nService } from '@kbn/core-i18n-browser-internal'; import { CoreSetup, CoreStart } from '.'; import { ChromeService } from './chrome'; import { FatalErrorsService, FatalErrorsSetup } from './fatal_errors'; import { HttpService } from './http'; -import { I18nService } from './i18n'; import { NotificationsService } from './notifications'; import { OverlayService } from './overlays'; import { PluginsService } from './plugins'; @@ -35,6 +35,7 @@ import { CoreApp } from './core_app'; import type { InternalApplicationSetup, InternalApplicationStart } from './application/types'; import { ExecutionContextService } from './execution_context'; import { fetchOptionalMemoryInfo } from './fetch_optional_memory_info'; +import { KBN_LOAD_MARKS } from './utils'; interface Params { rootDomElement: HTMLElement; @@ -124,6 +125,30 @@ export class CoreSystem { this.plugins = new PluginsService(this.coreContext, injectedMetadata.uiPlugins); this.coreApp = new CoreApp(this.coreContext); + + performance.mark(KBN_LOAD_MARKS, { + detail: 'core_created', + }); + } + + private getLoadMarksInfo() { + if (!performance) return []; + const reportData: Record = {}; + const marks = performance.getEntriesByName(KBN_LOAD_MARKS); + for (const mark of marks) { + reportData[(mark as PerformanceMark).detail] = mark.startTime; + } + + return reportData; + } + + private reportKibanaLoadedEvent(analytics: AnalyticsServiceStart) { + analytics.reportEvent('Loaded Kibana', { + kibana_version: this.coreContext.env.packageInfo.version, + ...fetchOptionalMemoryInfo(), + ...this.getLoadMarksInfo(), + }); + performance.clearMarks(KBN_LOAD_MARKS); } public async setup() { @@ -171,6 +196,10 @@ export class CoreSystem { // Services that do not expose contracts at setup await this.plugins.setup(core); + performance.mark(KBN_LOAD_MARKS, { + detail: 'setup_done', + }); + return { fatalErrors: this.fatalErrorsSetup }; } catch (error) { if (this.fatalErrorsSetup) { @@ -267,9 +296,19 @@ export class CoreSystem { targetDomElement: coreUiTargetDomElement, }); - analytics.reportEvent('Loaded Kibana', { - kibana_version: this.coreContext.env.packageInfo.version, - ...fetchOptionalMemoryInfo(), + performance.mark(KBN_LOAD_MARKS, { + detail: 'start_done', + }); + + // Wait for the first app navigation to report Kibana Loaded + const appSub = application.currentAppId$.subscribe((appId) => { + if (appId === undefined) return; + + performance.mark(KBN_LOAD_MARKS, { + detail: 'first_app_nav', + }); + this.reportKibanaLoadedEvent(analytics); + appSub.unsubscribe(); }); return { @@ -323,6 +362,33 @@ export class CoreSystem { type: 'long', _meta: { description: 'The used size of the heap', optional: true }, }, + load_started: { + type: 'long', + _meta: { description: 'When the render template starts loading assets', optional: true }, + }, + bootstrap_started: { + type: 'long', + _meta: { description: 'When kbnBootstrap callback is called', optional: true }, + }, + core_created: { + type: 'long', + _meta: { description: 'When core system is created', optional: true }, + }, + setup_done: { + type: 'long', + _meta: { description: 'When core system setup is complete', optional: true }, + }, + start_done: { + type: 'long', + _meta: { description: 'When core system start is complete', optional: true }, + }, + first_app_nav: { + type: 'long', + _meta: { + description: 'When the application emits the first app navigation', + optional: true, + }, + }, }, }); } diff --git a/src/core/public/fatal_errors/fatal_errors_service.tsx b/src/core/public/fatal_errors/fatal_errors_service.tsx index 048c4e4b4ba8d..952740c414163 100644 --- a/src/core/public/fatal_errors/fatal_errors_service.tsx +++ b/src/core/public/fatal_errors/fatal_errors_service.tsx @@ -13,7 +13,7 @@ import { first, tap } from 'rxjs/operators'; import type { InternalInjectedMetadataSetup } from '@kbn/core-injected-metadata-browser-internal'; import type { ThemeServiceSetup } from '@kbn/core-theme-browser'; -import { I18nStart } from '../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { CoreContextProvider } from '../utils'; import { FatalErrorsScreen } from './fatal_errors_screen'; import { FatalErrorInfo, getErrorInfo } from './get_error_info'; diff --git a/src/core/public/index.ts b/src/core/public/index.ts index b32d872c40acf..5162cdac1024d 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -33,6 +33,8 @@ import type { import { DocLinksStart } from '@kbn/core-doc-links-browser'; import type { ThemeServiceSetup, ThemeServiceStart } from '@kbn/core-theme-browser'; import type { AnalyticsServiceSetup, AnalyticsServiceStart } from '@kbn/core-analytics-browser'; +import type { I18nStart } from '@kbn/core-i18n-browser'; + import { ChromeBadge, ChromeBreadcrumb, @@ -57,7 +59,6 @@ import { } from './chrome'; import { FatalErrorsSetup, FatalErrorsStart, FatalErrorInfo } from './fatal_errors'; import { HttpSetup, HttpStart } from './http'; -import { I18nStart } from './i18n'; import { NotificationsSetup, NotificationsStart } from './notifications'; import { OverlayStart } from './overlays'; import { Plugin, PluginInitializer, PluginInitializerContext, PluginOpaqueId } from './plugins'; diff --git a/src/core/public/kbn_bootstrap.test.ts b/src/core/public/kbn_bootstrap.test.ts index 03096daf09c39..f32bb21cd041a 100644 --- a/src/core/public/kbn_bootstrap.test.ts +++ b/src/core/public/kbn_bootstrap.test.ts @@ -22,6 +22,7 @@ describe('kbn_bootstrap', () => { beforeEach(() => { jest.clearAllMocks(); + window.performance.mark = jest.fn(); }); it('does not report a fatal error if apm load fails', async () => { diff --git a/src/core/public/kbn_bootstrap.ts b/src/core/public/kbn_bootstrap.ts index 38e95188f4c06..79283daaf9a3a 100644 --- a/src/core/public/kbn_bootstrap.ts +++ b/src/core/public/kbn_bootstrap.ts @@ -9,9 +9,14 @@ import { i18n } from '@kbn/i18n'; import { CoreSystem } from './core_system'; import { ApmSystem } from './apm_system'; +import { KBN_LOAD_MARKS } from './utils'; /** @internal */ export async function __kbnBootstrap__() { + performance.mark(KBN_LOAD_MARKS, { + detail: 'bootstrap_started', + }); + const injectedMetadata = JSON.parse( document.querySelector('kbn-injected-metadata')!.getAttribute('data')! ); diff --git a/src/core/public/mocks.ts b/src/core/public/mocks.ts index 6493bd7420f11..3a1f03f5ea782 100644 --- a/src/core/public/mocks.ts +++ b/src/core/public/mocks.ts @@ -14,6 +14,7 @@ import { coreContextMock } from '@kbn/core-base-browser-mocks'; import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; // Only import types from '.' to avoid triggering default Jest mocks. +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { PluginInitializerContext, AppMountParameters } from '.'; // Import values from their individual modules instead. import { ScopedHistory } from './application'; @@ -21,7 +22,6 @@ import { applicationServiceMock } from './application/application_service.mock'; import { chromeServiceMock } from './chrome/chrome_service.mock'; import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock'; import { httpServiceMock } from './http/http_service.mock'; -import { i18nServiceMock } from './i18n/i18n_service.mock'; import { notificationServiceMock } from './notifications/notifications_service.mock'; import { overlayServiceMock } from './overlays/overlay_service.mock'; import { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; @@ -37,7 +37,7 @@ export { chromeServiceMock } from './chrome/chrome_service.mock'; export { executionContextServiceMock } from './execution_context/execution_context_service.mock'; export { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock'; export { httpServiceMock } from './http/http_service.mock'; -export { i18nServiceMock } from './i18n/i18n_service.mock'; +export { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; export { notificationServiceMock } from './notifications/notifications_service.mock'; export { overlayServiceMock } from './overlays/overlay_service.mock'; export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock'; diff --git a/src/core/public/notifications/notifications_service.ts b/src/core/public/notifications/notifications_service.ts index e09134944ff5d..859e21de5ffed 100644 --- a/src/core/public/notifications/notifications_service.ts +++ b/src/core/public/notifications/notifications_service.ts @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { Subscription } from 'rxjs'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; -import { I18nStart } from '../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { ToastsService, ToastsSetup, ToastsStart } from './toasts'; import { IUiSettingsClient } from '../ui_settings'; import { OverlayStart } from '../overlays'; diff --git a/src/core/public/notifications/toasts/error_toast.tsx b/src/core/public/notifications/toasts/error_toast.tsx index 3b0a8a14f4966..bef4833d0097d 100644 --- a/src/core/public/notifications/toasts/error_toast.tsx +++ b/src/core/public/notifications/toasts/error_toast.tsx @@ -20,8 +20,8 @@ import { } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { OverlayStart } from '../..'; -import { I18nStart } from '../../i18n'; interface ErrorToastProps { title: string; diff --git a/src/core/public/notifications/toasts/toasts_api.test.ts b/src/core/public/notifications/toasts/toasts_api.test.ts index 9130e060a37f8..d6b67bdb63f7a 100644 --- a/src/core/public/notifications/toasts/toasts_api.test.ts +++ b/src/core/public/notifications/toasts/toasts_api.test.ts @@ -11,7 +11,7 @@ import { firstValueFrom } from 'rxjs'; import { ToastsApi } from './toasts_api'; import { uiSettingsServiceMock } from '../../ui_settings/ui_settings_service.mock'; -import { i18nServiceMock } from '../../i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; async function getCurrentToasts(toasts: ToastsApi) { return await firstValueFrom(toasts.get$()); diff --git a/src/core/public/notifications/toasts/toasts_api.tsx b/src/core/public/notifications/toasts/toasts_api.tsx index 5aaea1ca90a56..ecf32d442931c 100644 --- a/src/core/public/notifications/toasts/toasts_api.tsx +++ b/src/core/public/notifications/toasts/toasts_api.tsx @@ -11,12 +11,12 @@ import React from 'react'; import * as Rx from 'rxjs'; import { omitBy, isUndefined } from 'lodash'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { ErrorToast } from './error_toast'; import { MountPoint } from '../../types'; import { mountReactNode } from '../../utils'; import { IUiSettingsClient } from '../../ui_settings'; import { OverlayStart } from '../../overlays'; -import { I18nStart } from '../../i18n'; /** * Allowed fields for {@link ToastInput}. diff --git a/src/core/public/notifications/toasts/toasts_service.tsx b/src/core/public/notifications/toasts/toasts_service.tsx index 505cbb8787ca3..045da1fc24d02 100644 --- a/src/core/public/notifications/toasts/toasts_service.tsx +++ b/src/core/public/notifications/toasts/toasts_service.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; -import { I18nStart } from '../../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { IUiSettingsClient } from '../../ui_settings'; import { GlobalToastList } from './global_toast_list'; import { ToastsApi, IToasts } from './toasts_api'; diff --git a/src/core/public/overlays/banners/banners_service.test.ts b/src/core/public/overlays/banners/banners_service.test.ts index 6ab49ce1b5f15..d3093879f8715 100644 --- a/src/core/public/overlays/banners/banners_service.test.ts +++ b/src/core/public/overlays/banners/banners_service.test.ts @@ -8,7 +8,7 @@ import { OverlayBannersService, OverlayBannersStart } from './banners_service'; import { take } from 'rxjs/operators'; -import { i18nServiceMock } from '../../i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { uiSettingsServiceMock } from '../../ui_settings/ui_settings_service.mock'; describe('OverlayBannersService', () => { diff --git a/src/core/public/overlays/banners/banners_service.tsx b/src/core/public/overlays/banners/banners_service.tsx index 540a46d373304..a5436d21ef45e 100644 --- a/src/core/public/overlays/banners/banners_service.tsx +++ b/src/core/public/overlays/banners/banners_service.tsx @@ -10,10 +10,10 @@ import React from 'react'; import { BehaviorSubject, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { PriorityMap } from './priority_map'; import { BannersList } from './banners_list'; import { IUiSettingsClient } from '../../ui_settings'; -import { I18nStart } from '../../i18n'; import { MountPoint } from '../../types'; import { UserBannerService } from './user_banner_service'; diff --git a/src/core/public/overlays/banners/user_banner_service.test.ts b/src/core/public/overlays/banners/user_banner_service.test.ts index ff46a03886d7e..52d6d00171261 100644 --- a/src/core/public/overlays/banners/user_banner_service.test.ts +++ b/src/core/public/overlays/banners/user_banner_service.test.ts @@ -9,7 +9,7 @@ import { uiSettingsServiceMock } from '../../ui_settings/ui_settings_service.mock'; import { UserBannerService } from './user_banner_service'; import { overlayBannersServiceMock } from './banners_service.mock'; -import { i18nServiceMock } from '../../i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { Subject } from 'rxjs'; describe('OverlayBannersService', () => { diff --git a/src/core/public/overlays/banners/user_banner_service.tsx b/src/core/public/overlays/banners/user_banner_service.tsx index cb6dd81d85a7b..175d43ea8ba59 100644 --- a/src/core/public/overlays/banners/user_banner_service.tsx +++ b/src/core/public/overlays/banners/user_banner_service.tsx @@ -14,7 +14,7 @@ import { Subscription } from 'rxjs'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiCallOut, EuiButton, EuiLoadingSpinner } from '@elastic/eui'; -import { I18nStart } from '../../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { IUiSettingsClient } from '../../ui_settings'; import { OverlayBannersStart } from './banners_service'; diff --git a/src/core/public/overlays/flyout/flyout_service.test.tsx b/src/core/public/overlays/flyout/flyout_service.test.tsx index b1508153a47f1..cd7e72f2883f5 100644 --- a/src/core/public/overlays/flyout/flyout_service.test.tsx +++ b/src/core/public/overlays/flyout/flyout_service.test.tsx @@ -9,7 +9,7 @@ import { mockReactDomRender, mockReactDomUnmount } from '../overlay.test.mocks'; import { mount } from 'enzyme'; -import { i18nServiceMock } from '../../i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; import { FlyoutService, OverlayFlyoutStart } from './flyout_service'; import { OverlayRef } from '../types'; diff --git a/src/core/public/overlays/flyout/flyout_service.tsx b/src/core/public/overlays/flyout/flyout_service.tsx index a7eed8a1751fd..701915113bb5a 100644 --- a/src/core/public/overlays/flyout/flyout_service.tsx +++ b/src/core/public/overlays/flyout/flyout_service.tsx @@ -13,7 +13,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subject } from 'rxjs'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; -import { I18nStart } from '../../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { MountPoint } from '../../types'; import { OverlayRef } from '../types'; import { MountWrapper, CoreContextProvider } from '../../utils'; diff --git a/src/core/public/overlays/modal/modal_service.test.tsx b/src/core/public/overlays/modal/modal_service.test.tsx index a95d61e4f46c2..bd4353c4e8982 100644 --- a/src/core/public/overlays/modal/modal_service.test.tsx +++ b/src/core/public/overlays/modal/modal_service.test.tsx @@ -10,7 +10,7 @@ import { mockReactDomRender, mockReactDomUnmount } from '../overlay.test.mocks'; import React from 'react'; import { mount } from 'enzyme'; -import { i18nServiceMock } from '../../i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; import { ModalService, OverlayModalStart } from './modal_service'; import { mountReactNode } from '../../utils'; diff --git a/src/core/public/overlays/modal/modal_service.tsx b/src/core/public/overlays/modal/modal_service.tsx index 37c6e002e5904..0195fb2b5bf1f 100644 --- a/src/core/public/overlays/modal/modal_service.tsx +++ b/src/core/public/overlays/modal/modal_service.tsx @@ -14,7 +14,7 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subject } from 'rxjs'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; -import { I18nStart } from '../../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { MountPoint } from '../../types'; import { OverlayRef } from '../types'; import { MountWrapper, CoreContextProvider } from '../../utils'; diff --git a/src/core/public/overlays/overlay_service.ts b/src/core/public/overlays/overlay_service.ts index 2a52aa323c480..35e839b0e175b 100644 --- a/src/core/public/overlays/overlay_service.ts +++ b/src/core/public/overlays/overlay_service.ts @@ -7,7 +7,7 @@ */ import type { ThemeServiceStart } from '@kbn/core-theme-browser'; -import { I18nStart } from '../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { IUiSettingsClient } from '../ui_settings'; import { OverlayBannersStart, OverlayBannersService } from './banners'; import { FlyoutService, OverlayFlyoutStart } from './flyout'; diff --git a/src/core/public/plugins/plugins_service.test.ts b/src/core/public/plugins/plugins_service.test.ts index 6e91392abde06..b3d0ab8f295a5 100644 --- a/src/core/public/plugins/plugins_service.test.ts +++ b/src/core/public/plugins/plugins_service.test.ts @@ -27,7 +27,7 @@ import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks'; import { notificationServiceMock } from '../notifications/notifications_service.mock'; import { applicationServiceMock } from '../application/application_service.mock'; -import { i18nServiceMock } from '../i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { overlayServiceMock } from '../overlays/overlay_service.mock'; import { chromeServiceMock } from '../chrome/chrome_service.mock'; import { fatalErrorsServiceMock } from '../fatal_errors/fatal_errors_service.mock'; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index ddb6522c7afa8..d0a3bc2ad19cf 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -29,6 +29,7 @@ import { EventType } from '@kbn/analytics-client'; import { EventTypeOpts } from '@kbn/analytics-client'; import { History as History_2 } from 'history'; import { Href } from 'history'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import { IconType } from '@elastic/eui'; import { InjectedMetadataParams } from '@kbn/core-injected-metadata-browser-internal'; import type { InjectedMetadataSetup } from '@kbn/core-injected-metadata-browser'; @@ -445,6 +446,8 @@ export interface CoreStart { fatalErrors: FatalErrorsStart; // (undocumented) http: HttpStart; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver + // // (undocumented) i18n: I18nStart; // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "InjectedMetadataStart" @@ -688,12 +691,7 @@ export interface HttpSetup { // @public export type HttpStart = HttpSetup; -// @public -export interface I18nStart { - Context: ({ children }: { - children: React_2.ReactNode; - }) => JSX.Element; -} +export { I18nStart } // Warning: (ae-missing-release-tag) "IAnonymousPaths" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1556,6 +1554,6 @@ export interface UserProvidedValues { // Warnings were encountered during analysis: // -// src/core/public/core_system.ts:186:21 - (ae-forgotten-export) The symbol "InternalApplicationStart" needs to be exported by the entry point index.d.ts +// src/core/public/core_system.ts:202:21 - (ae-forgotten-export) The symbol "InternalApplicationStart" needs to be exported by the entry point index.d.ts ``` diff --git a/src/core/public/rendering/rendering_service.test.tsx b/src/core/public/rendering/rendering_service.test.tsx index 3841cd98d33f7..13cfe0b29527e 100644 --- a/src/core/public/rendering/rendering_service.test.tsx +++ b/src/core/public/rendering/rendering_service.test.tsx @@ -14,7 +14,7 @@ import { applicationServiceMock } from '../application/application_service.mock' import { chromeServiceMock } from '../chrome/chrome_service.mock'; import { overlayServiceMock } from '../overlays/overlay_service.mock'; import { themeServiceMock } from '@kbn/core-theme-browser-mocks'; -import { i18nServiceMock } from '../i18n/i18n_service.mock'; +import { i18nServiceMock } from '@kbn/core-i18n-browser-mocks'; import { BehaviorSubject } from 'rxjs'; describe('RenderingService#start', () => { diff --git a/src/core/public/rendering/rendering_service.tsx b/src/core/public/rendering/rendering_service.tsx index 53165b5ff0c42..48031db64897a 100644 --- a/src/core/public/rendering/rendering_service.tsx +++ b/src/core/public/rendering/rendering_service.tsx @@ -11,10 +11,10 @@ import ReactDOM from 'react-dom'; import { pairwise, startWith } from 'rxjs/operators'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; +import type { I18nStart } from '@kbn/core-i18n-browser'; import type { InternalChromeStart } from '../chrome'; import type { InternalApplicationStart } from '../application'; import type { OverlayStart } from '../overlays'; -import type { I18nStart } from '../i18n'; import { CoreContextProvider } from '../utils'; import { AppWrapper } from './app_containers'; diff --git a/src/core/public/utils/consts.ts b/src/core/public/utils/consts.ts new file mode 100644 index 0000000000000..8372eafec8147 --- /dev/null +++ b/src/core/public/utils/consts.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/** @internal */ +export const KBN_LOAD_MARKS = 'kbnLoad'; diff --git a/src/core/public/utils/core_context_provider.tsx b/src/core/public/utils/core_context_provider.tsx index 4d13bfb3a7d48..a400f8eae9916 100644 --- a/src/core/public/utils/core_context_provider.tsx +++ b/src/core/public/utils/core_context_provider.tsx @@ -9,7 +9,7 @@ import React, { FC } from 'react'; import type { ThemeServiceStart } from '@kbn/core-theme-browser'; import { CoreThemeProvider } from '@kbn/core-theme-browser-internal'; -import type { I18nStart } from '../i18n'; +import type { I18nStart } from '@kbn/core-i18n-browser'; interface CoreContextProviderProps { theme: ThemeServiceStart; diff --git a/src/core/public/utils/index.ts b/src/core/public/utils/index.ts index d28a8dcc37501..4fb9c50f715c6 100644 --- a/src/core/public/utils/index.ts +++ b/src/core/public/utils/index.ts @@ -9,3 +9,4 @@ export { Sha256 } from './crypto'; export { MountWrapper, mountReactNode } from './mount'; export { CoreContextProvider } from './core_context_provider'; +export { KBN_LOAD_MARKS } from './consts'; diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts index fd08d12e60416..851b698dbcc75 100644 --- a/src/core/server/bootstrap.ts +++ b/src/core/server/bootstrap.ts @@ -8,8 +8,8 @@ import chalk from 'chalk'; import { CliArgs, Env, RawConfigService } from '@kbn/config'; +import { CriticalError } from '@kbn/core-base-server-internal'; import { Root } from './root'; -import { CriticalError } from './errors'; interface BootstrapArgs { configs: string[]; diff --git a/src/core/server/elasticsearch/elasticsearch_config.test.ts b/src/core/server/elasticsearch/elasticsearch_config.test.ts index 47453f1a80610..98fd88410adaf 100644 --- a/src/core/server/elasticsearch/elasticsearch_config.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_config.test.ts @@ -13,7 +13,7 @@ import { } from './elasticsearch_config.test.mocks'; import { ElasticsearchConfig, config } from './elasticsearch_config'; -import { getDeprecationsFor } from '../config/test_utils'; +import { getDeprecationsFor } from '@kbn/core-config-server-internal'; const CONFIG_PATH = 'elasticsearch'; diff --git a/src/core/server/elasticsearch/elasticsearch_service.test.ts b/src/core/server/elasticsearch/elasticsearch_service.test.ts index 4e9b981fce75e..254c1c05a243d 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.test.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.test.ts @@ -29,6 +29,7 @@ import { Env } from '@kbn/config'; import { configServiceMock, getEnvOptions } from '@kbn/config-mocks'; import type { CoreContext } from '@kbn/core-base-server-internal'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; import { httpServiceMock } from '../http/http_service.mock'; import { executionContextServiceMock } from '../execution_context/execution_context_service.mock'; import { configSchema, ElasticsearchConfig } from './elasticsearch_config'; @@ -37,7 +38,6 @@ import { elasticsearchClientMock } from './client/mocks'; import { duration } from 'moment'; import { isValidConnection as isValidConnectionMock } from './is_valid_connection'; import { pollEsNodesVersion as pollEsNodesVersionMocked } from './version_check/ensure_es_version'; -import { analyticsServiceMock } from '../analytics/analytics_service.mock'; const { pollEsNodesVersion: pollEsNodesVersionActual } = jest.requireActual( './version_check/ensure_es_version' diff --git a/src/core/server/elasticsearch/elasticsearch_service.ts b/src/core/server/elasticsearch/elasticsearch_service.ts index 90b616c0d439b..101ca5cea1bca 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.ts @@ -11,8 +11,8 @@ import { map, shareReplay, takeUntil } from 'rxjs/operators'; import type { Logger } from '@kbn/logging'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { registerAnalyticsContextProvider } from './register_analytics_context_provider'; -import { AnalyticsServiceSetup } from '../analytics'; import { ClusterClient, ElasticsearchClientConfig } from './client'; import { ElasticsearchConfig, ElasticsearchConfigType } from './elasticsearch_config'; diff --git a/src/core/server/elasticsearch/register_analytics_context_provider.test.ts b/src/core/server/elasticsearch/register_analytics_context_provider.test.ts index 4f09ea8677f44..b041586cf1903 100644 --- a/src/core/server/elasticsearch/register_analytics_context_provider.test.ts +++ b/src/core/server/elasticsearch/register_analytics_context_provider.test.ts @@ -7,8 +7,8 @@ */ import { firstValueFrom, of } from 'rxjs'; -import type { AnalyticsServiceSetup } from '../analytics'; -import { analyticsServiceMock } from '../analytics/analytics_service.mock'; +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { registerAnalyticsContextProvider } from './register_analytics_context_provider'; describe('registerAnalyticsContextProvider', () => { diff --git a/src/core/server/elasticsearch/register_analytics_context_provider.ts b/src/core/server/elasticsearch/register_analytics_context_provider.ts index cc4523c0d4eb5..9120d48fcb606 100644 --- a/src/core/server/elasticsearch/register_analytics_context_provider.ts +++ b/src/core/server/elasticsearch/register_analytics_context_provider.ts @@ -7,7 +7,7 @@ */ import type { Observable } from 'rxjs'; -import type { AnalyticsServiceSetup } from '../analytics'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import type { ClusterInfo } from './get_cluster_info'; /** diff --git a/src/core/server/environment/environment_service.test.ts b/src/core/server/environment/environment_service.test.ts index 563db4e91918f..d13f78609ed8d 100644 --- a/src/core/server/environment/environment_service.test.ts +++ b/src/core/server/environment/environment_service.test.ts @@ -9,16 +9,17 @@ import { BehaviorSubject } from 'rxjs'; import type { CoreContext } from '@kbn/core-base-server-internal'; +import type { AnalyticsServicePreboot } from '@kbn/core-analytics-server'; + import { EnvironmentService } from './environment_service'; import { resolveInstanceUuid } from './resolve_uuid'; import { createDataFolder } from './create_data_folder'; import { writePidFile } from './write_pid_file'; -import type { AnalyticsServicePreboot } from '../analytics'; import { configServiceMock } from '@kbn/config-mocks'; import { mockCoreContext } from '@kbn/core-base-server-mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; -import { analyticsServiceMock } from '../analytics/analytics_service.mock'; +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; jest.mock('./resolve_uuid', () => ({ resolveInstanceUuid: jest.fn().mockResolvedValue('SOME_UUID'), diff --git a/src/core/server/environment/environment_service.ts b/src/core/server/environment/environment_service.ts index 9fcf54c7bc1c2..17dd296a81b10 100644 --- a/src/core/server/environment/environment_service.ts +++ b/src/core/server/environment/environment_service.ts @@ -11,7 +11,7 @@ import { PathConfigType, config as pathConfigDef } from '@kbn/utils'; import type { Logger } from '@kbn/logging'; import type { IConfigService } from '@kbn/config'; import type { CoreContext } from '@kbn/core-base-server-internal'; -import type { AnalyticsServicePreboot } from '../analytics'; +import type { AnalyticsServicePreboot } from '@kbn/core-analytics-server'; import { HttpConfigType, config as httpConfigDef } from '../http'; import { PidConfigType, config as pidConfigDef } from './pid_config'; import { resolveInstanceUuid } from './resolve_uuid'; diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 252d23bb5c444..6266fbd3fd64a 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -33,6 +33,11 @@ import { Type } from '@kbn/config-schema'; import type { DocLinksServiceStart, DocLinksServiceSetup } from '@kbn/core-doc-links-server'; import type { AppenderConfigType, LoggingServiceSetup } from '@kbn/core-logging-server'; import { appendersSchema } from '@kbn/core-logging-server-internal'; +import type { + AnalyticsServiceSetup, + AnalyticsServiceStart, + AnalyticsServicePreboot, +} from '@kbn/core-analytics-server'; import { ElasticsearchServiceSetup, configSchema as elasticsearchConfigSchema, @@ -85,11 +90,6 @@ export type { }; import type { ExecutionContextSetup, ExecutionContextStart } from './execution_context'; -import type { - AnalyticsServicePreboot, - AnalyticsServiceSetup, - AnalyticsServiceStart, -} from './analytics'; export type { IExecutionContextContainer, KibanaExecutionContext } from './execution_context'; @@ -453,9 +453,6 @@ export type { export type { DocLinksServiceStart, DocLinksServiceSetup } from '@kbn/core-doc-links-server'; export type { - AnalyticsServiceSetup, - AnalyticsServicePreboot, - AnalyticsServiceStart, AnalyticsClient, Event, EventContext, @@ -466,8 +463,13 @@ export type { OptInConfig, ShipperClassConstructor, TelemetryCounter, -} from './analytics'; -export { TelemetryCounterType } from './analytics'; +} from '@kbn/analytics-client'; +export { TelemetryCounterType } from '@kbn/analytics-client'; +export type { + AnalyticsServiceSetup, + AnalyticsServicePreboot, + AnalyticsServiceStart, +} from '@kbn/core-analytics-server'; /** @public **/ export interface RequestHandlerContextBase { diff --git a/src/core/server/internal_types.ts b/src/core/server/internal_types.ts index 99e85406c9e76..934809f6f0eb6 100644 --- a/src/core/server/internal_types.ts +++ b/src/core/server/internal_types.ts @@ -11,6 +11,11 @@ import { InternalLoggingServicePreboot, InternalLoggingServiceSetup, } from '@kbn/core-logging-server-internal'; +import type { + AnalyticsServicePreboot, + AnalyticsServiceSetup, + AnalyticsServiceStart, +} from '@kbn/core-analytics-server'; import { CapabilitiesSetup, CapabilitiesStart } from './capabilities'; import { InternalContextPreboot, ContextSetup } from './context'; import { @@ -45,11 +50,6 @@ import type { InternalExecutionContextStart, } from './execution_context'; import { InternalPrebootServicePreboot } from './preboot'; -import type { - AnalyticsServicePreboot, - AnalyticsServiceSetup, - AnalyticsServiceStart, -} from './analytics'; /** @internal */ export interface InternalCorePreboot { diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index 2796e5a5742d1..a39efc69bd619 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -13,6 +13,7 @@ import { isPromise } from '@kbn/std'; import type { MockedKeys } from '@kbn/utility-types-jest'; import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks'; import { loggingSystemMock, loggingServiceMock } from '@kbn/core-logging-server-mocks'; +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; import type { PluginInitializerContext, CoreSetup, @@ -39,7 +40,6 @@ import { i18nServiceMock } from './i18n/i18n_service.mock'; import { deprecationsServiceMock } from './deprecations/deprecations_service.mock'; import { executionContextServiceMock } from './execution_context/execution_context_service.mock'; import { prebootServiceMock } from './preboot/preboot_service.mock'; -import { analyticsServiceMock } from './analytics/analytics_service.mock'; export { configServiceMock, configDeprecationsMock } from '@kbn/config-mocks'; export { loggingSystemMock } from '@kbn/core-logging-server-mocks'; @@ -64,7 +64,7 @@ export { i18nServiceMock } from './i18n/i18n_service.mock'; export { deprecationsServiceMock } from './deprecations/deprecations_service.mock'; export { executionContextServiceMock } from './execution_context/execution_context_service.mock'; export { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks'; -export { analyticsServiceMock } from './analytics/analytics_service.mock'; +export { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; export type { ElasticsearchClientMock, diff --git a/src/core/server/rendering/bootstrap/__snapshots__/render_template.test.ts.snap b/src/core/server/rendering/bootstrap/__snapshots__/render_template.test.ts.snap index 83aacda2b599a..f7e28eebd1a61 100644 --- a/src/core/server/rendering/bootstrap/__snapshots__/render_template.test.ts.snap +++ b/src/core/server/rendering/bootstrap/__snapshots__/render_template.test.ts.snap @@ -104,6 +104,10 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { }); } + performance.mark('kbnLoad', { + detail: 'load_started', + }) + load([ '/js-1','/js-2' ], function () { diff --git a/src/core/server/rendering/bootstrap/render_template.ts b/src/core/server/rendering/bootstrap/render_template.ts index 14127017b1c0f..996aacd5e3ede 100644 --- a/src/core/server/rendering/bootstrap/render_template.ts +++ b/src/core/server/rendering/bootstrap/render_template.ts @@ -120,6 +120,10 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { }); } + performance.mark('kbnLoad', { + detail: 'load_started', + }) + load([ ${jsDependencyPaths.map((path) => `'${path}'`).join(',')} ], function () { diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index d3862e494fb59..6a85c1dff4bd1 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -8,6 +8,9 @@ import { AddConfigDeprecation } from '@kbn/config'; import { AnalyticsClient } from '@kbn/analytics-client'; +import { AnalyticsServicePreboot } from '@kbn/core-analytics-server'; +import { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; +import { AnalyticsServiceStart } from '@kbn/core-analytics-server'; import apm from 'elastic-apm-node'; import { AppenderConfigType } from '@kbn/core-logging-server'; import { AwaitedProperties } from '@kbn/utility-types'; @@ -82,20 +85,11 @@ export { AddConfigDeprecation } export { AnalyticsClient } -// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver -// -// @public -export type AnalyticsServicePreboot = Omit; +export { AnalyticsServicePreboot } -// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver -// -// @public -export type AnalyticsServiceSetup = Omit; +export { AnalyticsServiceSetup } -// Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver -// -// @public -export type AnalyticsServiceStart = Pick; +export { AnalyticsServiceStart } // @public export const APP_WRAPPER_CLASS = "kbnAppWrapper"; @@ -438,6 +432,8 @@ export type CoreIncrementUsageCounter = (params: CoreIncrementCounterParams) => // @public export interface CorePreboot { + // Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver + // // (undocumented) analytics: AnalyticsServicePreboot; // (undocumented) @@ -495,6 +491,8 @@ export interface CoreServicesUsageData { // @public export interface CoreSetup { + // Warning: (ae-unresolved-link) The @link reference could not be resolved: This type of declaration is not supported yet by the resolver + // // (undocumented) analytics: AnalyticsServiceSetup; // (undocumented) @@ -537,6 +535,8 @@ export interface CoreSetup ({ })); export const mockEnsureValidConfiguration = jest.fn(); -jest.doMock('./config/ensure_valid_configuration', () => ({ +jest.doMock('@kbn/core-config-server-internal', () => ({ ensureValidConfiguration: mockEnsureValidConfiguration, })); diff --git a/src/core/server/server.ts b/src/core/server/server.ts index cf428a56844ac..7beb8ff86150b 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -17,7 +17,12 @@ import { ILoggingSystem, config as loggingConfig, } from '@kbn/core-logging-server-internal'; -import { coreDeprecationProvider, ensureValidConfiguration } from './config'; +import { + coreDeprecationProvider, + ensureValidConfiguration, +} from '@kbn/core-config-server-internal'; +import { AnalyticsService } from '@kbn/core-analytics-server-internal'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { CoreApp } from './core_app'; import { I18nService } from './i18n'; import { ElasticsearchService } from './elasticsearch'; @@ -51,7 +56,6 @@ import { config as executionContextConfig } from './execution_context'; import { PrebootCoreRouteHandlerContext } from './preboot_core_route_handler_context'; import { PrebootService } from './preboot'; import { DiscoveredPlugins } from './plugins'; -import { AnalyticsService, AnalyticsServiceSetup } from './analytics'; const coreId = Symbol('core'); const rootConfigPath = ''; diff --git a/src/core/server/status/status_service.test.ts b/src/core/server/status/status_service.test.ts index c58705ab60403..e6904464edb09 100644 --- a/src/core/server/status/status_service.test.ts +++ b/src/core/server/status/status_service.test.ts @@ -24,7 +24,7 @@ import { mockRouter, RouterMock } from '../http/router/router.mock'; import { metricsServiceMock } from '../metrics/metrics_service.mock'; import { configServiceMock } from '@kbn/config-mocks'; import { coreUsageDataServiceMock } from '../core_usage_data/core_usage_data_service.mock'; -import { analyticsServiceMock } from '../analytics/analytics_service.mock'; +import { analyticsServiceMock } from '@kbn/core-analytics-server-mocks'; import { AnalyticsServiceSetup } from '..'; expect.addSnapshotSerializer(ServiceStatusLevelSnapshotSerializer); diff --git a/src/core/server/status/status_service.ts b/src/core/server/status/status_service.ts index 65ddfc799facd..7288718ce2765 100644 --- a/src/core/server/status/status_service.ts +++ b/src/core/server/status/status_service.ts @@ -22,7 +22,7 @@ import type { RootSchema } from '@kbn/analytics-client'; import { Logger, LogMeta } from '@kbn/logging'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; import type { PluginName } from '@kbn/core-base-common'; -import { AnalyticsServiceSetup } from '../analytics'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { InternalElasticsearchServiceSetup } from '../elasticsearch'; import { InternalHttpServiceSetup } from '../http'; import { InternalSavedObjectsServiceSetup } from '../saved_objects'; diff --git a/src/core/server/test_utils.ts b/src/core/server/test_utils.ts index cf18defb0a960..4e2f8855209ff 100644 --- a/src/core/server/test_utils.ts +++ b/src/core/server/test_utils.ts @@ -9,4 +9,7 @@ export { createHttpServer } from './http/test_utils'; export { ServiceStatusLevelSnapshotSerializer } from './status/test_utils'; export { setupServer } from './saved_objects/routes/test_utils'; -export { getDeprecationsFor, getDeprecationsForGlobalSettings } from './config/test_utils'; +export { + getDeprecationsFor, + getDeprecationsForGlobalSettings, +} from '@kbn/core-config-server-internal'; diff --git a/src/plugins/data_views/README.mdx b/src/plugins/data_views/README.mdx index f4aa08da8b8ab..2d7bf08d78586 100644 --- a/src/plugins/data_views/README.mdx +++ b/src/plugins/data_views/README.mdx @@ -20,5 +20,5 @@ and field lists across the various Kibana apps. Its typically used in conjunctio **hasData:** A standardized way to check the empty state for indices and data views. - `hasESData: () => Promise; // Check to see if ES data exists` -- `hasDataView: () => Promise; // Check to see if any data view exists (primitive or user created)` -- `hasUserDataView: () => Promise; // Check to see if user created data views exists` +- `hasDataView: () => Promise; // Check to see if any data view exists (managed or user created)` +- `hasUserDataView: () => Promise; // Check to see if user created data views exists` diff --git a/src/plugins/discover/public/__fixtures__/fake_row.js b/src/plugins/discover/public/__fixtures__/fake_row.js deleted file mode 100644 index 8cba3d85a69c3..0000000000000 --- a/src/plugins/discover/public/__fixtures__/fake_row.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -const longString = Array(200).join('_'); - -export function getFakeRowVals(type, id, mapping) { - return mapping.reduce((collector, field) => { - collector[field.name] = `${field.name}_${type}_${id}_${longString}`; - return collector; - }, {}); -} - -export function getFakeRow(id, mapping) { - return { - _id: id, - _index: 'test', - _source: getFakeRowVals('original', id, mapping), - sort: [id], - }; -} diff --git a/src/plugins/discover/public/__fixtures__/real_hits.js b/src/plugins/discover/public/__fixtures__/real_hits.ts similarity index 89% rename from src/plugins/discover/public/__fixtures__/real_hits.js rename to src/plugins/discover/public/__fixtures__/real_hits.ts index 0286d036de090..96d084a977bd4 100644 --- a/src/plugins/discover/public/__fixtures__/real_hits.js +++ b/src/plugins/discover/public/__fixtures__/real_hits.ts @@ -5,7 +5,10 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import type { DataView } from '@kbn/data-views-plugin/common'; +import { cloneDeep } from 'lodash'; +import { buildDataTableRecord } from '../utils/build_data_record'; +import type { EsHitRecord } from '../types'; /* Extensions: gif: 5 @@ -23,10 +26,9 @@ All have the same index, ids are unique */ -export default [ +export const realHits: EsHitRecord[] = [ { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '61', _score: 1, _source: { @@ -36,7 +38,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '388', _score: 1, _source: { @@ -46,7 +47,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '403', _score: 1, _source: { @@ -56,7 +56,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '415', _score: 1, _source: { @@ -66,7 +65,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '460', _score: 1, _source: { @@ -77,7 +75,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '496', _score: 1, _source: { @@ -87,7 +84,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '511', _score: 1, _source: { @@ -97,7 +93,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '701', _score: 1, _source: { @@ -107,7 +102,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '838', _score: 1, _source: { @@ -118,7 +112,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '890', _score: 1, _source: { @@ -129,7 +122,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'nginx', _id: '927', _score: 1, _source: { @@ -140,7 +132,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1034', _score: 1, _source: { @@ -150,7 +141,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1142', _score: 1, _source: { @@ -161,7 +151,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1180', _score: 1, _source: { @@ -171,7 +160,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'nginx', _id: '1224', _score: 1, _source: { @@ -181,7 +169,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1243', _score: 1, _source: { @@ -191,7 +178,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1510', _score: 1, _source: { @@ -201,7 +187,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1628', _score: 1, _source: { @@ -211,7 +196,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1729', _score: 1, _source: { @@ -221,7 +205,6 @@ export default [ }, { _index: 'logstash-2014.09.09', - _type: 'apache', _id: '1945', _score: 1, _source: { @@ -230,3 +213,7 @@ export default [ }, }, ]; + +export function getDataTableRecords(dataView: DataView) { + return cloneDeep(realHits).map((hit: EsHitRecord) => buildDataTableRecord(hit, dataView)); +} diff --git a/src/plugins/discover/public/__mocks__/grid_context.ts b/src/plugins/discover/public/__mocks__/grid_context.ts index 3f760bc4a4258..7e35aaf42204c 100644 --- a/src/plugins/discover/public/__mocks__/grid_context.ts +++ b/src/plugins/discover/public/__mocks__/grid_context.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import { flattenHit } from '@kbn/data-plugin/common'; import type { DataView } from '@kbn/data-views-plugin/public'; import { indexPatternMock } from './index_pattern'; import { dataViewComplexMock } from './data_view_complex'; @@ -15,18 +14,18 @@ import { esHitsComplex } from './es_hits_complex'; import { discoverServiceMock } from './services'; import { GridContext } from '../components/discover_grid/discover_grid_context'; import { convertValueToString } from '../utils/convert_value_to_string'; -import type { ElasticSearchHit } from '../types'; +import { buildDataTableRecord } from '../utils/build_data_record'; +import { EsHitRecord } from '../types'; -const buildGridContext = (dataView: DataView, rows: ElasticSearchHit[]): GridContext => { - const rowsFlattened = rows.map((hit) => - flattenHit(hit, dataView, { includeIgnoredValues: true }) - ); +const buildGridContext = (dataView: DataView, rows: EsHitRecord[]): GridContext => { + const usedRows = rows.map((row) => { + return buildDataTableRecord(row, dataView); + }); return { expanded: undefined, setExpanded: jest.fn(), - rows, - rowsFlattened, + rows: usedRows, onFilter: jest.fn(), indexPattern: dataView, isDarkMode: false, @@ -37,8 +36,7 @@ const buildGridContext = (dataView: DataView, rows: ElasticSearchHit[]): GridCon rowIndex, columnId, services: discoverServiceMock, - rows, - rowsFlattened, + rows: usedRows, dataView, options, }), diff --git a/src/plugins/discover/public/application/context/__mocks__/use_context_app_fetch.tsx b/src/plugins/discover/public/application/context/__mocks__/use_context_app_fetch.tsx index 1499067d2332e..be424f12d93f3 100644 --- a/src/plugins/discover/public/application/context/__mocks__/use_context_app_fetch.tsx +++ b/src/plugins/discover/public/application/context/__mocks__/use_context_app_fetch.tsx @@ -6,14 +6,20 @@ * Side Public License, v 1. */ -export const mockAnchorHit = { - _id: '123', - _index: 'the-index-pattern-id', - fields: { order_date: ['2021-06-07T18:52:17.000Z'] }, - sort: [1623091937000, 2092], - isAnchor: true, - _version: 1, -}; +import { indexPatternMock } from '../../../__mocks__/index_pattern'; +import { buildDataTableRecord } from '../../../utils/build_data_record'; + +export const mockAnchorHit = buildDataTableRecord( + { + _id: '123', + _index: 'the-index-pattern-id', + fields: { order_date: ['2021-06-07T18:52:17.000Z'] }, + sort: [1623091937000, 2092], + _version: 1, + }, + indexPatternMock, + true +); export const mockPredecessorHits = [ { @@ -37,7 +43,7 @@ export const mockPredecessorHits = [ sort: ['2021-06-07T19:10:22.000Z', 2435], _version: 1, }, -]; +].map((entry) => buildDataTableRecord(entry, indexPatternMock)); export const mockSuccessorHits = [ { @@ -61,4 +67,4 @@ export const mockSuccessorHits = [ sort: ['2021-06-07T18:47:16.000Z', 2437], _version: 1, }, -]; +].map((entry) => buildDataTableRecord(entry, indexPatternMock)); diff --git a/src/plugins/discover/public/application/context/context_app.tsx b/src/plugins/discover/public/application/context/context_app.tsx index b56364781206b..47650b64ae8cf 100644 --- a/src/plugins/discover/public/application/context/context_app.tsx +++ b/src/plugins/discover/public/application/context/context_app.tsx @@ -95,7 +95,7 @@ export const ContextApp = ({ indexPattern, anchorId }: ContextAppProps) => { fetchContextRows, fetchAllRows, fetchSurroundingRows, - fetchedState.anchor._id, + fetchedState.anchor.id, ]); const { columns, onAddColumn, onRemoveColumn, onSetColumns } = useColumns({ @@ -110,7 +110,7 @@ export const ContextApp = ({ indexPattern, anchorId }: ContextAppProps) => { const rows = useMemo( () => [ ...(fetchedState.predecessors || []), - ...(fetchedState.anchor._id ? [fetchedState.anchor] : []), + ...(fetchedState.anchor.id ? [fetchedState.anchor] : []), ...(fetchedState.successors || []), ], [fetchedState.predecessors, fetchedState.anchor, fetchedState.successors] diff --git a/src/plugins/discover/public/application/context/context_app_content.test.tsx b/src/plugins/discover/public/application/context/context_app_content.test.tsx index 9751f0d38f3d0..23a475c38b940 100644 --- a/src/plugins/discover/public/application/context/context_app_content.test.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.test.tsx @@ -18,8 +18,8 @@ import { indexPatternMock } from '../../__mocks__/index_pattern'; import { DiscoverGrid } from '../../components/discover_grid/discover_grid'; import { discoverServiceMock } from '../../__mocks__/services'; import { DocTableWrapper } from '../../components/doc_table/doc_table_wrapper'; -import { EsHitRecordList } from '../types'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { buildDataTableRecord } from '../../utils/build_data_record'; describe('ContextAppContent test', () => { const mountComponent = ({ @@ -56,7 +56,7 @@ describe('ContextAppContent test', () => { anchorStatus: anchorStatus || LoadingStatus.LOADED, predecessorsStatus: LoadingStatus.LOADED, successorsStatus: LoadingStatus.LOADED, - rows: [hit] as unknown as EsHitRecordList, + rows: [buildDataTableRecord(hit, indexPatternMock)], predecessors: [], successors: [], defaultStepSize: 5, diff --git a/src/plugins/discover/public/application/context/context_app_content.tsx b/src/plugins/discover/public/application/context/context_app_content.tsx index 0c14c3bd62e34..ce9dd8af939d3 100644 --- a/src/plugins/discover/public/application/context/context_app_content.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.tsx @@ -20,10 +20,9 @@ import { AppState } from './services/context_state'; import { SurrDocType } from './services/context'; import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE } from './services/constants'; import { DocTableContext } from '../../components/doc_table/doc_table_context'; -import { EsHitRecordList } from '../types'; -import { SortPairArr } from '../../components/doc_table/utils/get_sort'; -import { ElasticSearchHit } from '../../types'; +import type { SortPairArr } from '../../components/doc_table/utils/get_sort'; import { useDiscoverServices } from '../../hooks/use_discover_services'; +import type { DataTableRecord } from '../../types'; export interface ContextAppContentProps { columns: string[]; @@ -33,9 +32,9 @@ export interface ContextAppContentProps { indexPattern: DataView; predecessorCount: number; successorCount: number; - rows: EsHitRecordList; - predecessors: EsHitRecordList; - successors: EsHitRecordList; + rows: DataTableRecord[]; + predecessors: DataTableRecord[]; + successors: DataTableRecord[]; anchorStatus: LoadingStatus; predecessorsStatus: LoadingStatus; successorsStatus: LoadingStatus; @@ -76,7 +75,7 @@ export function ContextAppContent({ }: ContextAppContentProps) { const { uiSettings: config } = useDiscoverServices(); - const [expandedDoc, setExpandedDoc] = useState(); + const [expandedDoc, setExpandedDoc] = useState(); const isAnchorLoading = anchorStatus === LoadingStatus.LOADING || anchorStatus === LoadingStatus.UNINITIALIZED; const arePredecessorsLoading = diff --git a/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.tsx b/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.tsx index a43b8b0ca4f9d..1201526da0821 100644 --- a/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.tsx +++ b/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.tsx @@ -21,8 +21,8 @@ import { } from '../services/context_query_state'; import { AppState } from '../services/context_state'; import { getFirstSortableField } from '../utils/sorting'; -import { EsHitRecord } from '../../types'; import { useDiscoverServices } from '../../../hooks/use_discover_services'; +import type { DataTableRecord } from '../../../types'; const createError = (statusKey: string, reason: FailureReason, error?: Error) => ({ [statusKey]: { value: LoadingStatus.FAILED, error, reason }, @@ -117,7 +117,7 @@ export function useContextAppFetch({ ]); const fetchSurroundingRows = useCallback( - async (type: SurrDocType, fetchedAnchor?: EsHitRecord) => { + async (type: SurrDocType, fetchedAnchor?: DataTableRecord) => { const filters = filterManager.getFilters(); const count = @@ -133,7 +133,7 @@ export function useContextAppFetch({ const rows = await fetchSurroundingDocs( type, indexPattern, - anchor as EsHitRecord, + anchor, tieBreakerField, SortDirection.desc, count, @@ -167,7 +167,7 @@ export function useContextAppFetch({ ); const fetchContextRows = useCallback( - (anchor?: EsHitRecord) => + (anchor?: DataTableRecord) => Promise.allSettled([ fetchSurroundingRows(SurrDocType.PREDECESSORS, anchor), fetchSurroundingRows(SurrDocType.SUCCESSORS, anchor), diff --git a/src/plugins/discover/public/application/context/services/_stubs.ts b/src/plugins/discover/public/application/context/services/_stubs.ts index b37c1ecf4efbf..f2375372829bc 100644 --- a/src/plugins/discover/public/application/context/services/_stubs.ts +++ b/src/plugins/discover/public/application/context/services/_stubs.ts @@ -11,7 +11,7 @@ import moment from 'moment'; import { of } from 'rxjs'; import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IKibanaSearchResponse } from '@kbn/data-plugin/common'; -import { EsHitRecordList } from '../../types'; +import { EsHitRecord } from '../../../types'; type SortHit = { [key in string]: number; // timeField name @@ -22,7 +22,7 @@ type SortHit = { /** * A stubbed search source with a `fetch` method that returns all of `_stubHits`. */ -export function createSearchSourceStub(hits: EsHitRecordList, timeField?: string) { +export function createSearchSourceStub(hits: EsHitRecord[], timeField?: string) { const requestResult = { id: 'Fjk5bndxTHJWU2FldVRVQ0tYR0VqOFEcRWtWNDhOdG5SUzJYcFhONVVZVTBJQToxMDMwOQ==', rawResponse: { diff --git a/src/plugins/discover/public/application/context/services/anchor.test.ts b/src/plugins/discover/public/application/context/services/anchor.test.ts index ab613fb71cc6d..0fff0193e4995 100644 --- a/src/plugins/discover/public/application/context/services/anchor.test.ts +++ b/src/plugins/discover/public/application/context/services/anchor.test.ts @@ -11,7 +11,6 @@ import { createSearchSourceStub } from './_stubs'; import { fetchAnchor, updateSearchSource } from './anchor'; import { indexPatternMock } from '../../../__mocks__/index_pattern'; import { savedSearchMock } from '../../../__mocks__/saved_search'; -import { EsHitRecordList } from '../../types'; describe('context app', function () { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -24,7 +23,7 @@ describe('context app', function () { describe('function fetchAnchor', function () { beforeEach(() => { - searchSourceStub = createSearchSourceStub([{ _id: 'hit1' }] as unknown as EsHitRecordList); + searchSourceStub = createSearchSourceStub([{ _id: 'hit1', _index: 'test' }]); }); it('should use the `fetch$` method of the SearchSource', function () { @@ -142,7 +141,7 @@ describe('context app', function () { }); it('should reject with an error when no hits were found', function () { - searchSourceStub = createSearchSourceStub([] as unknown as EsHitRecordList); + searchSourceStub = createSearchSourceStub([]); return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, @@ -159,15 +158,15 @@ describe('context app', function () { it('should return the first hit after adding an anchor marker', function () { searchSourceStub = createSearchSourceStub([ - { property1: 'value1' }, - { property2: 'value2' }, - ] as unknown as EsHitRecordList); + { _id: '1', _index: 't' }, + { _id: '3', _index: 't' }, + ]); return fetchAnchor('id', indexPattern, searchSourceStub, [ { '@timestamp': SortDirection.desc }, { _doc: SortDirection.desc }, ]).then((anchorDocument) => { - expect(anchorDocument).toHaveProperty('property1', 'value1'); + expect(anchorDocument).toHaveProperty('raw._id', '1'); expect(anchorDocument).toHaveProperty('isAnchor', true); }); }); @@ -175,7 +174,7 @@ describe('context app', function () { describe('useNewFields API', () => { beforeEach(() => { - searchSourceStub = createSearchSourceStub([{ _id: 'hit1' }] as unknown as EsHitRecordList); + searchSourceStub = createSearchSourceStub([{ _id: 'hit1', _index: 't' }]); }); it('should request fields if useNewFieldsApi set', function () { diff --git a/src/plugins/discover/public/application/context/services/anchor.ts b/src/plugins/discover/public/application/context/services/anchor.ts index 28d2298513aa7..77644c8af5808 100644 --- a/src/plugins/discover/public/application/context/services/anchor.ts +++ b/src/plugins/discover/public/application/context/services/anchor.ts @@ -9,7 +9,8 @@ import { lastValueFrom } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { ISearchSource, EsQuerySortValue } from '@kbn/data-plugin/public'; import { DataView } from '@kbn/data-views-plugin/public'; -import { EsHitRecord } from '../../types'; +import { DataTableRecord } from '../../../types'; +import { buildDataTableRecord } from '../../../utils/build_data_record'; export async function fetchAnchor( anchorId: string, @@ -17,7 +18,7 @@ export async function fetchAnchor( searchSource: ISearchSource, sort: EsQuerySortValue[], useNewFieldsApi: boolean = false -): Promise { +): Promise { updateSearchSource(searchSource, anchorId, sort, useNewFieldsApi, indexPattern); const { rawResponse } = await lastValueFrom(await searchSource.fetch$()); const doc = rawResponse.hits?.hits?.[0]; @@ -29,11 +30,7 @@ export async function fetchAnchor( }) ); } - - return { - ...doc, - isAnchor: true, - } as EsHitRecord; + return buildDataTableRecord(doc, indexPattern, true); } export function updateSearchSource( diff --git a/src/plugins/discover/public/application/context/services/context.predecessors.test.ts b/src/plugins/discover/public/application/context/services/context.predecessors.test.ts index d9b55303ad507..42d53dc66a878 100644 --- a/src/plugins/discover/public/application/context/services/context.predecessors.test.ts +++ b/src/plugins/discover/public/application/context/services/context.predecessors.test.ts @@ -14,7 +14,8 @@ import { Query } from '@kbn/es-query'; import { createContextSearchSourceStub } from './_stubs'; import { fetchSurroundingDocs, SurrDocType } from './context'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import { EsHitRecord, EsHitRecordList } from '../../types'; +import { DataTableRecord, EsHitRecord } from '../../../types'; +import { buildDataTableRecord, buildDataTableRecordList } from '../../../utils/build_data_record'; const MS_PER_DAY = 24 * 60 * 60 * 1000; const ANCHOR_TIMESTAMP = new Date(MS_PER_DAY).toJSON(); @@ -36,7 +37,7 @@ describe('context predecessors', function () { tieBreakerField: string, tieBreakerValue: number, size: number - ) => Promise; + ) => Promise; // eslint-disable-next-line @typescript-eslint/no-explicit-any let mockSearchSource: any; @@ -45,6 +46,9 @@ describe('context predecessors', function () { timeFieldName: '@timestamp', isTimeNanosBased: () => false, popularizeField: () => {}, + fields: { + getByName: jest.fn(), + }, } as unknown as DataView; describe('function fetchPredecessors', function () { @@ -59,17 +63,21 @@ describe('context predecessors', function () { } as unknown as DataPublicPluginStart; fetchPredecessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size = 10) => { - const anchor = { - _source: { - [indexPattern.timeFieldName!]: timeValIso, - }, - sort: [timeValNr, tieBreakerValue], - }; + const anchor = buildDataTableRecord( + { + _source: { + [indexPattern.timeFieldName!]: timeValIso, + }, + sort: [timeValNr, tieBreakerValue], + } as EsHitRecord, + indexPattern, + true + ); return fetchSurroundingDocs( SurrDocType.PREDECESSORS, indexPattern, - anchor as EsHitRecord, + anchor, tieBreakerField, SortDirection.desc, size, @@ -89,9 +97,11 @@ describe('context predecessors', function () { ]; return fetchPredecessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( - (hits: EsHitRecordList) => { + (hits) => { expect(mockSearchSource.fetch$.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(0, 3), indexPattern) + ); } ); }); @@ -106,7 +116,7 @@ describe('context predecessors', function () { ]; return fetchPredecessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 6).then( - (hits: EsHitRecordList) => { + (hits) => { const intervals: Timestamp[] = mockSearchSource.setField.args .filter(([property]: string) => property === 'query') .map(([, { query }]: [string, { query: Query }]) => @@ -121,8 +131,9 @@ describe('context predecessors', function () { // should have ended with a half-open interval expect(Object.keys(last(intervals) ?? {})).toEqual(['format', 'gte']); expect(intervals.length).toBeGreaterThan(1); - - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(0, 3), indexPattern) + ); } ); }); @@ -136,7 +147,7 @@ describe('context predecessors', function () { ]; return fetchPredecessors(ANCHOR_TIMESTAMP_1000, MS_PER_DAY * 1000, '_doc', 0, 3).then( - (hits: EsHitRecordList) => { + (hits) => { const intervals: Timestamp[] = mockSearchSource.setField.args .filter(([property]: string) => property === 'query') .map(([, { query }]: [string, { query: Query }]) => { @@ -155,17 +166,18 @@ describe('context predecessors', function () { // should have stopped before reaching MS_PER_DAY * 1700 expect(moment(last(intervals)?.lte).valueOf()).toBeLessThan(MS_PER_DAY * 1700); expect(intervals.length).toBeGreaterThan(1); - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(-3), indexPattern) + ); } ); }); it('should return an empty array when no hits were found', function () { - return fetchPredecessors(ANCHOR_TIMESTAMP_3, MS_PER_DAY * 3, '_doc', 0, 3).then( - (hits: EsHitRecordList) => { - expect(hits).toEqual([]); - } - ); + return fetchPredecessors(ANCHOR_TIMESTAMP_3, MS_PER_DAY * 3, '_doc', 0, 3).then((hits) => { + expect(hits).toEqual([]); + }); }); it('should configure the SearchSource to not inherit from the implicit root', function () { @@ -201,17 +213,21 @@ describe('context predecessors', function () { } as unknown as DataPublicPluginStart; fetchPredecessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size = 10) => { - const anchor = { - _source: { - [indexPattern.timeFieldName!]: timeValIso, - }, - sort: [timeValNr, tieBreakerValue], - }; + const anchor = buildDataTableRecord( + { + _source: { + [indexPattern.timeFieldName!]: timeValIso, + }, + sort: [timeValNr, tieBreakerValue], + } as EsHitRecord, + indexPattern, + true + ); return fetchSurroundingDocs( SurrDocType.PREDECESSORS, indexPattern, - anchor as EsHitRecord, + anchor, tieBreakerField, SortDirection.desc, size, @@ -232,13 +248,15 @@ describe('context predecessors', function () { ]; return fetchPredecessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( - (hits: EsHitRecordList) => { + (hits) => { const setFieldsSpy = mockSearchSource.setField.withArgs('fields'); const removeFieldsSpy = mockSearchSource.removeField.withArgs('fieldsFromSource'); expect(mockSearchSource.fetch$.calledOnce).toBe(true); expect(removeFieldsSpy.calledOnce).toBe(true); expect(setFieldsSpy.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 3)); + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(0, 3), indexPattern) + ); } ); }); diff --git a/src/plugins/discover/public/application/context/services/context.successors.test.ts b/src/plugins/discover/public/application/context/services/context.successors.test.ts index c9f819c6497d9..dfc57b1859cb1 100644 --- a/src/plugins/discover/public/application/context/services/context.successors.test.ts +++ b/src/plugins/discover/public/application/context/services/context.successors.test.ts @@ -14,7 +14,8 @@ import { createContextSearchSourceStub } from './_stubs'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Query } from '@kbn/es-query'; import { fetchSurroundingDocs, SurrDocType } from './context'; -import { EsHitRecord, EsHitRecordList } from '../../types'; +import { DataTableRecord } from '../../../types'; +import { buildDataTableRecord, buildDataTableRecordList } from '../../../utils/build_data_record'; const MS_PER_DAY = 24 * 60 * 60 * 1000; const ANCHOR_TIMESTAMP = new Date(MS_PER_DAY).toJSON(); @@ -34,7 +35,7 @@ describe('context successors', function () { tieBreakerField: string, tieBreakerValue: number, size: number - ) => Promise; + ) => Promise; let dataPluginMock: DataPublicPluginStart; // eslint-disable-next-line @typescript-eslint/no-explicit-any let mockSearchSource: any; @@ -43,6 +44,9 @@ describe('context successors', function () { timeFieldName: '@timestamp', isTimeNanosBased: () => false, popularizeField: () => {}, + fields: { + getByName: jest.fn(), + }, } as unknown as DataView; describe('function fetchSuccessors', function () { @@ -58,17 +62,23 @@ describe('context successors', function () { } as unknown as DataPublicPluginStart; fetchSuccessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size) => { - const anchor = { - _source: { - [indexPattern.timeFieldName!]: timeValIso, + const anchor = buildDataTableRecord( + { + _index: 't', + _id: '1', + _source: { + [indexPattern.timeFieldName!]: timeValIso, + }, + sort: [timeValNr, tieBreakerValue], }, - sort: [timeValNr, tieBreakerValue], - }; + indexPattern, + true + ); return fetchSurroundingDocs( SurrDocType.SUCCESSORS, indexPattern, - anchor as EsHitRecord, + anchor, tieBreakerField, SortDirection.desc, size, @@ -90,7 +100,9 @@ describe('context successors', function () { return fetchSuccessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( (hits) => { expect(mockSearchSource.fetch$.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(-3), indexPattern) + ); } ); }); @@ -120,8 +132,9 @@ describe('context successors', function () { // should have ended with a half-open interval expect(Object.keys(last(intervals) ?? {})).toEqual(['format', 'lte']); expect(intervals.length).toBeGreaterThan(1); - - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(-3), indexPattern) + ); } ); }); @@ -149,8 +162,9 @@ describe('context successors', function () { // should have stopped before reaching MS_PER_DAY * 2200 expect(moment(last(intervals)?.gte).valueOf()).toBeGreaterThan(MS_PER_DAY * 2200); expect(intervals.length).toBeGreaterThan(1); - - expect(hits).toEqual(mockSearchSource._stubHits.slice(0, 4)); + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(0, 4), indexPattern) + ); } ); }); @@ -194,17 +208,23 @@ describe('context successors', function () { } as unknown as DataPublicPluginStart; fetchSuccessors = (timeValIso, timeValNr, tieBreakerField, tieBreakerValue, size) => { - const anchor = { - _source: { - [indexPattern.timeFieldName!]: timeValIso, + const anchor = buildDataTableRecord( + { + _id: '1', + _index: 'test', + _source: { + [indexPattern.timeFieldName!]: timeValIso, + }, + sort: [timeValNr, tieBreakerValue], }, - sort: [timeValNr, tieBreakerValue], - }; + indexPattern, + true + ); return fetchSurroundingDocs( SurrDocType.SUCCESSORS, indexPattern, - anchor as EsHitRecord, + anchor, tieBreakerField, SortDirection.desc, size, @@ -227,7 +247,9 @@ describe('context successors', function () { return fetchSuccessors(ANCHOR_TIMESTAMP_3000, MS_PER_DAY * 3000, '_doc', 0, 3).then( (hits) => { expect(mockSearchSource.fetch$.calledOnce).toBe(true); - expect(hits).toEqual(mockSearchSource._stubHits.slice(-3)); + expect(hits).toEqual( + buildDataTableRecordList(mockSearchSource._stubHits.slice(-3), indexPattern) + ); const setFieldsSpy = mockSearchSource.setField.withArgs('fields'); const removeFieldsSpy = mockSearchSource.removeField.withArgs('fieldsFromSource'); expect(removeFieldsSpy.calledOnce).toBe(true); diff --git a/src/plugins/discover/public/application/context/services/context.ts b/src/plugins/discover/public/application/context/services/context.ts index 336ca6a21cc33..c2f2b7f765f73 100644 --- a/src/plugins/discover/public/application/context/services/context.ts +++ b/src/plugins/discover/public/application/context/services/context.ts @@ -14,7 +14,7 @@ import { fetchHitsInInterval } from '../utils/fetch_hits_in_interval'; import { generateIntervals } from '../utils/generate_intervals'; import { getEsQuerySearchAfter } from '../utils/get_es_query_search_after'; import { getEsQuerySort } from '../utils/get_es_query_sort'; -import { EsHitRecord, EsHitRecordList } from '../../types'; +import { DataTableRecord } from '../../../types'; export enum SurrDocType { SUCCESSORS = 'successors', @@ -31,7 +31,7 @@ const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000].map((days) => days * DAY_MILLIS * * @param {SurrDocType} type - `successors` or `predecessors` * @param {DataView} indexPattern - * @param {EsHitRecord} anchor - anchor record + * @param {DataTableRecord} anchor - anchor record * @param {string} tieBreakerField - name of the tie breaker, the 2nd sort field * @param {SortDirection} sortDir - direction of sorting * @param {number} size - number of records to retrieve @@ -42,14 +42,14 @@ const LOOKUP_OFFSETS = [0, 1, 7, 30, 365, 10000].map((days) => days * DAY_MILLIS export async function fetchSurroundingDocs( type: SurrDocType, indexPattern: DataView, - anchor: EsHitRecord, + anchor: DataTableRecord, tieBreakerField: string, sortDir: SortDirection, size: number, filters: Filter[], data: DataPublicPluginStart, useNewFieldsApi?: boolean -): Promise { +): Promise { if (typeof anchor !== 'object' || anchor === null || !size) { return []; } @@ -57,13 +57,16 @@ export async function fetchSurroundingDocs( const searchSource = data.search.searchSource.createEmpty(); updateSearchSource(searchSource, indexPattern, filters, Boolean(useNewFieldsApi)); const sortDirToApply = type === SurrDocType.SUCCESSORS ? sortDir : reverseSortDir(sortDir); + const anchorRaw = anchor.raw!; - const nanos = indexPattern.isTimeNanosBased() ? extractNanos(anchor.fields[timeField][0]) : ''; + const nanos = indexPattern.isTimeNanosBased() + ? extractNanos(anchorRaw.fields?.[timeField][0]) + : ''; const timeValueMillis = - nanos !== '' ? convertIsoToMillis(anchor.fields[timeField][0]) : anchor.sort[0]; + nanos !== '' ? convertIsoToMillis(anchorRaw.fields?.[timeField][0]) : anchorRaw.sort?.[0]; const intervals = generateIntervals(LOOKUP_OFFSETS, timeValueMillis as number, type, sortDir); - let documents: EsHitRecordList = []; + let documents: DataTableRecord[] = []; for (const interval of intervals) { const remainingSize = size - documents.length; @@ -92,7 +95,7 @@ export async function fetchSurroundingDocs( searchAfter, remainingSize, nanos, - anchor._id + anchor.raw._id ); documents = diff --git a/src/plugins/discover/public/application/context/services/context_query_state.ts b/src/plugins/discover/public/application/context/services/context_query_state.ts index 3a6a4c0959ea6..611c7666b52fb 100644 --- a/src/plugins/discover/public/application/context/services/context_query_state.ts +++ b/src/plugins/discover/public/application/context/services/context_query_state.ts @@ -6,21 +6,21 @@ * Side Public License, v 1. */ -import { EsHitRecord, EsHitRecordList } from '../../types'; +import { DataTableRecord } from '../../../types'; export interface ContextFetchState { /** * Documents listed before anchor */ - predecessors: EsHitRecordList; + predecessors: DataTableRecord[]; /** * Documents after anchor */ - successors: EsHitRecordList; + successors: DataTableRecord[]; /** * Anchor document */ - anchor: EsHitRecord; + anchor: DataTableRecord; /** * Anchor fetch status */ @@ -54,7 +54,7 @@ export interface LoadingStatusEntry { } export const getInitialContextQueryState = (): ContextFetchState => ({ - anchor: {} as EsHitRecord, + anchor: {} as DataTableRecord, predecessors: [], successors: [], anchorStatus: { value: LoadingStatus.UNINITIALIZED }, diff --git a/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts b/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts index 3547127c1ab8c..cd805a5e4f1a6 100644 --- a/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts +++ b/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts @@ -7,10 +7,11 @@ */ import { lastValueFrom } from 'rxjs'; import { ISearchSource, EsQuerySortValue, SortDirection } from '@kbn/data-plugin/public'; +import { EsQuerySearchAfter } from '@kbn/data-plugin/common'; +import { buildDataTableRecord } from '../../../utils/build_data_record'; import { convertTimeValueToIso } from './date_conversion'; import { IntervalValue } from './generate_intervals'; -import { EsQuerySearchAfter } from './get_es_query_search_after'; -import { EsHitRecord, EsHitRecordList } from '../../types'; +import type { DataTableRecord } from '../../../types'; interface RangeQuery { format: string; @@ -35,7 +36,7 @@ export async function fetchHitsInInterval( maxCount: number, nanosValue: string, anchorId: string -): Promise { +): Promise { const range: RangeQuery = { format: 'strict_date_optional_time', }; @@ -77,7 +78,8 @@ export async function fetchHitsInInterval( .fetch$(); const { rawResponse } = await lastValueFrom(fetch$); + const dataView = searchSource.getField('index'); + const records = rawResponse.hits?.hits.map((hit) => buildDataTableRecord(hit, dataView!)); - // TODO: There's a difference in the definition of SearchResponse and EsHitRecord - return (rawResponse.hits?.hits as unknown as EsHitRecord[]) || []; + return records ?? []; } diff --git a/src/plugins/discover/public/application/context/utils/get_es_query_search_after.ts b/src/plugins/discover/public/application/context/utils/get_es_query_search_after.ts index 85a68376fe43b..bfec54c61e856 100644 --- a/src/plugins/discover/public/application/context/utils/get_es_query_search_after.ts +++ b/src/plugins/discover/public/application/context/utils/get_es_query_search_after.ts @@ -5,11 +5,9 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import type { EsQuerySearchAfter } from '@kbn/data-plugin/common'; import { SurrDocType } from '../services/context'; -import { EsHitRecord, EsHitRecordList } from '../../types'; - -export type EsQuerySearchAfter = [string | number, string | number]; +import type { DataTableRecord } from '../../../types'; /** * Get the searchAfter query value for elasticsearch @@ -19,9 +17,9 @@ export type EsQuerySearchAfter = [string | number, string | number]; */ export function getEsQuerySearchAfter( type: SurrDocType, - documents: EsHitRecordList, + documents: DataTableRecord[], timeFieldName: string, - anchor: EsHitRecord, + anchor: DataTableRecord, nanoSeconds: string, useNewFieldsApi?: boolean ): EsQuerySearchAfter { @@ -30,23 +28,24 @@ export function getEsQuerySearchAfter( const afterTimeRecIdx = type === SurrDocType.SUCCESSORS && documents.length ? documents.length - 1 : 0; const afterTimeDoc = documents[afterTimeRecIdx]; - let afterTimeValue = afterTimeDoc.sort[0] as string | number; + const afterTimeDocRaw = afterTimeDoc.raw; + let afterTimeValue = afterTimeDocRaw.sort?.[0] as string | number; if (nanoSeconds) { afterTimeValue = useNewFieldsApi - ? afterTimeDoc.fields[timeFieldName][0] - : afterTimeDoc._source?.[timeFieldName]; + ? afterTimeDocRaw.fields?.[timeFieldName][0] + : afterTimeDocRaw._source?.[timeFieldName]; } - return [afterTimeValue, afterTimeDoc.sort[1] as string | number]; + return [afterTimeValue, afterTimeDoc.raw.sort?.[1] as string | number]; } // if data_nanos adapt timestamp value for sorting, since numeric value was rounded by browser // ES search_after also works when number is provided as string const searchAfter = new Array(2) as EsQuerySearchAfter; - searchAfter[0] = anchor.sort[0] as string | number; + searchAfter[0] = anchor.raw.sort?.[0] as string | number; if (nanoSeconds) { searchAfter[0] = useNewFieldsApi - ? anchor.fields[timeFieldName][0] - : anchor._source?.[timeFieldName]; + ? anchor.raw.fields?.[timeFieldName][0] + : anchor.raw._source?.[timeFieldName]; } - searchAfter[1] = anchor.sort[1] as string | number; + searchAfter[1] = anchor.raw.sort?.[1] as string | number; return searchAfter; } diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx index 01d5aae129a72..b76b6d6a1ce07 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.test.tsx @@ -18,12 +18,13 @@ import { discoverServiceMock } from '../../../../__mocks__/services'; import { FetchStatus } from '../../../types'; import { DiscoverDocuments } from './discover_documents'; import { indexPatternMock } from '../../../../__mocks__/index_pattern'; -import { ElasticSearchHit } from '../../../../types'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { buildDataTableRecord } from '../../../../utils/build_data_record'; +import { EsHitRecord } from '../../../../types'; setHeaderActionMenuMounter(jest.fn()); -function mountComponent(fetchStatus: FetchStatus, hits: ElasticSearchHit[]) { +function mountComponent(fetchStatus: FetchStatus, hits: EsHitRecord[]) { const services = discoverServiceMock; services.data.query.timefilter.timefilter.getTime = () => { return { from: '2020-05-14T11:05:13.590', to: '2020-05-14T11:20:13.590' }; @@ -31,7 +32,7 @@ function mountComponent(fetchStatus: FetchStatus, hits: ElasticSearchHit[]) { const documents$ = new BehaviorSubject({ fetchStatus, - result: hits, + result: hits.map((hit) => buildDataTableRecord(hit, indexPatternMock)), }) as DataDocuments$; const props = { @@ -62,13 +63,13 @@ describe('Discover documents layout', () => { }); test('render complete when loading but documents were already fetched', () => { - const component = mountComponent(FetchStatus.LOADING, esHits as ElasticSearchHit[]); + const component = mountComponent(FetchStatus.LOADING, esHits); expect(component.find('.dscDocuments__loading').exists()).toBeFalsy(); expect(component.find('.dscTable').exists()).toBeTruthy(); }); test('render complete', () => { - const component = mountComponent(FetchStatus.COMPLETE, esHits as ElasticSearchHit[]); + const component = mountComponent(FetchStatus.COMPLETE, esHits); expect(component.find('.dscDocuments__loading').exists()).toBeFalsy(); expect(component.find('.dscTable').exists()).toBeTruthy(); }); diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx index 530118cb8f1c9..3dbf313fcc7c7 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx @@ -32,10 +32,10 @@ import { AppState, GetStateReturn } from '../../services/discover_state'; import { useDataState } from '../../hooks/use_data_state'; import { DocTableInfinite } from '../../../../components/doc_table/doc_table_infinite'; import { SortPairArr } from '../../../../components/doc_table/utils/get_sort'; -import { ElasticSearchHit } from '../../../../types'; import { DocumentExplorerCallout } from '../document_explorer_callout'; import { DocumentExplorerUpdateCallout } from '../document_explorer_callout/document_explorer_update_callout'; import { DiscoverTourProvider } from '../../../../components/discover_tour'; +import { DataTableRecord } from '../../../../types'; const DocTableInfiniteMemoized = React.memo(DocTableInfinite); const DataGridMemoized = React.memo(DiscoverGrid); @@ -51,12 +51,12 @@ function DiscoverDocumentsComponent({ stateContainer, }: { documents$: DataDocuments$; - expandedDoc?: ElasticSearchHit; + expandedDoc?: DataTableRecord; indexPattern: DataView; navigateTo: (url: string) => void; onAddFilter: DocViewFilterFn; savedSearch: SavedSearch; - setExpandedDoc: (doc?: ElasticSearchHit) => void; + setExpandedDoc: (doc?: DataTableRecord) => void; state: AppState; stateContainer: GetStateReturn; }) { diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx index 1025270dab355..4aff6e2a78070 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.test.tsx @@ -32,10 +32,10 @@ import { FetchStatus } from '../../../types'; import { RequestAdapter } from '@kbn/inspector-plugin'; import { Chart } from '../chart/point_series'; import { DiscoverSidebar } from '../sidebar/discover_sidebar'; -import { ElasticSearchHit } from '../../../../types'; import { LocalStorageMock } from '../../../../__mocks__/local_storage_mock'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { DiscoverServices } from '../../../../build_services'; +import { buildDataTableRecord } from '../../../../utils/build_data_record'; setHeaderActionMenuMounter(jest.fn()); @@ -66,7 +66,7 @@ function mountComponent( const documents$ = new BehaviorSubject({ fetchStatus: FetchStatus.COMPLETE, - result: esHits as ElasticSearchHit[], + result: esHits.map((esHit) => buildDataTableRecord(esHit, indexPattern)), }) as DataDocuments$; const availableFields$ = new BehaviorSubject({ diff --git a/src/plugins/discover/public/application/main/components/layout/types.ts b/src/plugins/discover/public/application/main/components/layout/types.ts index e7bcfb3bc3971..f381f87c7389d 100644 --- a/src/plugins/discover/public/application/main/components/layout/types.ts +++ b/src/plugins/discover/public/application/main/components/layout/types.ts @@ -11,10 +11,10 @@ import type { SavedObject } from '@kbn/data-plugin/public'; import type { DataView, DataViewAttributes } from '@kbn/data-views-plugin/public'; import { ISearchSource } from '@kbn/data-plugin/public'; import { RequestAdapter } from '@kbn/inspector-plugin'; +import { DataTableRecord } from '../../../../types'; import { AppState, GetStateReturn } from '../../services/discover_state'; import { DataRefetch$, SavedSearchData } from '../../hooks/use_saved_search'; import { SavedSearch } from '../../../../services/saved_searches'; -import { ElasticSearchHit } from '../../../../types'; export interface DiscoverLayoutProps { indexPattern: DataView; @@ -24,8 +24,8 @@ export interface DiscoverLayoutProps { onChangeIndexPattern: (id: string) => void; onUpdateQuery: (payload: { dateRange: TimeRange; query?: Query }, isUpdate?: boolean) => void; resetSavedSearch: () => void; - expandedDoc?: ElasticSearchHit; - setExpandedDoc: (doc?: ElasticSearchHit) => void; + expandedDoc?: DataTableRecord; + setExpandedDoc: (doc?: DataTableRecord) => void; savedSearch: SavedSearch; savedSearchData$: SavedSearchData; savedSearchRefetch$: DataRefetch$; diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx index 34cfde26ff32c..2bbd2e579f4aa 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.test.tsx @@ -5,18 +5,13 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - -import { cloneDeep, each } from 'lodash'; import { ReactWrapper } from 'enzyme'; import { findTestSubject } from '@elastic/eui/lib/test'; import { Action } from '@kbn/ui-actions-plugin/public'; -// @ts-expect-error -import realHits from '../../../../__fixtures__/real_hits'; - +import { getDataTableRecords } from '../../../../__fixtures__/real_hits'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import React from 'react'; import { DiscoverSidebarProps } from './discover_sidebar'; -import { flattenHit } from '@kbn/data-plugin/public'; import { DataViewAttributes } from '@kbn/data-views-plugin/public'; import { SavedObject } from '@kbn/core/types'; import { getDefaultFieldFilter } from './lib/field_filter'; @@ -24,7 +19,6 @@ import { DiscoverSidebarComponent as DiscoverSidebar } from './discover_sidebar' import { discoverServiceMock as mockDiscoverServices } from '../../../../__mocks__/services'; import { stubLogstashIndexPattern } from '@kbn/data-plugin/common/stubs'; import { VIEW_MODE } from '../../../../components/view_mode_toggle'; -import { ElasticSearchHit } from '../../../../types'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { BehaviorSubject } from 'rxjs'; import { FetchStatus } from '../../../types'; @@ -42,9 +36,7 @@ jest.mock('../../../../kibana_services', () => ({ function getCompProps(): DiscoverSidebarProps { const indexPattern = stubLogstashIndexPattern; - const hits = each(cloneDeep(realHits), (hit) => - flattenHit(hit, indexPattern) - ) as unknown as ElasticSearchHit[]; + const hits = getDataTableRecords(indexPattern); const indexPatternList = [ { id: '0', attributes: { title: 'b' } } as SavedObject, @@ -55,7 +47,7 @@ function getCompProps(): DiscoverSidebarProps { const fieldCounts: Record = {}; for (const hit of hits) { - for (const key of Object.keys(flattenHit(hit, indexPattern))) { + for (const key of Object.keys(hit.flattened)) { fieldCounts[key] = (fieldCounts[key] || 0) + 1; } } diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx index 0141aead76eff..5ce3ad6cd147d 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar.tsx @@ -40,7 +40,7 @@ import { getIndexPatternFieldList } from './lib/get_index_pattern_field_list'; import { DiscoverSidebarResponsiveProps } from './discover_sidebar_responsive'; import { VIEW_MODE } from '../../../../components/view_mode_toggle'; import { DISCOVER_TOUR_STEP_ANCHOR_IDS } from '../../../../components/discover_tour'; -import { ElasticSearchHit } from '../../../../types'; +import type { DataTableRecord } from '../../../../types'; /** * Default number of available fields displayed and added on scroll @@ -88,7 +88,7 @@ export interface DiscoverSidebarProps extends Omit ({ function getCompProps(): DiscoverSidebarResponsiveProps { const indexPattern = stubLogstashIndexPattern; - const hits = each(cloneDeep(realHits), (hit) => - flattenHit(hit, indexPattern) - ) as unknown as ElasticSearchHit[]; + const hits = getDataTableRecords(indexPattern); const indexPatternList = [ { id: '0', attributes: { title: 'b' } } as SavedObject, @@ -90,7 +84,7 @@ function getCompProps(): DiscoverSidebarResponsiveProps { ]; for (const hit of hits) { - for (const key of Object.keys(flattenHit(hit, indexPattern))) { + for (const key of Object.keys(hit.flattened)) { mockfieldCounts[key] = (mockfieldCounts[key] || 0) + 1; } } @@ -99,7 +93,7 @@ function getCompProps(): DiscoverSidebarResponsiveProps { columns: ['extension'], documents$: new BehaviorSubject({ fetchStatus: FetchStatus.COMPLETE, - result: hits as ElasticSearchHit[], + result: hits, }) as DataDocuments$, availableFields$: new BehaviorSubject({ fetchStatus: FetchStatus.COMPLETE, diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx index c6d8d05a23ad8..e4134184306fa 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx @@ -123,7 +123,10 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) */ const fieldCounts = useRef | null>(null); if (fieldCounts.current === null) { - fieldCounts.current = calcFieldCounts(props.documents$.getValue().result, selectedIndexPattern); + fieldCounts.current = calcFieldCounts( + props.documents$.getValue().result!, + selectedIndexPattern + ); } const [documentState, setDocumentState] = useState(props.documents$.getValue()); @@ -266,7 +269,7 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) flattenHit(hit, dataView)); + hits = getDataTableRecords(dataView); }); it('Should return an array of values for _source fields', function () { @@ -153,7 +149,7 @@ describe('fieldCalculator', function () { let params: { hits: any; field: any; count: number; dataView: DataView }; beforeEach(function () { params = { - hits: cloneDeep(realHits), + hits: getDataTableRecords(dataView), field: dataView.fields.getByName('extension'), count: 3, dataView, diff --git a/src/plugins/discover/public/application/main/components/sidebar/lib/get_details.ts b/src/plugins/discover/public/application/main/components/sidebar/lib/get_details.ts index 78e752494c43d..99ab866a53491 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/lib/get_details.ts +++ b/src/plugins/discover/public/application/main/components/sidebar/lib/get_details.ts @@ -9,11 +9,11 @@ import { DataView, DataViewField } from '@kbn/data-views-plugin/public'; // @ts-expect-error import { fieldCalculator } from './field_calculator'; -import { ElasticSearchHit } from '../../../../../types'; +import { DataTableRecord } from '../../../../../types'; export function getDetails( field: DataViewField, - hits: ElasticSearchHit[] | undefined, + hits: DataTableRecord[] | undefined, columns: string[], indexPattern?: DataView ) { @@ -24,7 +24,6 @@ export function getDetails( ...fieldCalculator.getFieldValueCounts({ hits, field, - indexPattern, count: 5, grouped: false, }), diff --git a/src/plugins/discover/public/application/main/discover_main_app.tsx b/src/plugins/discover/public/application/main/discover_main_app.tsx index ae477719af119..6025c27a0c433 100644 --- a/src/plugins/discover/public/application/main/discover_main_app.tsx +++ b/src/plugins/discover/public/application/main/discover_main_app.tsx @@ -15,8 +15,8 @@ import { addHelpMenuToAppChrome } from '../../components/help_menu/help_menu_uti import { useDiscoverState } from './hooks/use_discover_state'; import { useUrl } from './hooks/use_url'; import { SavedSearch } from '../../services/saved_searches'; -import { ElasticSearchHit } from '../../types'; import { useDiscoverServices } from '../../hooks/use_discover_services'; +import { DataTableRecord } from '../../types'; const DiscoverLayoutMemoized = React.memo(DiscoverLayout); @@ -36,7 +36,7 @@ export function DiscoverMainApp(props: DiscoverMainProps) { const services = useDiscoverServices(); const { chrome, docLinks, uiSettings: config, data } = services; const history = useHistory(); - const [expandedDoc, setExpandedDoc] = useState(undefined); + const [expandedDoc, setExpandedDoc] = useState(undefined); const navigateTo = useCallback( (path: string) => { history.push(path); diff --git a/src/plugins/discover/public/application/main/hooks/use_discover_state.ts b/src/plugins/discover/public/application/main/hooks/use_discover_state.ts index ab481f2f67a50..2d82e12824f04 100644 --- a/src/plugins/discover/public/application/main/hooks/use_discover_state.ts +++ b/src/plugins/discover/public/application/main/hooks/use_discover_state.ts @@ -24,7 +24,7 @@ import { useSearchSession } from './use_search_session'; import { FetchStatus } from '../../types'; import { getSwitchIndexPatternAppState } from '../utils/get_switch_index_pattern_app_state'; import { SortPairArr } from '../../../components/doc_table/utils/get_sort'; -import { ElasticSearchHit } from '../../../types'; +import { DataTableRecord } from '../../../types'; export function useDiscoverState({ services, @@ -35,7 +35,7 @@ export function useDiscoverState({ services: DiscoverServices; savedSearch: SavedSearch; history: History; - setExpandedDoc: (doc?: ElasticSearchHit) => void; + setExpandedDoc: (doc?: DataTableRecord) => void; }) { const { uiSettings: config, data, filterManager, indexPatterns, storage } = services; const useNewFieldsApi = useMemo(() => !config.get(SEARCH_FIELDS_FROM_SOURCE), [config]); diff --git a/src/plugins/discover/public/application/main/hooks/use_saved_search.ts b/src/plugins/discover/public/application/main/hooks/use_saved_search.ts index d4d6b869c7ee7..0cfa1b2e97579 100644 --- a/src/plugins/discover/public/application/main/hooks/use_saved_search.ts +++ b/src/plugins/discover/public/application/main/hooks/use_saved_search.ts @@ -7,9 +7,9 @@ */ import { useCallback, useEffect, useMemo, useRef } from 'react'; import { BehaviorSubject, Subject } from 'rxjs'; +import type { AutoRefreshDoneFn } from '@kbn/data-plugin/public'; import { ISearchSource } from '@kbn/data-plugin/public'; import { RequestAdapter } from '@kbn/inspector-plugin/public'; -import type { AutoRefreshDoneFn } from '@kbn/data-plugin/public'; import { DiscoverServices } from '../../../build_services'; import { DiscoverSearchSessionManager } from '../services/discover_search_session'; import { GetStateReturn } from '../services/discover_state'; @@ -17,13 +17,12 @@ import { validateTimeRange } from '../utils/validate_time_range'; import { Chart } from '../components/chart/point_series'; import { useSingleton } from './use_singleton'; import { FetchStatus } from '../../types'; - import { fetchAll } from '../utils/fetch_all'; import { useBehaviorSubject } from './use_behavior_subject'; import { sendResetMsg } from './use_saved_search_messages'; import { getFetch$ } from '../utils/get_fetch_observable'; -import { ElasticSearchHit } from '../../../types'; import { SavedSearch } from '../../../services/saved_searches'; +import type { DataTableRecord } from '../../../types'; export interface SavedSearchData { main$: DataMain$; @@ -66,7 +65,7 @@ export interface DataMainMsg extends DataMsg { } export interface DataDocumentsMsg extends DataMsg { - result?: ElasticSearchHit[]; + result?: DataTableRecord[]; } export interface DataTotalHitsMsg extends DataMsg { diff --git a/src/plugins/discover/public/application/main/utils/calc_field_counts.test.ts b/src/plugins/discover/public/application/main/utils/calc_field_counts.test.ts index 2ed564194bd25..1534dbf6aad4d 100644 --- a/src/plugins/discover/public/application/main/utils/calc_field_counts.test.ts +++ b/src/plugins/discover/public/application/main/utils/calc_field_counts.test.ts @@ -8,19 +8,17 @@ import { calcFieldCounts } from './calc_field_counts'; import { indexPatternMock } from '../../../__mocks__/index_pattern'; -import { ElasticSearchHit } from '../../../types'; +import { buildDataTableRecord } from '../../../utils/build_data_record'; describe('calcFieldCounts', () => { test('returns valid field count data', async () => { const rows = [ - { _id: 1, _source: { message: 'test1', bytes: 20 } }, - { _id: 2, _source: { name: 'test2', extension: 'jpg' } }, - ] as unknown as ElasticSearchHit[]; + { _id: '1', _index: 'test', _source: { message: 'test1', bytes: 20 } }, + { _id: '2', _index: 'test', _source: { name: 'test2', extension: 'jpg' } }, + ].map((row) => buildDataTableRecord(row)); const result = calcFieldCounts(rows, indexPatternMock); expect(result).toMatchInlineSnapshot(` Object { - "_index": 2, - "_score": 2, "bytes": 1, "extension": 1, "message": 1, @@ -30,14 +28,12 @@ describe('calcFieldCounts', () => { }); test('updates field count data', async () => { const rows = [ - { _id: 1, _source: { message: 'test1', bytes: 20 } }, - { _id: 2, _source: { name: 'test2', extension: 'jpg' } }, - ] as unknown as ElasticSearchHit[]; + { _id: '1', _index: 'test', _source: { message: 'test1', bytes: 20 } }, + { _id: '2', _index: 'test', _source: { name: 'test2', extension: 'jpg' } }, + ].map((row) => buildDataTableRecord(row)); const result = calcFieldCounts(rows, indexPatternMock); expect(result).toMatchInlineSnapshot(` Object { - "_index": 2, - "_score": 2, "bytes": 1, "extension": 1, "message": 1, diff --git a/src/plugins/discover/public/application/main/utils/calc_field_counts.ts b/src/plugins/discover/public/application/main/utils/calc_field_counts.ts index cf2b5d7a880b3..5112625ba12b9 100644 --- a/src/plugins/discover/public/application/main/utils/calc_field_counts.ts +++ b/src/plugins/discover/public/application/main/utils/calc_field_counts.ts @@ -6,20 +6,19 @@ * Side Public License, v 1. */ import { DataView } from '@kbn/data-views-plugin/public'; -import { flattenHit } from '@kbn/data-plugin/public'; -import { ElasticSearchHit } from '../../../types'; +import { DataTableRecord } from '../../../types'; /** * This function is calculating stats of the available fields, for usage in sidebar and sharing * Note that this values aren't displayed, but used for internal calculations */ -export function calcFieldCounts(rows?: ElasticSearchHit[], indexPattern?: DataView) { +export function calcFieldCounts(rows?: DataTableRecord[], indexPattern?: DataView) { const counts: Record = {}; if (!rows || !indexPattern) { return {}; } for (const hit of rows) { - const fields = Object.keys(flattenHit(hit, indexPattern, { includeIgnoredValues: true })); + const fields = Object.keys(hit.flattened); for (const fieldName of fields) { counts[fieldName] = (counts[fieldName] || 0) + 1; } diff --git a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts index d372f921f9976..e33d931c571da 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts @@ -27,6 +27,8 @@ import { import { fetchDocuments } from './fetch_documents'; import { fetchChart } from './fetch_chart'; import { fetchTotalHits } from './fetch_total_hits'; +import { indexPatternMock } from '../../../__mocks__/index_pattern'; +import { buildDataTableRecord } from '../../../utils/build_data_record'; jest.mock('./fetch_documents', () => ({ fetchDocuments: jest.fn().mockResolvedValue([]), @@ -119,7 +121,10 @@ describe('test fetchAll', () => { expect(await collect()).toEqual([ { fetchStatus: FetchStatus.UNINITIALIZED }, { fetchStatus: FetchStatus.LOADING }, - { fetchStatus: FetchStatus.COMPLETE, result: hits }, + { + fetchStatus: FetchStatus.COMPLETE, + result: hits.map((hit) => buildDataTableRecord(hit, indexPatternMock)), + }, ]); }); diff --git a/src/plugins/discover/public/application/main/utils/fetch_all.ts b/src/plugins/discover/public/application/main/utils/fetch_all.ts index 1d5d4646445a5..655027dddbf1e 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_all.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_all.ts @@ -5,11 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { ISearchSource } from '@kbn/data-plugin/public'; +import { DataPublicPluginStart, ISearchSource } from '@kbn/data-plugin/public'; import { Adapters } from '@kbn/inspector-plugin'; -import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { ReduxLikeStateContainer } from '@kbn/kibana-utils-plugin/common'; import { DataViewType } from '@kbn/data-views-plugin/public'; +import { buildDataTableRecord } from '../../../utils/build_data_record'; import { sendCompleteMsg, sendErrorMsg, @@ -45,6 +45,7 @@ export interface FetchDeps { services: DiscoverServices; useNewFieldsApi: boolean; } + /** * This function starts fetching all required queries in Discover. This will be the query to load the individual * documents, and depending on whether a chart is shown either the aggregation query to load the chart data @@ -139,10 +140,13 @@ export function fetchAll( result: docs.length, }); } + const dataView = searchSource.getField('index')!; + + const resultDocs = docs.map((doc) => buildDataTableRecord(doc, dataView)); dataSubjects.documents$.next({ fetchStatus: FetchStatus.COMPLETE, - result: docs, + result: resultDocs, }); checkHitCount(docs.length); diff --git a/src/plugins/discover/public/application/main/utils/fetch_chart.ts b/src/plugins/discover/public/application/main/utils/fetch_chart.ts index 5117bffe5c9b8..da1a071a18d4b 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_chart.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_chart.ts @@ -28,14 +28,7 @@ interface Result { export function fetchChart( searchSource: ISearchSource, - { - abortController, - appStateContainer, - data, - inspectorAdapters, - searchSessionId, - savedSearch, - }: FetchDeps + { abortController, appStateContainer, data, inspectorAdapters, searchSessionId }: FetchDeps ): Promise { const interval = appStateContainer.getState().interval ?? 'auto'; const chartAggConfigs = updateSearchSource(searchSource, interval, data); diff --git a/src/plugins/discover/public/application/main/utils/fetch_documents.ts b/src/plugins/discover/public/application/main/utils/fetch_documents.ts index d652f544a8f70..e09875d11deb6 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_documents.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_documents.ts @@ -18,7 +18,7 @@ import { FetchDeps } from './fetch_all'; */ export const fetchDocuments = ( searchSource: ISearchSource, - { abortController, inspectorAdapters, searchSessionId, services, savedSearch }: FetchDeps + { abortController, inspectorAdapters, searchSessionId, services }: FetchDeps ) => { searchSource.setField('size', services.uiSettings.get(SAMPLE_SIZE_SETTING)); searchSource.setField('trackTotalHits', false); diff --git a/src/plugins/discover/public/application/types.ts b/src/plugins/discover/public/application/types.ts index f04f3bf77c2f9..798e0f350cc5f 100644 --- a/src/plugins/discover/public/application/types.ts +++ b/src/plugins/discover/public/application/types.ts @@ -5,7 +5,6 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export enum FetchStatus { UNINITIALIZED = 'uninitialized', @@ -14,13 +13,3 @@ export enum FetchStatus { COMPLETE = 'complete', ERROR = 'error', } - -export type EsHitRecord = Required< - Pick -> & { - _source?: Record; - _score?: number; - // note that this a special property for Discover Context, to determine the anchor record - isAnchor?: boolean; -}; -export type EsHitRecordList = EsHitRecord[]; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx index c5ac7335b69c2..876ffadfed433 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx @@ -14,10 +14,11 @@ import { esHits } from '../../__mocks__/es_hits'; import { indexPatternMock } from '../../__mocks__/index_pattern'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { DiscoverGrid, DiscoverGridProps } from './discover_grid'; -import { getDocId } from './discover_grid_document_selection'; -import { ElasticSearchHit } from '../../types'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { discoverServiceMock } from '../../__mocks__/services'; +import { buildDataTableRecord } from '../../utils/build_data_record'; +import { getDocId } from '../../utils/get_doc_id'; +import { EsHitRecord } from '../../types'; function getProps() { return { @@ -32,7 +33,7 @@ function getProps() { onResize: jest.fn(), onSetColumns: jest.fn(), onSort: jest.fn(), - rows: esHits, + rows: esHits.map((hit) => buildDataTableRecord(hit, indexPatternMock)), sampleSize: 30, searchDescription: '', searchTitle: '', @@ -74,7 +75,7 @@ function getDisplayedDocNr(component: ReactWrapper) { async function toggleDocSelection( component: ReactWrapper, - document: ElasticSearchHit + document: EsHitRecord ) { act(() => { const docId = getDocId(document); @@ -146,7 +147,7 @@ describe('DiscoverGrid', () => { bytes: 50, }, }, - ], + ].map((row) => buildDataTableRecord(row, indexPatternMock)), }); expect(getDisplayedDocNr(component)).toBe(1); expect(getSelectedDocNr(component)).toBe(0); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid.tsx index 48fd2ba656746..5b60a92110320 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid.tsx @@ -23,7 +23,6 @@ import { EuiLink, } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; -import { flattenHit } from '@kbn/data-plugin/public'; import { DocViewFilterFn } from '../../services/doc_views/doc_views_types'; import { getSchemaDetectors } from './discover_grid_schema'; import { DiscoverGridFlyout } from './discover_grid_flyout'; @@ -48,10 +47,10 @@ import { MAX_DOC_FIELDS_DISPLAYED, SHOW_MULTIFIELDS, } from '../../../common'; -import { DiscoverGridDocumentToolbarBtn, getDocId } from './discover_grid_document_selection'; +import { DiscoverGridDocumentToolbarBtn } from './discover_grid_document_selection'; import { SortPairArr } from '../doc_table/utils/get_sort'; import { getFieldsToShow } from '../../utils/get_fields_to_show'; -import type { ElasticSearchHit, ValueToStringConverter } from '../../types'; +import type { DataTableRecord, ValueToStringConverter } from '../../types'; import { useRowHeightsOptions } from '../../hooks/use_row_heights_options'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { convertValueToString } from '../../utils/convert_value_to_string'; @@ -77,7 +76,7 @@ export interface DiscoverGridProps { /** * If set, the given document is displayed in a flyout */ - expandedDoc?: ElasticSearchHit; + expandedDoc?: DataTableRecord; /** * The used index pattern */ @@ -114,7 +113,7 @@ export interface DiscoverGridProps { /** * Array of documents provided by Elasticsearch */ - rows?: ElasticSearchHit[]; + rows?: DataTableRecord[]; /** * The max size of the documents returned by Elasticsearch */ @@ -122,7 +121,7 @@ export interface DiscoverGridProps { /** * Function to set the expanded document, which is displayed in a flyout */ - setExpandedDoc: (doc?: ElasticSearchHit) => void; + setExpandedDoc: (doc?: DataTableRecord) => void; /** * Grid display settings persisted in Elasticsearch (e.g. column width) */ @@ -211,7 +210,7 @@ export const DiscoverGrid = ({ if (!selectedDocs.length || !rows?.length) { return []; } - const idMap = rows.reduce((map, row) => map.set(getDocId(row), true), new Map()); + const idMap = rows.reduce((map, row) => map.set(row.id, true), new Map()); // filter out selected docs that are no longer part of the current data const result = selectedDocs.filter((docId) => idMap.get(docId)); if (result.length === 0 && isFilterActive) { @@ -227,7 +226,7 @@ export const DiscoverGrid = ({ if (!isFilterActive || usedSelectedDocs.length === 0) { return rows; } - const rowsFiltered = rows.filter((row) => usedSelectedDocs.includes(getDocId(row))); + const rowsFiltered = rows.filter((row) => usedSelectedDocs.includes(row.id)); if (!rowsFiltered.length) { // in case the selected docs are no longer part of the sample of 500, show all docs return rows; @@ -235,25 +234,18 @@ export const DiscoverGrid = ({ return rowsFiltered; }, [rows, usedSelectedDocs, isFilterActive]); - const displayedRowsFlattened = useMemo(() => { - return displayedRows.map((hit) => { - return flattenHit(hit, indexPattern, { includeIgnoredValues: true }); - }); - }, [displayedRows, indexPattern]); - const valueToStringConverter: ValueToStringConverter = useCallback( (rowIndex, columnId, options) => { return convertValueToString({ rowIndex, rows: displayedRows, - rowsFlattened: displayedRowsFlattened, dataView: indexPattern, columnId, services, options, }); }, - [displayedRows, displayedRowsFlattened, indexPattern, services] + [displayedRows, indexPattern, services] ); /** @@ -314,20 +306,12 @@ export const DiscoverGrid = ({ getRenderCellValueFn( indexPattern, displayedRows, - displayedRowsFlattened, useNewFieldsApi, fieldsToShow, services.uiSettings.get(MAX_DOC_FIELDS_DISPLAYED), () => dataGridRef.current?.closeCellPopover() ), - [ - indexPattern, - displayedRowsFlattened, - displayedRows, - useNewFieldsApi, - fieldsToShow, - services.uiSettings, - ] + [indexPattern, displayedRows, useNewFieldsApi, fieldsToShow, services.uiSettings] ); /** @@ -473,7 +457,6 @@ export const DiscoverGrid = ({ expanded: expandedDoc, setExpanded: setExpandedDoc, rows: displayedRows, - rowsFlattened: displayedRowsFlattened, onFilter, indexPattern, isDarkMode: services.uiSettings.get('theme:darkMode'), diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.tsx index f7497dd5d459d..055967d6440a2 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.tsx @@ -20,8 +20,8 @@ function onFilterCell( columnId: EuiDataGridColumnCellActionProps['columnId'], mode: '+' | '-' ) { - const row = context.rowsFlattened[rowIndex]; - const value = String(row[columnId]); + const row = context.rows[rowIndex]; + const value = String(row.flattened[columnId]); const field = context.indexPattern.fields.getByName(columnId); if (value && field) { diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_context.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_context.tsx index ca2a0ee5839cb..0761e4c40376e 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_context.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_context.tsx @@ -9,13 +9,12 @@ import React from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { DocViewFilterFn } from '../../services/doc_views/doc_views_types'; -import type { ElasticSearchHit, HitsFlattened, ValueToStringConverter } from '../../types'; +import type { DataTableRecord, ValueToStringConverter } from '../../types'; export interface GridContext { - expanded?: ElasticSearchHit; - setExpanded: (hit?: ElasticSearchHit) => void; - rows: ElasticSearchHit[]; - rowsFlattened: HitsFlattened; + expanded?: DataTableRecord | undefined; + setExpanded: (hit?: DataTableRecord) => void; + rows: DataTableRecord[]; onFilter: DocViewFilterFn; indexPattern: DataView; isDarkMode: boolean; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.test.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.test.tsx index 5ca7b84789e91..96bc9082d9e0f 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.test.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.test.tsx @@ -8,13 +8,10 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { findTestSubject } from '@elastic/eui/lib/test'; -import { - DiscoverGridDocumentToolbarBtn, - getDocId, - SelectButton, -} from './discover_grid_document_selection'; +import { DiscoverGridDocumentToolbarBtn, SelectButton } from './discover_grid_document_selection'; import { discoverGridContextMock } from '../../__mocks__/grid_context'; import { DiscoverGridContext } from './discover_grid_context'; +import { getDocId } from '../../utils/get_doc_id'; describe('document selection', () => { describe('getDocId', () => { diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx index efe8784028cbf..c17ff66ac0806 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx @@ -5,37 +5,28 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import React, { useCallback, useState, useContext, useMemo, useEffect } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import classNames from 'classnames'; import { EuiButtonEmpty, + EuiCheckbox, EuiContextMenuItem, EuiContextMenuPanel, EuiCopy, - EuiPopover, - EuiCheckbox, EuiDataGridCellValueElementProps, + EuiPopover, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { euiLightVars as themeLight, euiDarkVars as themeDark } from '@kbn/ui-theme'; +import { euiDarkVars as themeDark, euiLightVars as themeLight } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { DiscoverGridContext } from './discover_grid_context'; -import { ElasticSearchHit } from '../../types'; +import type { DataTableRecord } from '../../types'; -/** - * Returning a generated id of a given ES document, since `_id` can be the same - * when using different indices and shard routing - */ -export const getDocId = (doc: ElasticSearchHit & { _routing?: string }) => { - const routing = doc._routing ? doc._routing : ''; - return [doc._index, doc._id, routing].join('::'); -}; export const SelectButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueElementProps) => { const { selectedDocs, expanded, rows, isDarkMode, setSelectedDocs } = useContext(DiscoverGridContext); const doc = useMemo(() => rows[rowIndex], [rows, rowIndex]); - const id = useMemo(() => getDocId(doc), [doc]); - const checked = useMemo(() => selectedDocs.includes(id), [selectedDocs, id]); + const checked = useMemo(() => selectedDocs.includes(doc.id), [selectedDocs, doc.id]); const toggleDocumentSelectionLabel = i18n.translate('discover.grid.selectDoc', { defaultMessage: `Select document '{rowNumber}'`, @@ -43,7 +34,7 @@ export const SelectButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueEle }); useEffect(() => { - if (expanded && doc && expanded._id === doc._id && expanded._index === doc._index) { + if (expanded && doc && expanded.id === doc.id) { setCellProps({ style: { backgroundColor: isDarkMode ? themeDark.euiColorHighlight : themeLight.euiColorHighlight, @@ -56,16 +47,16 @@ export const SelectButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueEle return ( { if (checked) { - const newSelection = selectedDocs.filter((docId) => docId !== id); + const newSelection = selectedDocs.filter((docId) => docId !== doc.id); setSelectedDocs(newSelection); } else { - setSelectedDocs([...selectedDocs, id]); + setSelectedDocs([...selectedDocs, doc.id]); } }} /> @@ -80,7 +71,7 @@ export function DiscoverGridDocumentToolbarBtn({ setSelectedDocs, }: { isFilterActive: boolean; - rows: ElasticSearchHit[]; + rows: DataTableRecord[]; selectedDocs: string[]; setIsFilterActive: (value: boolean) => void; setSelectedDocs: (value: string[]) => void; @@ -121,7 +112,11 @@ export function DiscoverGridDocumentToolbarBtn({ key="copyJsonWrapper" data-test-subj="dscGridCopySelectedDocumentsJSON" textToCopy={ - rows ? JSON.stringify(rows.filter((row) => selectedDocs.includes(getDocId(row)))) : '' + rows + ? JSON.stringify( + rows.filter((row) => selectedDocs.includes(row.id)).map((row) => row.raw) + ) + : '' } > {(copy) => ( diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx index 3a506c063c177..e00e722f9c2e9 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx @@ -11,7 +11,6 @@ import { EuiButtonIcon, EuiDataGridCellValueElementProps, EuiToolTip } from '@el import { euiLightVars as themeLight, euiDarkVars as themeDark } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { DiscoverGridContext } from './discover_grid_context'; -import { EsHitRecord } from '../../application/types'; import { DISCOVER_TOUR_STEP_ANCHOR_IDS } from '../discover_tour'; /** @@ -21,16 +20,11 @@ export const ExpandButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueEle const { expanded, setExpanded, rows, isDarkMode } = useContext(DiscoverGridContext); const current = rows[rowIndex]; useEffect(() => { - if ((current as EsHitRecord).isAnchor) { + if (current.isAnchor) { setCellProps({ className: 'dscDocsGrid__cell--highlight', }); - } else if ( - expanded && - current && - expanded._id === current._id && - expanded._index === current._index - ) { + } else if (expanded && current && expanded.id === current.id) { setCellProps({ style: { backgroundColor: isDarkMode ? themeDark.euiColorHighlight : themeLight.euiColorHighlight, @@ -46,7 +40,7 @@ export const ExpandButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueEle defaultMessage: 'Toggle dialog with details', }); - const testSubj = (current as EsHitRecord).isAnchor + const testSubj = current.isAnchor ? 'docTableExpandToggleColumnAnchor' : 'docTableExpandToggleColumn'; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx index 6452349bbdc77..5b4d4d3109e19 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx @@ -19,7 +19,8 @@ import { setDocViewsRegistry } from '../../kibana_services'; import { indexPatternWithTimefieldMock } from '../../__mocks__/index_pattern_with_timefield'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; -import type { ElasticSearchHit } from '../../types'; +import type { DataTableRecord, EsHitRecord } from '../../types'; +import { buildDataTableRecord } from '../../utils/build_data_record'; describe('Discover flyout', function () { setDocViewsRegistry(new DocViewsRegistry()); @@ -30,7 +31,7 @@ describe('Discover flyout', function () { hitIndex, }: { indexPattern?: DataView; - hits?: ElasticSearchHit[]; + hits?: DataTableRecord[]; hitIndex?: number; }) => { const onClose = jest.fn(); @@ -40,11 +41,20 @@ describe('Discover flyout', function () { history: () => ({ location: {} }), } as unknown as DiscoverServices; + const hit = buildDataTableRecord( + hitIndex ? esHits[hitIndex] : (esHits[0] as EsHitRecord), + indexPatternMock + ); + const props = { columns: ['date'], indexPattern: indexPattern || indexPatternMock, - hit: hitIndex ? esHits[hitIndex] : esHits[0], - hits: hits || esHits, + hit, + hits: + hits || + esHits.map((entry: EsHitRecord) => + buildDataTableRecord(entry, indexPattern || indexPatternMock) + ), onAddColumn: jest.fn(), onClose, onFilter: jest.fn(), @@ -116,7 +126,7 @@ describe('Discover flyout', function () { _type: '_doc', _source: { date: '2020-20-01T12:12:12.124', name: 'test2', extension: 'jpg' }, }, - ]; + ].map((hit) => buildDataTableRecord(hit, indexPatternMock)); const { component } = mountComponent({ hits }); const docNav = findTestSubject(component, 'dscDocNavigation'); expect(docNav.length).toBeFalsy(); @@ -127,7 +137,7 @@ describe('Discover flyout', function () { const { component, props } = mountComponent({}); findTestSubject(component, 'pagination-button-next').simulate('click'); // we selected 1, so we'd expect 2 - expect(props.setExpandedDoc.mock.calls[0][0]._id).toBe('2'); + expect(props.setExpandedDoc.mock.calls[0][0].raw._id).toBe('2'); }); it('doesnt allow you to navigate to the previous doc, if expanded doc is the first', async () => { @@ -149,16 +159,16 @@ describe('Discover flyout', function () { const { component, props } = mountComponent({ hitIndex: esHits.length - 1 }); findTestSubject(component, 'pagination-button-previous').simulate('click'); expect(props.setExpandedDoc).toHaveBeenCalledTimes(1); - expect(props.setExpandedDoc.mock.calls[0][0]._id).toBe('4'); + expect(props.setExpandedDoc.mock.calls[0][0].raw._id).toBe('4'); }); it('allows navigating with arrow keys through documents', () => { const { component, props } = mountComponent({}); findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowRight' }); - expect(props.setExpandedDoc).toHaveBeenCalledWith(expect.objectContaining({ _id: '2' })); + expect(props.setExpandedDoc).toHaveBeenCalledWith(expect.objectContaining({ id: 'i::2::' })); component.setProps({ ...props, hit: props.hits[1] }); findTestSubject(component, 'docTableDetailsFlyout').simulate('keydown', { key: 'ArrowLeft' }); - expect(props.setExpandedDoc).toHaveBeenCalledWith(expect.objectContaining({ _id: '1' })); + expect(props.setExpandedDoc).toHaveBeenCalledWith(expect.objectContaining({ id: 'i::1::' })); }); it('should not navigate with keypresses when already at the border of documents', () => { diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx index a34e6da654699..c2165fc27ee2a 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx @@ -28,31 +28,24 @@ import { import { DocViewer } from '../../services/doc_views/components/doc_viewer/doc_viewer'; import { DocViewFilterFn } from '../../services/doc_views/doc_views_types'; import { useNavigationProps } from '../../hooks/use_navigation_props'; -import { ElasticSearchHit } from '../../types'; import { useDiscoverServices } from '../../hooks/use_discover_services'; +import type { DataTableRecord } from '../../types'; export interface DiscoverGridFlyoutProps { columns: string[]; - hit: ElasticSearchHit; - hits?: ElasticSearchHit[]; + hit: DataTableRecord; + hits?: DataTableRecord[]; indexPattern: DataView; onAddColumn: (column: string) => void; onClose: () => void; onFilter: DocViewFilterFn; onRemoveColumn: (column: string) => void; - setExpandedDoc: (doc: ElasticSearchHit) => void; + setExpandedDoc: (doc: DataTableRecord) => void; } -type ElasticSearchHitWithRouting = ElasticSearchHit & { _routing?: string }; - -function getDocFingerprintId(doc: ElasticSearchHitWithRouting) { - const routing = doc._routing || ''; - return [doc._index, doc._id, routing].join('||'); -} - -function getIndexByDocId(hits: ElasticSearchHit[], id: string) { +function getIndexByDocId(hits: DataTableRecord[], id: string) { return hits.findIndex((h) => { - return getDocFingerprintId(h) === id; + return h.id === id; }); } /** @@ -71,13 +64,10 @@ export function DiscoverGridFlyout({ }: DiscoverGridFlyoutProps) { const services = useDiscoverServices(); // Get actual hit with updated highlighted searches - const actualHit = useMemo( - () => hits?.find(({ _id, _index }) => hit._index === _index && _id === hit?._id) || hit, - [hit, hits] - ); + const actualHit = useMemo(() => hits?.find(({ id }) => id === hit?.id) || hit, [hit, hits]); const pageCount = useMemo(() => (hits ? hits.length : 0), [hits]); const activePage = useMemo(() => { - const id = getDocFingerprintId(hit); + const id = hit.id; if (!hits || pageCount <= 1) { return -1; } @@ -107,8 +97,8 @@ export function DiscoverGridFlyout({ const { singleDocProps, surrDocsProps } = useNavigationProps({ indexPatternId: indexPattern.id!, - rowIndex: hit._index, - rowId: hit._id, + rowIndex: hit.raw._index, + rowId: hit.raw._id, filterManager: services.filterManager, addBasePath: services.addBasePath, columns, diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx index c706892c9f706..b797c8a969831 100644 --- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx +++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx @@ -12,9 +12,9 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { getRenderCellValueFn } from './get_render_cell_value'; import { indexPatternMock } from '../../__mocks__/index_pattern'; -import { flattenHit } from '@kbn/data-plugin/public'; -import { ElasticSearchHit } from '../../types'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { buildDataTableRecord } from '../../utils/build_data_record'; +import { EsHitRecord } from '../../types'; const mockServices = { uiSettings: { @@ -33,7 +33,7 @@ jest.mock('../../hooks/use_discover_services', () => { }; }); -const rowsSource: ElasticSearchHit[] = [ +const rowsSource: EsHitRecord[] = [ { _id: '1', _index: 'test', @@ -45,7 +45,7 @@ const rowsSource: ElasticSearchHit[] = [ }, ]; -const rowsFields: ElasticSearchHit[] = [ +const rowsFields: EsHitRecord[] = [ { _id: '1', _index: 'test', @@ -58,7 +58,7 @@ const rowsFields: ElasticSearchHit[] = [ }, ]; -const rowsFieldsWithTopLevelObject: ElasticSearchHit[] = [ +const rowsFieldsWithTopLevelObject: EsHitRecord[] = [ { _id: '1', _index: 'test', @@ -71,16 +71,13 @@ const rowsFieldsWithTopLevelObject: ElasticSearchHit[] = [ }, ]; -const flatten = (hit: ElasticSearchHit): Record => { - return flattenHit(hit, indexPatternMock); -}; +const build = (hit: EsHitRecord) => buildDataTableRecord(hit, indexPatternMock); describe('Discover grid cell rendering', function () { it('renders bytes column correctly', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsSource, - rowsSource.map(flatten), + rowsSource.map(build), false, [], 100, @@ -105,8 +102,7 @@ describe('Discover grid cell rendering', function () { it('renders bytes column correctly using _source when details is true', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsSource, - rowsSource.map(flatten), + rowsSource.map(build), false, [], 100, @@ -132,8 +128,7 @@ describe('Discover grid cell rendering', function () { const closePopoverMockFn = jest.fn(); const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFields, - rowsFields.map(flatten), + rowsFields.map(build), false, [], 100, @@ -160,8 +155,7 @@ describe('Discover grid cell rendering', function () { it('renders _source column correctly', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsSource, - rowsSource.map(flatten), + rowsSource.map(build), false, ['extension', 'bytes'], 100, @@ -235,8 +229,7 @@ describe('Discover grid cell rendering', function () { it('renders _source column correctly when isDetails is set to true', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsSource, - rowsSource.map(flatten), + rowsSource.map(build), false, [], 100, @@ -309,8 +302,7 @@ describe('Discover grid cell rendering', function () { it('renders fields-based column correctly', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFields, - rowsFields.map(flatten), + rowsFields.map(build), true, ['extension', 'bytes'], 100, @@ -388,8 +380,7 @@ describe('Discover grid cell rendering', function () { it('limits amount of rendered items', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFields, - rowsFields.map(flatten), + rowsFields.map(build), true, ['extension', 'bytes'], // this is the number of rendered items @@ -468,8 +459,7 @@ describe('Discover grid cell rendering', function () { it('renders fields-based column correctly when isDetails is set to true', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFields, - rowsFields.map(flatten), + rowsFields.map(build), true, [], 100, @@ -547,8 +537,7 @@ describe('Discover grid cell rendering', function () { it('collect object fields and renders them like _source', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFieldsWithTopLevelObject, - rowsFieldsWithTopLevelObject.map(flatten), + rowsFieldsWithTopLevelObject.map(build), true, ['object.value', 'extension', 'bytes'], 100, @@ -590,8 +579,7 @@ describe('Discover grid cell rendering', function () { (indexPatternMock.getFieldByName as jest.Mock).mockReturnValueOnce(undefined); const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFieldsWithTopLevelObject, - rowsFieldsWithTopLevelObject.map(flatten), + rowsFieldsWithTopLevelObject.map(build), true, ['extension', 'bytes', 'object.value'], 100, @@ -633,8 +621,7 @@ describe('Discover grid cell rendering', function () { const closePopoverMockFn = jest.fn(); const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFieldsWithTopLevelObject, - rowsFieldsWithTopLevelObject.map(flatten), + rowsFieldsWithTopLevelObject.map(build), true, [], 100, @@ -699,8 +686,7 @@ describe('Discover grid cell rendering', function () { const closePopoverMockFn = jest.fn(); const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFieldsWithTopLevelObject, - rowsFieldsWithTopLevelObject.map(flatten), + rowsFieldsWithTopLevelObject.map(build), true, [], 100, @@ -728,8 +714,7 @@ describe('Discover grid cell rendering', function () { (indexPatternMock.getFieldByName as jest.Mock).mockReturnValueOnce(undefined); const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFieldsWithTopLevelObject, - rowsFieldsWithTopLevelObject.map(flatten), + rowsFieldsWithTopLevelObject.map(build), true, [], 100, @@ -763,8 +748,7 @@ describe('Discover grid cell rendering', function () { it('renders correctly when invalid row is given', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsSource, - rowsSource.map(flatten), + rowsSource.map(build), false, [], 100, @@ -789,8 +773,7 @@ describe('Discover grid cell rendering', function () { it('renders correctly when invalid column is given', () => { const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsSource, - rowsSource.map(flatten), + rowsSource.map(build), false, [], 100, @@ -814,7 +797,7 @@ describe('Discover grid cell rendering', function () { it('renders unmapped fields correctly', () => { (indexPatternMock.getFieldByName as jest.Mock).mockReturnValueOnce(undefined); - const rowsFieldsUnmapped: ElasticSearchHit[] = [ + const rowsFieldsUnmapped: EsHitRecord[] = [ { _id: '1', _index: 'test', @@ -828,8 +811,7 @@ describe('Discover grid cell rendering', function () { ]; const DiscoverGridCellValue = getRenderCellValueFn( indexPatternMock, - rowsFieldsUnmapped, - rowsFieldsUnmapped.map(flatten), + rowsFieldsUnmapped.map(build), true, ['unmapped'], 100, diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx index b129b57dbec9c..5636e31efff5c 100644 --- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx +++ b/src/plugins/discover/public/components/discover_grid/get_render_cell_value.tsx @@ -24,10 +24,9 @@ import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { DiscoverGridContext } from './discover_grid_context'; import { JsonCodeEditor } from '../json_code_editor/json_code_editor'; import { defaultMonacoEditorWidth } from './constants'; -import { EsHitRecord } from '../../application/types'; import { formatFieldValue } from '../../utils/format_value'; import { formatHit } from '../../utils/format_hit'; -import { ElasticSearchHit, HitsFlattened } from '../../types'; +import { DataTableRecord, EsHitRecord } from '../../types'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { MAX_DOC_FIELDS_DISPLAYED } from '../../../common'; @@ -36,8 +35,7 @@ const CELL_CLASS = 'dscDiscoverGrid__cellValue'; export const getRenderCellValueFn = ( dataView: DataView, - rows: ElasticSearchHit[] | undefined, - rowsFlattened: HitsFlattened, + rows: DataTableRecord[] | undefined, useNewFieldsApi: boolean, fieldsToShow: string[], maxDocFieldsDisplayed: number, @@ -49,24 +47,16 @@ export const getRenderCellValueFn = const maxEntries = useMemo(() => uiSettings.get(MAX_DOC_FIELDS_DISPLAYED), [uiSettings]); const row = rows ? rows[rowIndex] : undefined; - const rowFlattened = rowsFlattened - ? (rowsFlattened[rowIndex] as Record) - : undefined; const field = dataView.fields.getByName(columnId); const ctx = useContext(DiscoverGridContext); useEffect(() => { - if ((row as EsHitRecord).isAnchor) { + if (row?.isAnchor) { setCellProps({ className: 'dscDocsGrid__cell--highlight', }); - } else if ( - ctx.expanded && - row && - ctx.expanded._id === row._id && - ctx.expanded._index === row._index - ) { + } else if (ctx.expanded && row && ctx.expanded.id === row.id) { setCellProps({ style: { backgroundColor: ctx.isDarkMode @@ -79,7 +69,7 @@ export const getRenderCellValueFn = } }, [ctx, row, setCellProps]); - if (typeof row === 'undefined' || typeof rowFlattened === 'undefined') { + if (typeof row === 'undefined') { return -; } @@ -90,14 +80,13 @@ export const getRenderCellValueFn = const useTopLevelObjectColumns = Boolean( useNewFieldsApi && !field && - row?.fields && - !(row.fields as Record)[columnId] + row?.raw.fields && + !(row.raw.fields as Record)[columnId] ); if (isDetails) { return renderPopoverContent({ - rowRaw: row, - rowFlattened, + row, field, columnId, dataView, @@ -109,7 +98,7 @@ export const getRenderCellValueFn = if (field?.type === '_source' || useTopLevelObjectColumns) { const pairs = useTopLevelObjectColumns - ? getTopLevelObjectPairs(row, columnId, dataView, fieldsToShow).slice( + ? getTopLevelObjectPairs(row.raw, columnId, dataView, fieldsToShow).slice( 0, maxDocFieldsDisplayed ) @@ -140,7 +129,7 @@ export const getRenderCellValueFn = // formatFieldValue guarantees sanitized values // eslint-disable-next-line react/no-danger dangerouslySetInnerHTML={{ - __html: formatFieldValue(rowFlattened[columnId], row, fieldFormats, dataView, field), + __html: formatFieldValue(row.flattened[columnId], row.raw, fieldFormats, dataView, field), }} /> ); @@ -158,10 +147,10 @@ function getInnerColumns(fields: Record, columnId: string) { ); } -function getJSON(columnId: string, rowRaw: ElasticSearchHit, useTopLevelObjectColumns: boolean) { +function getJSON(columnId: string, row: DataTableRecord, useTopLevelObjectColumns: boolean) { const json = useTopLevelObjectColumns - ? getInnerColumns(rowRaw.fields as Record, columnId) - : rowRaw; + ? getInnerColumns(row.raw.fields as Record, columnId) + : row.raw; return json as Record; } @@ -169,8 +158,7 @@ function getJSON(columnId: string, rowRaw: ElasticSearchHit, useTopLevelObjectCo * Helper function for the cell popover */ function renderPopoverContent({ - rowRaw, - rowFlattened, + row, field, columnId, dataView, @@ -178,8 +166,7 @@ function renderPopoverContent({ fieldFormats, closePopover, }: { - rowRaw: ElasticSearchHit; - rowFlattened: Record; + row: DataTableRecord; field: DataViewField | undefined; columnId: string; dataView: DataView; @@ -209,7 +196,7 @@ function renderPopoverContent({ @@ -226,7 +213,13 @@ function renderPopoverContent({ // formatFieldValue guarantees sanitized values // eslint-disable-next-line react/no-danger dangerouslySetInnerHTML={{ - __html: formatFieldValue(rowFlattened[columnId], rowRaw, fieldFormats, dataView, field), + __html: formatFieldValue( + row.flattened[columnId], + row.raw, + fieldFormats, + dataView, + field + ), }} /> @@ -239,7 +232,7 @@ function renderPopoverContent({ * this is used for legacy stuff like displaying products of our ecommerce dataset */ function getTopLevelObjectPairs( - row: ElasticSearchHit, + row: EsHitRecord, columnId: string, dataView: DataView, fieldsToShow: string[] diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx index 03a12428569f7..1101c01784e84 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx @@ -17,6 +17,8 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { discoverServiceMock } from '../../../__mocks__/services'; import { DOC_HIDE_TIME_COLUMN_SETTING, MAX_DOC_FIELDS_DISPLAYED } from '../../../../common'; +import { buildDataTableRecord } from '../../../utils/build_data_record'; +import { EsHitRecord } from '../../../types'; jest.mock('../utils/row_formatter', () => { const originalModule = jest.requireActual('../utils/row_formatter'); @@ -64,7 +66,7 @@ const mockHit = { }, ], _source: { message: 'mock_message', bytes: 20 }, -}; +} as unknown as EsHitRecord; const mockFilterManager = createFilterManagerMock(); @@ -74,7 +76,7 @@ describe('Doc table row component', () => { columns: ['_source'], filter: mockInlineFilter, indexPattern: indexPatternWithTimefieldMock, - row: mockHit, + row: buildDataTableRecord(mockHit, indexPatternWithTimefieldMock), useNewFieldsApi: true, filterManager: mockFilterManager, addBasePath: (path: string) => path, diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.tsx index e08843006020a..898cb25417403 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_row.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_row.tsx @@ -10,7 +10,6 @@ import React, { Fragment, useCallback, useMemo, useState } from 'react'; import classNames from 'classnames'; import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty, EuiIcon } from '@elastic/eui'; -import { flattenHit } from '@kbn/data-plugin/public'; import { DataView } from '@kbn/data-views-plugin/public'; import { formatFieldValue } from '../../../utils/format_value'; import { DocViewer } from '../../../services/doc_views/components/doc_viewer'; @@ -18,19 +17,19 @@ import { TableCell } from './table_row/table_cell'; import { formatRow, formatTopLevelObject } from '../utils/row_formatter'; import { useNavigationProps } from '../../../hooks/use_navigation_props'; import { DocViewFilterFn } from '../../../services/doc_views/doc_views_types'; -import { ElasticSearchHit } from '../../../types'; +import { DataTableRecord, EsHitRecord } from '../../../types'; import { TableRowDetails } from './table_row_details'; import { useDiscoverServices } from '../../../hooks/use_discover_services'; import { DOC_HIDE_TIME_COLUMN_SETTING, MAX_DOC_FIELDS_DISPLAYED } from '../../../../common'; -export type DocTableRow = ElasticSearchHit & { +export type DocTableRow = EsHitRecord & { isAnchor?: boolean; }; export interface TableRowProps { columns: string[]; filter: DocViewFilterFn; - row: DocTableRow; + row: DataTableRecord; indexPattern: DataView; useNewFieldsApi: boolean; fieldsToShow: string[]; @@ -62,10 +61,6 @@ export const TableRow = ({ }); const anchorDocTableRowSubj = row.isAnchor ? ' docTableAnchorRow' : ''; - const flattenedRow = useMemo( - () => flattenHit(row, indexPattern, { includeIgnoredValues: true }), - [indexPattern, row] - ); const mapping = useMemo(() => indexPattern.fields.getByName, [indexPattern]); // toggle display of the rows details, a full list of the fields from each row @@ -82,8 +77,8 @@ export const TableRow = ({ } const formattedField = formatFieldValue( - flattenedRow[fieldName], - row, + row.flattened[fieldName], + row.raw, fieldFormats, indexPattern, mapping(fieldName) @@ -98,15 +93,15 @@ export const TableRow = ({ const inlineFilter = useCallback( (column: string, type: '+' | '-') => { const field = indexPattern.fields.getByName(column); - filter(field!, flattenedRow[column], type); + filter(field!, row.flattened, type); }, - [filter, flattenedRow, indexPattern.fields] + [filter, indexPattern.fields, row.flattened] ); const { singleDocProps, surrDocsProps } = useNavigationProps({ indexPatternId: indexPattern.id!, - rowIndex: row._index, - rowId: row._id, + rowIndex: row.raw._index, + rowId: row.raw._id, filterManager, addBasePath, columns, @@ -161,9 +156,9 @@ export const TableRow = ({ ); } else { columns.forEach(function (column: string) { - if (useNewFieldsApi && !mapping(column) && row.fields && !row.fields[column]) { + if (useNewFieldsApi && !mapping(column) && row.raw.fields && !row.raw.fields[column]) { const innerColumns = Object.fromEntries( - Object.entries(row.fields).filter(([key]) => { + Object.entries(row.raw.fields).filter(([key]) => { return key.indexOf(`${column}.`) === 0; }) ); @@ -185,7 +180,7 @@ export const TableRow = ({ // We should improve this and show a helpful tooltip why the filter buttons are not // there/disabled when there are ignored values. const isFilterable = Boolean( - mapping(column)?.filterable && filter && !row._ignored?.includes(column) + mapping(column)?.filterable && filter && !row.raw._ignored?.includes(column) ); rowCells.push( { - const mountComponent = (rows?: DocTableRow[]) => { + const mountComponent = (rows?: EsHitRecord[]) => { const props = { columns: ['_source'], indexPattern: indexPatternMock, - rows: rows || [ - { - _index: 'mock_index', - _id: '1', - _score: 1, - fields: [ - { - timestamp: '2020-20-01T12:12:12.123', - }, - ], - _source: { message: 'mock_message', bytes: 20 }, - }, - ], + rows: ( + rows || [ + { + _index: 'mock_index', + _id: '1', + _score: 1, + fields: [ + { + timestamp: '2020-20-01T12:12:12.123', + }, + ], + _source: { message: 'mock_message', bytes: 20 }, + } as EsHitRecord, + ] + ).map((row) => buildDataTableRecord(row, indexPatternMock)), + sort: [['order_date', 'desc']], isLoading: false, searchDescription: '', diff --git a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx index 3562337961417..e226c859fb0a1 100644 --- a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx +++ b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx @@ -13,16 +13,17 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { TableHeader } from './components/table_header/table_header'; import { SHOW_MULTIFIELDS } from '../../../common'; import { SortOrder } from './components/table_header/helpers'; -import { DocTableRow, TableRow } from './components/table_row'; +import { TableRow } from './components/table_row'; import { DocViewFilterFn } from '../../services/doc_views/doc_views_types'; import { getFieldsToShow } from '../../utils/get_fields_to_show'; import { useDiscoverServices } from '../../hooks/use_discover_services'; +import type { DataTableRecord } from '../../types'; export interface DocTableProps { /** * Rows of classic table */ - rows: DocTableRow[]; + rows: DataTableRecord[]; /** * Columns of classic table */ @@ -79,8 +80,8 @@ export interface DocTableProps { export interface DocTableRenderProps { columnLength: number; - rows: DocTableRow[]; - renderRows: (row: DocTableRow[]) => JSX.Element[]; + rows: DataTableRecord[]; + renderRows: (row: DataTableRecord[]) => JSX.Element[]; renderHeader: () => JSX.Element; onSkipBottomButtonClick: () => void; } @@ -155,10 +156,10 @@ export const DocTableWrapper = forwardRef( ); const renderRows = useCallback( - (rowsToRender: DocTableRow[]) => { + (rowsToRender: DataTableRecord[]) => { return rowsToRender.map((current) => ( { - const hit = { - _id: 'a', - _index: 'foo', - _type: 'doc', - _score: 1, - _source: { - foo: 'bar', - number: 42, - hello: '

World

', - also: 'with "quotes" or \'single quotes\'', - }, - }; let services: DiscoverServices; const createIndexPattern = () => { @@ -45,6 +34,18 @@ describe('Row formatter', () => { }; const indexPattern = createIndexPattern(); + const rawHit = { + _id: 'a', + _index: 'foo', + _score: 1, + _source: { + foo: 'bar', + number: 42, + hello: '

World

', + also: 'with "quotes" or \'single quotes\'', + }, + }; + const hit = buildDataTableRecord(rawHit, indexPattern); const fieldsToShow = indexPattern.fields.getAll().map((fld) => fld.name); @@ -138,15 +139,13 @@ describe('Row formatter', () => { }); it('formats document with highlighted fields first', () => { - expect( - formatRow( - { ...hit, highlight: { number: ['42'] } }, - indexPattern, - fieldsToShow, - 100, - services.fieldFormats - ) - ).toMatchInlineSnapshot(` + const highLightHit = buildDataTableRecord( + { ...rawHit, highlight: { number: ['42'] } }, + indexPattern + ); + + expect(formatRow(highLightHit, indexPattern, fieldsToShow, 100, services.fieldFormats)) + .toMatchInlineSnapshot(` { }; export const formatRow = ( - hit: estypes.SearchHit, + hit: DataTableRecord, indexPattern: DataView, fieldsToShow: string[], maxEntries: number, @@ -65,7 +65,7 @@ export const formatTopLevelObject = ( const displayKey = fields.getByName ? fields.getByName(key)?.displayName : undefined; const formatter = field ? indexPattern.getFormatterForField(field) - : { convert: (v: unknown, ...rest: unknown[]) => String(v) }; + : { convert: (v: unknown, ..._: unknown[]) => String(v) }; if (!values.map) return; const formatted = values .map((val: unknown) => diff --git a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx index 0cd179768df0a..cc6557e50e668 100644 --- a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx @@ -27,6 +27,8 @@ import { ISearchSource } from '@kbn/data-plugin/public'; import { DataView, DataViewField } from '@kbn/data-views-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { buildDataTableRecord } from '../utils/build_data_record'; +import { DataTableRecord } from '../types'; import { ISearchEmbeddable, SearchInput, SearchOutput } from './types'; import { SavedSearch } from '../services/saved_searches'; import { SEARCH_EMBEDDABLE_TYPE } from './constants'; @@ -50,7 +52,6 @@ import { SortOrder } from '../components/doc_table/components/table_header/helpe import { VIEW_MODE } from '../components/view_mode_toggle'; import { updateSearchSource } from './utils/update_search_source'; import { FieldStatisticsTable } from '../application/main/components/field_stats_table'; -import { ElasticSearchHit } from '../types'; export type SearchProps = Partial & Partial & { @@ -59,9 +60,8 @@ export type SearchProps = Partial & sharedItemTitle?: string; inspectorAdapters?: Adapters; services: DiscoverServices; - filter?: (field: DataViewField, value: string[], operator: string) => void; - hits?: ElasticSearchHit[]; + hits?: DataTableRecord[]; totalHitCount?: number; onMoveColumn?: (column: string, index: number) => void; onUpdateRowHeight?: (rowHeight?: number) => void; @@ -131,12 +131,15 @@ export class SavedSearchEmbeddable this.inspectorAdapters = { requests: new RequestAdapter(), }; + this.panelTitle = savedSearch.title ?? ''; this.initializeSearchEmbeddableProps(); this.subscription = this.getUpdated$().subscribe(() => { - this.panelTitle = this.output.title || ''; - - if (this.searchProps) { + const titleChanged = this.output.title && this.panelTitle !== this.output.title; + if (titleChanged) { + this.panelTitle = this.output.title || ''; + } + if (this.searchProps && (titleChanged || this.isFetchRequired(this.searchProps))) { this.pushContainerStateParamsToProps(this.searchProps); } }); @@ -207,7 +210,9 @@ export class SavedSearchEmbeddable ); this.updateOutput({ loading: false, error: undefined }); - this.searchProps!.rows = resp.hits.hits; + this.searchProps!.rows = resp.hits.hits.map((hit) => + buildDataTableRecord(hit, this.searchProps!.indexPattern) + ); this.searchProps!.totalHitCount = resp.hits.total as number; this.searchProps!.isLoading = false; } catch (error) { @@ -329,16 +334,24 @@ export class SavedSearchEmbeddable } } - private async pushContainerStateParamsToProps( - searchProps: SearchProps, - { forceFetch = false }: { forceFetch: boolean } = { forceFetch: false } - ) { - const isFetchRequired = + private isFetchRequired(searchProps?: SearchProps) { + if (!searchProps) { + return false; + } + return ( !onlyDisabledFiltersChanged(this.input.filters, this.prevFilters) || !isEqual(this.prevQuery, this.input.query) || !isEqual(this.prevTimeRange, this.input.timeRange) || !isEqual(searchProps.sort, this.input.sort || this.savedSearch.sort) || - this.prevSearchSessionId !== this.input.searchSessionId; + this.prevSearchSessionId !== this.input.searchSessionId + ); + } + + private async pushContainerStateParamsToProps( + searchProps: SearchProps, + { forceFetch = false }: { forceFetch: boolean } = { forceFetch: false } + ) { + const isFetchRequired = this.isFetchRequired(searchProps); // If there is column or sort data on the panel, that means the original columns or sort settings have // been overridden in a dashboard. @@ -393,7 +406,7 @@ export class SavedSearchEmbeddable } private renderReactComponent(domNode: HTMLElement, searchProps: SearchProps) { - if (!this.searchProps) { + if (!searchProps) { return; } diff --git a/src/plugins/discover/public/embeddable/saved_search_grid.tsx b/src/plugins/discover/public/embeddable/saved_search_grid.tsx index ff72ed378aff3..7c567dc75dfa3 100644 --- a/src/plugins/discover/public/embeddable/saved_search_grid.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_grid.tsx @@ -7,9 +7,9 @@ */ import React, { useState, memo } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { DataTableRecord } from '../types'; import { DiscoverGrid, DiscoverGridProps } from '../components/discover_grid/discover_grid'; import { TotalDocuments } from '../application/main/components/total_documents/total_documents'; -import { ElasticSearchHit } from '../types'; export interface DiscoverGridEmbeddableProps extends DiscoverGridProps { totalHitCount: number; @@ -18,7 +18,7 @@ export interface DiscoverGridEmbeddableProps extends DiscoverGridProps { export const DataGridMemoized = memo(DiscoverGrid); export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) { - const [expandedDoc, setExpandedDoc] = useState(undefined); + const [expandedDoc, setExpandedDoc] = useState(undefined); return ( helper / hook', () => { getComputedFields: () => [], }; - const record = { test: 1 }; + const record = { _id: '1', _index: 't', test: 1 }; const props = { id: '1', @@ -233,6 +234,9 @@ describe('Test of helper / hook', () => { await hook.waitForNextUpdate(); }); - expect(hook.result.current.slice(0, 2)).toEqual([ElasticRequestState.Found, record]); + expect(hook.result.current.slice(0, 2)).toEqual([ + ElasticRequestState.Found, + buildDataTableRecord(record), + ]); }); }); diff --git a/src/plugins/discover/public/hooks/use_es_doc_search.ts b/src/plugins/discover/public/hooks/use_es_doc_search.ts index 84e759962de04..06c50af8e3889 100644 --- a/src/plugins/discover/public/hooks/use_es_doc_search.ts +++ b/src/plugins/discover/public/hooks/use_es_doc_search.ts @@ -10,10 +10,11 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { lastValueFrom } from 'rxjs'; import { DataView } from '@kbn/data-views-plugin/public'; +import { buildDataTableRecord } from '../utils/build_data_record'; +import { DataTableRecord } from '../types'; import { DocProps } from '../application/doc/components/doc'; import { ElasticRequestState } from '../application/doc/types'; import { SEARCH_FIELDS_FROM_SOURCE } from '../../common'; -import { ElasticSearchHit } from '../types'; import { useDiscoverServices } from './use_discover_services'; type RequestBody = Pick; @@ -26,9 +27,9 @@ export function useEsDocSearch({ index, indexPattern, requestSource, -}: DocProps): [ElasticRequestState, ElasticSearchHit | null, () => void] { +}: DocProps): [ElasticRequestState, DataTableRecord | null, () => void] { const [status, setStatus] = useState(ElasticRequestState.Loading); - const [hit, setHit] = useState(null); + const [hit, setHit] = useState(null); const { data, uiSettings } = useDiscoverServices(); const useNewFieldsApi = useMemo(() => !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE), [uiSettings]); @@ -48,7 +49,7 @@ export function useEsDocSearch({ if (hits?.hits?.[0]) { setStatus(ElasticRequestState.Found); - setHit(hits.hits[0]); + setHit(buildDataTableRecord(hits.hits[0], indexPattern)); } else { setStatus(ElasticRequestState.NotFound); } diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 24da9869238b0..e9eaba11d048c 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -241,8 +241,8 @@ export class DiscoverPlugin } > diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx index 6d0018f695a33..41d483cb667c8 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer.test.tsx @@ -12,6 +12,7 @@ import { DocViewer } from './doc_viewer'; import { findTestSubject } from '@elastic/eui/lib/test'; import { getDocViewsRegistry } from '../../../../kibana_services'; import { DocViewRenderProps } from '../../doc_views_types'; +import { buildDataTableRecord } from '../../../../utils/build_data_record'; jest.mock('../../../../kibana_services', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -75,7 +76,9 @@ test('Render with 1 tab displaying error message', () => { component: SomeComponent, }); - const renderProps = { hit: {} } as DocViewRenderProps; + const renderProps = { + hit: buildDataTableRecord({ _index: 't', _id: '1' }), + } as DocViewRenderProps; const errorMsg = 'Catch me if you can!'; const wrapper = mount(); diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.test.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.test.tsx index 1d5b1d4577652..af0bda4b67713 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.test.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.test.tsx @@ -10,17 +10,18 @@ import React from 'react'; import { shallow } from 'enzyme'; import { DocViewerTab } from './doc_viewer_tab'; import { indexPatternMock } from '../../../../__mocks__/index_pattern'; -import { ElasticSearchHit } from '../../../../types'; +import { buildDataTableRecord } from '../../../../utils/build_data_record'; describe('DocViewerTab', () => { test('changing columns triggers an update', () => { + const hit = buildDataTableRecord({ _index: 'test', _id: '1' }, indexPatternMock); const props = { title: 'test', component: jest.fn(), id: 1, render: jest.fn(), renderProps: { - hit: {} as ElasticSearchHit, + hit, columns: ['test'], indexPattern: indexPatternMock, }, @@ -31,7 +32,7 @@ describe('DocViewerTab', () => { const nextProps = { ...props, renderProps: { - hit: {} as ElasticSearchHit, + hit, columns: ['test2'], indexPattern: indexPatternMock, }, diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx index 0ad3187e1cf4f..837ee910176b9 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer/doc_viewer_tab.tsx @@ -42,9 +42,8 @@ export class DocViewerTab extends React.Component { shouldComponentUpdate(nextProps: Props, nextState: State) { return ( - nextProps.renderProps.hit._id !== this.props.renderProps.hit._id || - nextProps.renderProps.hit._index !== this.props.renderProps.hit._index || - !isEqual(nextProps.renderProps.hit.highlight, this.props.renderProps.hit.highlight) || + nextProps.renderProps.hit.id !== this.props.renderProps.hit.id || + !isEqual(nextProps.renderProps.hit.raw.highlight, this.props.renderProps.hit.raw.highlight) || nextProps.id !== this.props.id || !isEqual(nextProps.renderProps.columns, this.props.renderProps.columns) || nextState.hasError diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/__snapshots__/source.test.tsx.snap b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/__snapshots__/source.test.tsx.snap deleted file mode 100644 index c639e60dd9a7c..0000000000000 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/__snapshots__/source.test.tsx.snap +++ /dev/null @@ -1,128 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Source Viewer component renders error state 1`] = ` -
-
-
- -
-
-
-

- An Error Occurred -

-
-
-
- Could not fetch data at this time. Refresh the tab to try again. -
- -
-
-
-
-
-
-`; - -exports[`Source Viewer component renders json code editor 1`] = ` -
-
-
-
- - - -
-
-
-
-
-
-`; - -exports[`Source Viewer component renders loading state 1`] = ` -
- -
- Loading JSON -
-
-`; diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.test.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.test.tsx index 2f08caa4f6817..f51ddd13f1afe 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.test.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.test.tsx @@ -15,6 +15,7 @@ import * as useUiSettingHook from '@kbn/kibana-react-plugin/public/ui_settings/u import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui'; import { JsonCodeEditorCommon } from '../../../../components/json_code_editor/json_code_editor_common'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { buildDataTableRecord } from '../../../../utils/build_data_record'; const mockIndexPattern = { getComputedFields: () => [], @@ -51,7 +52,6 @@ describe('Source Viewer component', () => { /> ); - expect(comp.children().render()).toMatchSnapshot(); const loadingIndicator = comp.find(EuiLoadingSpinner); expect(loadingIndicator).not.toBe(null); }); @@ -70,7 +70,6 @@ describe('Source Viewer component', () => { /> ); - expect(comp.children().render()).toMatchSnapshot(); const errorPrompt = comp.find(EuiEmptyPrompt); expect(errorPrompt.length).toBe(1); const refreshButton = comp.find(EuiButton); @@ -78,9 +77,8 @@ describe('Source Viewer component', () => { }); test('renders json code editor', () => { - const mockHit = { + const mockHit = buildDataTableRecord({ _index: 'logstash-2014.09.09', - _type: 'doc', _id: 'id123', _score: 1, _source: { @@ -95,7 +93,7 @@ describe('Source Viewer component', () => { scripted: 123, _underscore: 123, }, - } as never; + }); jest.spyOn(hooks, 'useEsDocSearch').mockImplementation(() => [2, mockHit, () => {}]); jest.spyOn(useUiSettingHook, 'useUiSetting').mockImplementation(() => { return false; @@ -111,7 +109,6 @@ describe('Source Viewer component', () => { /> ); - expect(comp.children().render()).toMatchSnapshot(); const jsonCodeEditor = comp.find(JsonCodeEditorCommon); expect(jsonCodeEditor).not.toBe(null); }); diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx index cbc14c9382e1c..ade467df853b0 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_source/source.tsx @@ -56,7 +56,7 @@ export const DocViewerSource = ({ useEffect(() => { if (reqState === ElasticRequestState.Found && hit) { - setJsonValue(JSON.stringify(hit, undefined, 2)); + setJsonValue(JSON.stringify(hit.raw, undefined, 2)); } }, [reqState, hit]); diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx index 0e75ab7d7800d..053af6643eb79 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.test.tsx @@ -12,9 +12,9 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { DocViewerLegacyTable } from './table'; import { DataView } from '@kbn/data-views-plugin/public'; import { DocViewRenderProps } from '../../../doc_views_types'; -import { ElasticSearchHit } from '../../../../../types'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { DiscoverServices } from '../../../../../build_services'; +import { buildDataTableRecord } from '../../../../../utils/build_data_record'; const services = { uiSettings: { @@ -85,14 +85,14 @@ describe('DocViewTable at Discover', () => { // At Discover's main view, all buttons are rendered // check for existence of action buttons and warnings - const hit = { - _index: 'logstash-2014.09.09', - _type: 'doc', - _id: 'id123', - _score: 1, - _source: { - message: - 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ + const hit = buildDataTableRecord( + { + _index: 'logstash-2014.09.09', + _id: 'id123', + _score: 1, + _source: { + message: + 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus \ et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, \ ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. \ @@ -100,17 +100,19 @@ describe('DocViewTable at Discover', () => { rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. \ Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. \ Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut', - extension: 'html', - not_mapped: 'yes', - bytes: 100, - objectArray: [{ foo: true }], - relatedContent: { - test: 1, + extension: 'html', + not_mapped: 'yes', + bytes: 100, + objectArray: [{ foo: true }], + relatedContent: { + test: 1, + }, + scripted: 123, + _underscore: 123, }, - scripted: 123, - _underscore: 123, }, - } as ElasticSearchHit; + indexPattern + ); const props = { hit, @@ -194,14 +196,14 @@ describe('DocViewTable at Discover', () => { describe('DocViewTable at Discover Context', () => { // here no toggleColumnButtons are rendered - const hit = { - _index: 'logstash-2014.09.09', - _type: 'doc', - _id: 'id123', - _score: 1, - _source: { - message: - 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ + const hit = buildDataTableRecord( + { + _index: 'logstash-2014.09.09', + _id: 'id123', + _score: 1, + _source: { + message: + 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus \ et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, \ ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. \ @@ -209,8 +211,10 @@ describe('DocViewTable at Discover Context', () => { rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. \ Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. \ Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut', + }, }, - } as ElasticSearchHit; + indexPattern + ); const props = { hit, columns: ['extension'], @@ -246,16 +250,18 @@ describe('DocViewTable at Discover Context', () => { }); describe('DocViewTable at Discover Doc', () => { - const hit = { - _index: 'logstash-2014.09.09', - _score: 1, - _type: 'doc', - _id: 'id123', - _source: { - extension: 'html', - not_mapped: 'yes', + const hit = buildDataTableRecord( + { + _index: 'logstash-2014.09.09', + _score: 1, + _id: 'id123', + _source: { + extension: 'html', + not_mapped: 'yes', + }, }, - }; + indexPattern + ); // here no action buttons are rendered const props = { hit, @@ -370,20 +376,22 @@ describe('DocViewTable at Discover Doc with Fields API', () => { return indexPatterneCommerce.fields.getAll().find((field) => field.name === name); }; - const fieldsHit = { - _index: 'logstash-2014.09.09', - _type: 'doc', - _id: 'id123', - _score: 1.0, - fields: { - category: "Women's Clothing", - 'category.keyword': "Women's Clothing", - customer_first_name: 'Betty', - 'customer_first_name.keyword': 'Betty', - 'customer_first_name.nickname': 'Betsy', - 'city.raw': 'Los Angeles', + const fieldsHit = buildDataTableRecord( + { + _index: 'logstash-2014.09.09', + _id: 'id123', + _score: 1.0, + fields: { + category: "Women's Clothing", + 'category.keyword': "Women's Clothing", + customer_first_name: 'Betty', + 'customer_first_name.keyword': 'Betty', + 'customer_first_name.nickname': 'Betsy', + 'city.raw': 'Los Angeles', + }, }, - }; + indexPattern + ); const props = { hit: fieldsHit, columns: ['Document'], diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx index 152a5451e7760..ad4345a79b166 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/legacy/table.tsx @@ -9,7 +9,6 @@ import '../table.scss'; import React, { useCallback, useMemo } from 'react'; import { EuiInMemoryTable } from '@elastic/eui'; -import { flattenHit } from '@kbn/data-plugin/public'; import { getTypeForFieldIcon } from '../../../../../utils/get_type_for_field_icon'; import { useDiscoverServices } from '../../../../../hooks/use_discover_services'; import { SHOW_MULTIFIELDS } from '../../../../../../common'; @@ -57,10 +56,9 @@ export const DocViewerLegacyTable = ({ }; }, []); - const flattened = flattenHit(hit, dataView, { source: true, includeIgnoredValues: true }); - const fieldsToShow = getFieldsToShow(Object.keys(flattened), dataView, showMultiFields); + const fieldsToShow = getFieldsToShow(Object.keys(hit.flattened), dataView, showMultiFields); - const items: FieldRecordLegacy[] = Object.keys(flattened) + const items: FieldRecordLegacy[] = Object.keys(hit.flattened) .filter((fieldName) => { return fieldsToShow.includes(fieldName); }) @@ -79,13 +77,13 @@ export const DocViewerLegacyTable = ({ : fieldMapping ? getTypeForFieldIcon(fieldMapping) : undefined; - const ignored = getIgnoredReason(fieldMapping ?? field, hit._ignored); + const ignored = getIgnoredReason(fieldMapping ?? field, hit.raw._ignored); return { action: { onToggleColumn, onFilter: filter, isActive: !!columns?.includes(field), - flattenedField: flattened[field], + flattenedField: hit.flattened[field], }, field: { field, @@ -96,8 +94,8 @@ export const DocViewerLegacyTable = ({ }, value: { formattedValue: formatFieldValue( - flattened[field], - hit, + hit.flattened[field], + hit.raw, fieldFormats, dataView, fieldMapping diff --git a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx index 48a869c86d3e8..7e61918aa7ae8 100644 --- a/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx +++ b/src/plugins/discover/public/services/doc_views/components/doc_viewer_table/table.tsx @@ -28,7 +28,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { debounce } from 'lodash'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { flattenHit } from '@kbn/data-plugin/public'; import { getTypeForFieldIcon } from '../../../../utils/get_type_for_field_icon'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; import { usePager } from '../../../../hooks/use_pager'; @@ -119,7 +118,7 @@ export const DocViewerTable = ({ getPinnedFields(currentDataViewId, storage) ); - const flattened = flattenHit(hit, dataView, { source: true, includeIgnoredValues: true }); + const flattened = hit.flattened; const fieldsToShow = getFieldsToShow(Object.keys(flattened), dataView, showMultiFields); const searchPlaceholder = i18n.translate('discover.docView.table.searchPlaceHolder', { @@ -164,7 +163,7 @@ export const DocViewerTable = ({ ? getTypeForFieldIcon(fieldMapping) : undefined; - const ignored = getIgnoredReason(fieldMapping ?? field, hit._ignored); + const ignored = getIgnoredReason(fieldMapping ?? field, hit.raw._ignored); return { action: { @@ -184,8 +183,8 @@ export const DocViewerTable = ({ }, value: { formattedValue: formatFieldValue( - flattened[field], - hit, + hit.flattened[field], + hit.raw, fieldFormats, dataView, fieldMapping diff --git a/src/plugins/discover/public/services/doc_views/doc_views_registry.ts b/src/plugins/discover/public/services/doc_views/doc_views_registry.ts index 8ee8741d73d3f..d6bf89c5fef70 100644 --- a/src/plugins/discover/public/services/doc_views/doc_views_registry.ts +++ b/src/plugins/discover/public/services/doc_views/doc_views_registry.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { ElasticSearchHit } from '../../types'; import { DocView, DocViewInput, DocViewInputFn } from './doc_views_types'; +import { DataTableRecord } from '../../types'; export class DocViewsRegistry { private docViews: DocView[] = []; @@ -25,7 +25,7 @@ export class DocViewsRegistry { /** * Returns a sorted array of doc_views for rendering tabs */ - getDocViewsSorted(hit: ElasticSearchHit) { + getDocViewsSorted(hit: DataTableRecord) { return this.docViews .filter((docView) => docView.shouldShow(hit)) .sort((a, b) => (Number(a.order) > Number(b.order) ? 1 : -1)); diff --git a/src/plugins/discover/public/services/doc_views/doc_views_types.ts b/src/plugins/discover/public/services/doc_views/doc_views_types.ts index 171b29a86bb05..ca05bce452f91 100644 --- a/src/plugins/discover/public/services/doc_views/doc_views_types.ts +++ b/src/plugins/discover/public/services/doc_views/doc_views_types.ts @@ -7,7 +7,7 @@ */ import { DataView, DataViewField } from '@kbn/data-views-plugin/public'; -import { ElasticSearchHit } from '../../types'; +import { DataTableRecord } from '../../types'; import { IgnoredReason } from '../../utils/get_ignored_reason'; export interface FieldMapping { @@ -26,7 +26,7 @@ export type DocViewFilterFn = ( ) => void; export interface DocViewRenderProps { - hit: ElasticSearchHit; + hit: DataTableRecord; indexPattern: DataView; columns?: string[]; filter?: DocViewFilterFn; @@ -41,7 +41,7 @@ export type DocViewRenderFn = ( export interface BaseDocViewInput { order: number; - shouldShow?: (hit: ElasticSearchHit) => boolean; + shouldShow?: (hit: DataTableRecord) => boolean; title: string; } diff --git a/src/plugins/discover/public/types.ts b/src/plugins/discover/public/types.ts index fa8582337349d..f96edccb5f9bf 100644 --- a/src/plugins/discover/public/types.ts +++ b/src/plugins/discover/public/types.ts @@ -6,14 +6,35 @@ * Side Public License, v 1. */ -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; - -export type ElasticSearchHit = estypes.SearchHit; - -export type HitsFlattened = Array>; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; export type ValueToStringConverter = ( rowIndex: number, columnId: string, options?: { disableMultiline?: boolean } ) => { formattedString: string; withFormula: boolean }; + +export interface EsHitRecord extends Omit { + _source?: Record; +} +/** + * This is the record/row of data provided to our Data Table + */ +export interface DataTableRecord { + /** + * A unique id generated by index, id and routing of a record + */ + id: string; + /** + * The document returned by Elasticsearch for search queries + */ + raw: EsHitRecord; + /** + * A flattened version of the ES doc or data provided by SQL, aggregations ... + */ + flattened: Record; + /** + * Determines that the given doc is the anchor doc when rendering view surrounding docs + */ + isAnchor?: boolean; +} diff --git a/src/plugins/discover/public/utils/build_data_record.ts b/src/plugins/discover/public/utils/build_data_record.ts new file mode 100644 index 0000000000000..2691fddfb66a9 --- /dev/null +++ b/src/plugins/discover/public/utils/build_data_record.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DataView } from '@kbn/data-views-plugin/common'; +import { flattenHit } from '@kbn/data-plugin/common'; +import { getDocId } from './get_doc_id'; +import type { DataTableRecord, EsHitRecord } from '../types'; + +/** + * Build a record for data table, explorer + classic one + * @param doc the document returned from Elasticsearch + * @param dataView this current data view + * @param isAnchor determines if the given doc is the anchor doc when viewing surrounding documents + */ +export function buildDataTableRecord( + doc: EsHitRecord, + dataView?: DataView, + isAnchor?: boolean +): DataTableRecord { + return { + id: getDocId(doc), + raw: doc, + flattened: flattenHit(doc, dataView, { includeIgnoredValues: true }), + isAnchor, + }; +} + +/** + * Helper to build multiple DataTableRecords at once, saved a bit of testing code lines + * @param docs Array of documents returned from Elasticsearch + * @param dataView this current data view + */ +export function buildDataTableRecordList( + docs: EsHitRecord[], + dataView?: DataView +): DataTableRecord[] { + return docs.map((doc) => buildDataTableRecord(doc, dataView)); +} diff --git a/src/plugins/discover/public/utils/convert_value_to_string.test.tsx b/src/plugins/discover/public/utils/convert_value_to_string.test.tsx index e77d664851a23..64042c190feba 100644 --- a/src/plugins/discover/public/utils/convert_value_to_string.test.tsx +++ b/src/plugins/discover/public/utils/convert_value_to_string.test.tsx @@ -14,7 +14,6 @@ describe('convertValueToString', () => { it('should convert a keyword value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'keyword_key', @@ -30,7 +29,6 @@ describe('convertValueToString', () => { it('should convert a text value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'text_message', @@ -46,7 +44,6 @@ describe('convertValueToString', () => { it('should convert a multiline text value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'text_message', @@ -63,7 +60,6 @@ describe('convertValueToString', () => { it('should convert a number value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'number_price', @@ -79,7 +75,6 @@ describe('convertValueToString', () => { it('should convert a date value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'date', @@ -95,7 +90,6 @@ describe('convertValueToString', () => { it('should convert a date nanos value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'date_nanos', @@ -111,7 +105,6 @@ describe('convertValueToString', () => { it('should convert a boolean value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'bool_enabled', @@ -127,7 +120,6 @@ describe('convertValueToString', () => { it('should convert a binary value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'binary_blob', @@ -143,7 +135,6 @@ describe('convertValueToString', () => { it('should convert an object value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'object_user.first', @@ -159,7 +150,6 @@ describe('convertValueToString', () => { it('should convert a nested value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'nested_user', @@ -177,7 +167,6 @@ describe('convertValueToString', () => { it('should convert a flattened value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'flattened_labels', @@ -193,7 +182,6 @@ describe('convertValueToString', () => { it('should convert a range value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'range_time_frame', @@ -211,7 +199,6 @@ describe('convertValueToString', () => { it('should convert a rank features value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'rank_features', @@ -227,7 +214,6 @@ describe('convertValueToString', () => { it('should convert a histogram value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'histogram', @@ -243,7 +229,6 @@ describe('convertValueToString', () => { it('should convert a IP value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'ip_addr', @@ -259,7 +244,6 @@ describe('convertValueToString', () => { it('should convert a version value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'version', @@ -275,7 +259,6 @@ describe('convertValueToString', () => { it('should convert a vector value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'vector', @@ -291,7 +274,6 @@ describe('convertValueToString', () => { it('should convert a geo point value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'geo_point', @@ -307,7 +289,6 @@ describe('convertValueToString', () => { it('should convert a geo point object value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'geo_point', @@ -323,7 +304,6 @@ describe('convertValueToString', () => { it('should convert an array value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'array_tags', @@ -339,7 +319,6 @@ describe('convertValueToString', () => { it('should convert a shape value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'geometry', @@ -357,7 +336,6 @@ describe('convertValueToString', () => { it('should convert a runtime value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'runtime_number', @@ -373,7 +351,6 @@ describe('convertValueToString', () => { it('should convert a scripted value to text', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'scripted_string', @@ -389,7 +366,6 @@ describe('convertValueToString', () => { it('should return an empty string and not fail', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'unknown', @@ -405,7 +381,6 @@ describe('convertValueToString', () => { it('should return an empty string when rowIndex is out of range', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'unknown', @@ -421,7 +396,6 @@ describe('convertValueToString', () => { it('should return _source value', () => { const result = convertValueToString({ rows: discoverGridContextMock.rows, - rowsFlattened: discoverGridContextMock.rowsFlattened, dataView: discoverGridContextMock.indexPattern, services: discoverServiceMock, columnId: '_source', @@ -445,7 +419,6 @@ describe('convertValueToString', () => { it('should return a formatted _source value', () => { const result = convertValueToString({ rows: discoverGridContextMock.rows, - rowsFlattened: discoverGridContextMock.rowsFlattened, dataView: discoverGridContextMock.indexPattern, services: discoverServiceMock, columnId: '_source', @@ -463,7 +436,6 @@ describe('convertValueToString', () => { it('should escape formula', () => { const result = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'array_tags', @@ -478,7 +450,6 @@ describe('convertValueToString', () => { const result2 = convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, columnId: 'scripted_string', diff --git a/src/plugins/discover/public/utils/convert_value_to_string.ts b/src/plugins/discover/public/utils/convert_value_to_string.ts index 0f00725a69fb2..7c00bc0988cce 100644 --- a/src/plugins/discover/public/utils/convert_value_to_string.ts +++ b/src/plugins/discover/public/utils/convert_value_to_string.ts @@ -9,8 +9,8 @@ import { DataView } from '@kbn/data-views-plugin/public'; import { cellHasFormulas, createEscapeValue } from '@kbn/data-plugin/common'; import { formatFieldValue } from './format_value'; -import { ElasticSearchHit, HitsFlattened } from '../types'; import { DiscoverServices } from '../build_services'; +import { DataTableRecord } from '../types'; interface ConvertedResult { formattedString: string; @@ -20,15 +20,13 @@ interface ConvertedResult { export const convertValueToString = ({ rowIndex, rows, - rowsFlattened, columnId, dataView, services, options, }: { rowIndex: number; - rows: ElasticSearchHit[]; - rowsFlattened: HitsFlattened; + rows: DataTableRecord[]; columnId: string; dataView: DataView; services: DiscoverServices; @@ -37,7 +35,13 @@ export const convertValueToString = ({ }; }): ConvertedResult => { const { fieldFormats } = services; - const rowFlattened = rowsFlattened[rowIndex]; + if (!rows[rowIndex]) { + return { + formattedString: '', + withFormula: false, + }; + } + const rowFlattened = rows[rowIndex].flattened; const value = rowFlattened?.[columnId]; const field = dataView.fields.getByName(columnId); const valuesArray = Array.isArray(value) ? value : [value]; @@ -56,7 +60,7 @@ export const convertValueToString = ({ .map((subValue) => { const formattedValue = formatFieldValue( subValue, - rows[rowIndex], + rows[rowIndex].raw, fieldFormats, dataView, field, diff --git a/src/plugins/discover/public/utils/copy_value_to_clipboard.test.tsx b/src/plugins/discover/public/utils/copy_value_to_clipboard.test.tsx index 3f3beed866eca..842d8147aece1 100644 --- a/src/plugins/discover/public/utils/copy_value_to_clipboard.test.tsx +++ b/src/plugins/discover/public/utils/copy_value_to_clipboard.test.tsx @@ -23,7 +23,6 @@ describe('copyValueToClipboard', () => { const valueToStringConverter: ValueToStringConverter = (rowIndex, columnId, options) => convertValueToString({ rows: discoverGridContextComplexMock.rows, - rowsFlattened: discoverGridContextComplexMock.rowsFlattened, dataView: discoverGridContextComplexMock.indexPattern, services: discoverServiceMock, rowIndex, diff --git a/src/plugins/discover/public/utils/format_hit.test.ts b/src/plugins/discover/public/utils/format_hit.test.ts index 601d88cdedc96..c273a565ff645 100644 --- a/src/plugins/discover/public/utils/format_hit.test.ts +++ b/src/plugins/discover/public/utils/format_hit.test.ts @@ -6,13 +6,15 @@ * Side Public License, v 1. */ -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { indexPatternMock as dataViewMock } from '../__mocks__/index_pattern'; import { formatHit } from './format_hit'; import { discoverServiceMock } from '../__mocks__/services'; +import { DataTableRecord, EsHitRecord } from '../types'; +import { buildDataTableRecord } from './build_data_record'; describe('formatHit', () => { - let hit: estypes.SearchHit; + let row: DataTableRecord; + let hit: EsHitRecord; beforeEach(() => { hit = { _id: '1', @@ -24,6 +26,7 @@ describe('formatHit', () => { bytes: [123], }, }; + row = buildDataTableRecord(hit, dataViewMock); (dataViewMock.getFormatterForField as jest.Mock).mockReturnValue({ convert: (value: unknown) => `formatted:${value}`, }); @@ -35,7 +38,7 @@ describe('formatHit', () => { it('formats a document as expected', () => { const formatted = formatHit( - hit, + row, dataViewMock, ['message', 'extension', 'object.value'], 220, @@ -51,8 +54,16 @@ describe('formatHit', () => { }); it('orders highlighted fields first', () => { + const highlightHit = buildDataTableRecord( + { + ...hit, + highlight: { message: ['%%'] }, + }, + dataViewMock + ); + const formatted = formatHit( - { ...hit, highlight: { message: ['%%'] } }, + highlightHit, dataViewMock, ['message', 'extension', 'object.value'], 220, @@ -69,7 +80,7 @@ describe('formatHit', () => { it('only limits count of pairs based on advanced setting', () => { const formatted = formatHit( - hit, + row, dataViewMock, ['message', 'extension', 'object.value'], 2, @@ -84,7 +95,7 @@ describe('formatHit', () => { it('should not include fields not mentioned in fieldsToShow', () => { const formatted = formatHit( - hit, + row, dataViewMock, ['message', 'object.value'], 220, @@ -100,7 +111,7 @@ describe('formatHit', () => { it('should filter fields based on their real name not displayName', () => { const formatted = formatHit( - hit, + row, dataViewMock, ['bytes'], 220, diff --git a/src/plugins/discover/public/utils/format_hit.ts b/src/plugins/discover/public/utils/format_hit.ts index 6af6a8aa61210..4e3c6160109c6 100644 --- a/src/plugins/discover/public/utils/format_hit.ts +++ b/src/plugins/discover/public/utils/format_hit.ts @@ -9,8 +9,8 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { i18n } from '@kbn/i18n'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import { flattenHit } from '@kbn/data-plugin/public'; import { DataView } from '@kbn/data-views-plugin/public'; +import { DataTableRecord } from '../types'; import { formatFieldValue } from './format_value'; const formattedHitCache = new WeakMap(); @@ -26,20 +26,20 @@ type FormattedHit = Array; * @param fieldsToShow A list of fields that should be included in the document summary. */ export function formatHit( - hit: estypes.SearchHit, + hit: DataTableRecord, dataView: DataView, fieldsToShow: string[], maxEntries: number, fieldFormats: FieldFormatsStart ): FormattedHit { - const cached = formattedHitCache.get(hit); + const cached = formattedHitCache.get(hit.raw); if (cached) { return cached; } - const highlights = hit.highlight ?? {}; + const highlights = hit.raw.highlight ?? {}; // Flatten the object using the flattenHit implementation we use across Discover for flattening documents. - const flattened = flattenHit(hit, dataView, { includeIgnoredValues: true, source: true }); + const flattened = hit.flattened; const highlightPairs: Array<[fieldName: string, formattedValue: string]> = []; const sourcePairs: Array<[fieldName: string, formattedValue: string]> = []; @@ -54,7 +54,7 @@ export function formatHit( // Format the raw value using the regular field formatters for that field const formattedValue = formatFieldValue( val, - hit, + hit.raw, fieldFormats, dataView, dataView.fields.getByName(key) @@ -85,6 +85,6 @@ export function formatHit( '', ] as const, ]; - formattedHitCache.set(hit, formatted); + formattedHitCache.set(hit.raw, formatted); return formatted; } diff --git a/src/plugins/discover/public/utils/get_doc_id.tsx b/src/plugins/discover/public/utils/get_doc_id.tsx new file mode 100644 index 0000000000000..5b6b638d3b562 --- /dev/null +++ b/src/plugins/discover/public/utils/get_doc_id.tsx @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EsHitRecord } from '../types'; +/** + * Returning a generated id of a given ES document, since `_id` can be the same + * when using different indices and shard routing + */ +export const getDocId = (doc: EsHitRecord & { _routing?: string }) => { + const routing = doc._routing ? doc._routing : ''; + return [doc._index, doc._id, routing].join('::'); +}; diff --git a/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap b/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap index c185e1b85ae1a..a5b79401d0b46 100644 --- a/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap +++ b/src/plugins/kibana_overview/public/components/overview/__snapshots__/overview.test.tsx.snap @@ -1,22 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Overview during loading 1`] = ` -
-
- -
-
-`; - -exports[`Overview render 1`] = ` +exports[`Overview renders correctly 1`] = ` `; -exports[`Overview when there is no user data view 1`] = ` +exports[`Overview renders correctly when there is no user data view 1`] = ` `; -exports[`Overview without features 1`] = ` +exports[`Overview renders correctly without features 1`] = ` `; -exports[`Overview without solutions 1`] = ` +exports[`Overview renders correctly without solutions 1`] = ` `; + +exports[`Overview show loading spinner during loading 1`] = ` +
+
+ +
+
+`; diff --git a/src/plugins/kibana_overview/public/components/overview/overview.test.tsx b/src/plugins/kibana_overview/public/components/overview/overview.test.tsx index b433e7a39da13..99d8b45cdf27b 100644 --- a/src/plugins/kibana_overview/public/components/overview/overview.test.tsx +++ b/src/plugins/kibana_overview/public/components/overview/overview.test.tsx @@ -166,7 +166,7 @@ describe('Overview', () => { afterAll(() => jest.clearAllMocks()); - test('render', async () => { + test('renders correctly', async () => { const component = mountWithIntl( { expect(component.find(KibanaPageTemplate).length).toBe(1); }); - test('without solutions', async () => { + test('renders correctly without solutions', async () => { const component = mountWithIntl( ); @@ -191,7 +191,7 @@ describe('Overview', () => { expect(component).toMatchSnapshot(); }); - test('without features', async () => { + test('renders correctly without features', async () => { const component = mountWithIntl( ); @@ -201,7 +201,7 @@ describe('Overview', () => { expect(component).toMatchSnapshot(); }); - test('when there is no user data view', async () => { + test('renders correctly when there is no user data view', async () => { hasESData.mockResolvedValue(true); hasUserDataView.mockResolvedValue(false); @@ -221,7 +221,7 @@ describe('Overview', () => { expect(component.find(EuiLoadingSpinner).length).toBe(0); }); - test('during loading', async () => { + test('show loading spinner during loading', async () => { hasESData.mockImplementation(() => new Promise(() => {})); hasUserDataView.mockImplementation(() => new Promise(() => {})); diff --git a/src/plugins/kibana_overview/public/components/overview/overview.tsx b/src/plugins/kibana_overview/public/components/overview/overview.tsx index 2258c662fe94e..738b278b17b36 100644 --- a/src/plugins/kibana_overview/public/components/overview/overview.tsx +++ b/src/plugins/kibana_overview/public/components/overview/overview.tsx @@ -22,11 +22,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { CoreStart } from '@kbn/core/public'; import { useKibana, - KibanaPageTemplateSolutionNavAvatar, overviewPageActions, OverviewPageFooter, } from '@kbn/kibana-react-plugin/public'; import { KibanaPageTemplate } from '@kbn/shared-ux-components'; +import { KibanaSolutionAvatar } from '@kbn/shared-ux-avatar-solution'; import { AnalyticsNoDataPageKibanaProvider, AnalyticsNoDataPage, @@ -298,13 +298,7 @@ export const Overview: FC = ({ newsFetchResult, solutions, features }) => className={`kbnOverviewSolution ${id}`} description={description ? description : ''} href={addBasePath(path)} - icon={ - - } + icon={} image={addBasePath(getSolutionGraphicURL(snakeCase(id)))} title={title} titleElement="h3" diff --git a/src/plugins/usage_collection/tsconfig.json b/src/plugins/usage_collection/tsconfig.json index 7fac30a8048ea..0430eb5d64bf1 100644 --- a/src/plugins/usage_collection/tsconfig.json +++ b/src/plugins/usage_collection/tsconfig.json @@ -17,4 +17,4 @@ { "path": "../../core/tsconfig.json" }, { "path": "../../plugins/kibana_utils/tsconfig.json" } ] -} +} \ No newline at end of file diff --git a/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts b/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts index 53493b99ad1ad..9b7310529eed3 100644 --- a/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts +++ b/test/analytics/tests/instrumented_events/from_the_browser/loaded_kibana.ts @@ -25,7 +25,22 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(event.properties).to.have.property('kibana_version'); expect(event.properties.kibana_version).to.be.a('string'); + // Kibana Loaded timings + expect(event.properties).to.have.property('load_started'); + expect(event.properties.load_started).to.be.a('number'); + expect(event.properties).to.have.property('bootstrap_started'); + expect(event.properties.bootstrap_started).to.be.a('number'); + expect(event.properties).to.have.property('core_created'); + expect(event.properties.core_created).to.be.a('number'); + expect(event.properties).to.have.property('setup_done'); + expect(event.properties.setup_done).to.be.a('number'); + expect(event.properties).to.have.property('start_done'); + expect(event.properties.start_done).to.be.a('number'); + expect(event.properties).to.have.property('first_app_nav'); + expect(event.properties.start_done).to.be.a('number'); + if (browser.isChromium) { + // Kibana Loaded memory expect(event.properties).to.have.property('memory_js_heap_size_limit'); expect(event.properties.memory_js_heap_size_limit).to.be.a('number'); expect(event.properties).to.have.property('memory_js_heap_size_total'); diff --git a/test/functional/apps/context/_context_navigation.ts b/test/functional/apps/context/_context_navigation.ts index 15de70882086e..1bda70cc558ee 100644 --- a/test/functional/apps/context/_context_navigation.ts +++ b/test/functional/apps/context/_context_navigation.ts @@ -30,7 +30,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async () => { await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update({ - 'doc_table:legacy': false, defaultIndex: 'logstash-*', }); await PageObjects.common.navigateToApp('discover'); diff --git a/test/functional/apps/context/_date_nanos.ts b/test/functional/apps/context/_date_nanos.ts index 969a7dcecd5c3..b486dd77ecef8 100644 --- a/test/functional/apps/context/_date_nanos.ts +++ b/test/functional/apps/context/_date_nanos.ts @@ -30,7 +30,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.update({ 'context:defaultSize': `${TEST_DEFAULT_CONTEXT_SIZE}`, 'context:step': `${TEST_STEP_SIZE}`, - 'doc_table:legacy': false, }); }); diff --git a/test/functional/apps/context/_date_nanos_custom_timestamp.ts b/test/functional/apps/context/_date_nanos_custom_timestamp.ts index b8af57e40a3e3..b91aafa89dabf 100644 --- a/test/functional/apps/context/_date_nanos_custom_timestamp.ts +++ b/test/functional/apps/context/_date_nanos_custom_timestamp.ts @@ -32,7 +32,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.update({ 'context:defaultSize': `${TEST_DEFAULT_CONTEXT_SIZE}`, 'context:step': `${TEST_STEP_SIZE}`, - 'doc_table:legacy': false, }); }); diff --git a/test/functional/apps/context/_discover_navigation.ts b/test/functional/apps/context/_discover_navigation.ts index 5add260d8f4d0..46f03b512bff3 100644 --- a/test/functional/apps/context/_discover_navigation.ts +++ b/test/functional/apps/context/_discover_navigation.ts @@ -37,7 +37,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async () => { await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update({ - 'doc_table:legacy': false, defaultIndex: 'logstash-*', }); await PageObjects.common.navigateToApp('discover'); diff --git a/test/functional/apps/context/_filters.ts b/test/functional/apps/context/_filters.ts index fe5b27f2f8055..e8a8675e85f82 100644 --- a/test/functional/apps/context/_filters.ts +++ b/test/functional/apps/context/_filters.ts @@ -19,19 +19,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const filterBar = getService('filterBar'); const testSubjects = getService('testSubjects'); const retry = getService('retry'); - const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['common', 'context']); describe('context filters', function contextSize() { - before(async function () { - await kibanaServer.uiSettings.update({ 'doc_table:legacy': false }); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - beforeEach(async function () { await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID, { columns: TEST_COLUMN_NAMES, diff --git a/test/functional/apps/context/_size.ts b/test/functional/apps/context/_size.ts index 563af7e07857e..853d4ebde79de 100644 --- a/test/functional/apps/context/_size.ts +++ b/test/functional/apps/context/_size.ts @@ -29,7 +29,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.update({ 'context:defaultSize': `${TEST_DEFAULT_CONTEXT_SIZE}`, 'context:step': `${TEST_STEP_SIZE}`, - 'doc_table:legacy': false, }); await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID); }); diff --git a/test/functional/apps/discover/_context_encoded_url_params.ts b/test/functional/apps/discover/_context_encoded_url_params.ts index 293a1ee0b5e28..cff83b2d6f645 100644 --- a/test/functional/apps/discover/_context_encoded_url_params.ts +++ b/test/functional/apps/discover/_context_encoded_url_params.ts @@ -41,7 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('discover'); }); - it('should navigate correctly when ', async () => { + it('should navigate correctly', async () => { await PageObjects.discover.selectIndexPattern('context-encoded-param'); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.discover.waitForDocTableLoadingComplete(); diff --git a/test/functional/apps/discover/_data_grid.ts b/test/functional/apps/discover/_data_grid.ts index 198691f3b8477..96085f09186f6 100644 --- a/test/functional/apps/discover/_data_grid.ts +++ b/test/functional/apps/discover/_data_grid.ts @@ -19,7 +19,7 @@ export default function ({ const esArchiver = getService('esArchiver'); const PageObjects = getPageObjects(['common', 'discover', 'timePicker']); const kibanaServer = getService('kibanaServer'); - const defaultSettings = { defaultIndex: 'logstash-*', 'doc_table:legacy': false }; + const defaultSettings = { defaultIndex: 'logstash-*' }; const testSubjects = getService('testSubjects'); before(async function () { @@ -31,10 +31,6 @@ export default function ({ await PageObjects.timePicker.setDefaultAbsoluteRange(); }); - after(async function () { - await kibanaServer.uiSettings.replace({ 'doc_table:legacy': true }); - }); - it('can add fields to the table', async function () { const getTitles = async () => (await testSubjects.getVisibleText('dataGridHeader')).replace(/\s|\r?\n|\r/g, ' '); diff --git a/test/functional/apps/discover/_data_grid_context.ts b/test/functional/apps/discover/_data_grid_context.ts index d12ada2070cff..c2628026dfdda 100644 --- a/test/functional/apps/discover/_data_grid_context.ts +++ b/test/functional/apps/discover/_data_grid_context.ts @@ -27,7 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'dashboard', 'header', ]); - const defaultSettings = { defaultIndex: 'logstash-*', 'doc_table:legacy': false }; + const defaultSettings = { defaultIndex: 'logstash-*' }; const kibanaServer = getService('kibanaServer'); const esArchiver = getService('esArchiver'); const dashboardAddPanel = getService('dashboardAddPanel'); diff --git a/test/functional/apps/discover/_data_grid_copy_to_clipboard.ts b/test/functional/apps/discover/_data_grid_copy_to_clipboard.ts index f202595729cfb..ec359e3c569db 100644 --- a/test/functional/apps/discover/_data_grid_copy_to_clipboard.ts +++ b/test/functional/apps/discover/_data_grid_copy_to_clipboard.ts @@ -19,7 +19,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker', 'dashboard']); const defaultSettings = { defaultIndex: 'logstash-*', - 'doc_table:legacy': false, }; describe('discover data grid supports copy to clipboard', function describeIndexTests() { diff --git a/test/functional/apps/discover/_data_grid_doc_navigation.ts b/test/functional/apps/discover/_data_grid_doc_navigation.ts index 2da6db97aa13f..3c5c8b3967cb0 100644 --- a/test/functional/apps/discover/_data_grid_doc_navigation.ts +++ b/test/functional/apps/discover/_data_grid_doc_navigation.ts @@ -17,7 +17,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const retry = getService('retry'); const kibanaServer = getService('kibanaServer'); - const defaultSettings = { defaultIndex: 'logstash-*', 'doc_table:legacy': false }; + const defaultSettings = { defaultIndex: 'logstash-*' }; describe('discover data grid doc link', function () { before(async () => { diff --git a/test/functional/apps/discover/_data_grid_doc_table.ts b/test/functional/apps/discover/_data_grid_doc_table.ts index bb0cd56298c20..6918edc8285d8 100644 --- a/test/functional/apps/discover/_data_grid_doc_table.ts +++ b/test/functional/apps/discover/_data_grid_doc_table.ts @@ -21,7 +21,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker', 'dashboard']); const defaultSettings = { defaultIndex: 'logstash-*', - 'doc_table:legacy': false, }; const testSubjects = getService('testSubjects'); diff --git a/test/functional/apps/discover/_data_grid_field_data.ts b/test/functional/apps/discover/_data_grid_field_data.ts index 4a4e06e28c321..84d1c81f8ee68 100644 --- a/test/functional/apps/discover/_data_grid_field_data.ts +++ b/test/functional/apps/discover/_data_grid_field_data.ts @@ -16,7 +16,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const toasts = getService('toasts'); const queryBar = getService('queryBar'); const PageObjects = getPageObjects(['common', 'header', 'discover', 'visualize', 'timePicker']); - const defaultSettings = { defaultIndex: 'logstash-*', 'doc_table:legacy': false }; + const defaultSettings = { defaultIndex: 'logstash-*' }; const dataGrid = getService('dataGrid'); describe('discover data grid field data tests', function describeIndexTests() { diff --git a/test/functional/apps/discover/_data_grid_pagination.ts b/test/functional/apps/discover/_data_grid_pagination.ts index da9faa24bb151..7b0fc40e94ab8 100644 --- a/test/functional/apps/discover/_data_grid_pagination.ts +++ b/test/functional/apps/discover/_data_grid_pagination.ts @@ -14,7 +14,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const dataGrid = getService('dataGrid'); const PageObjects = getPageObjects(['settings', 'common', 'discover', 'header', 'timePicker']); - const defaultSettings = { defaultIndex: 'logstash-*', 'doc_table:legacy': false }; + const defaultSettings = { defaultIndex: 'logstash-*' }; const testSubjects = getService('testSubjects'); const retry = getService('retry'); diff --git a/test/functional/apps/discover/_discover_fields_api.ts b/test/functional/apps/discover/_discover_fields_api.ts index fb3ee3b9858d3..e64280c1977b5 100644 --- a/test/functional/apps/discover/_discover_fields_api.ts +++ b/test/functional/apps/discover/_discover_fields_api.ts @@ -14,11 +14,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); + const dataGrid = getService('dataGrid'); const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker', 'settings']); const defaultSettings = { defaultIndex: 'logstash-*', 'discover:searchFieldsFromSource': false, - 'doc_table:legacy': true, }; describe('discover uses fields API test', function describeIndexTests() { before(async function () { @@ -60,7 +60,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('displays _source viewer in doc viewer', async function () { - await PageObjects.discover.clickDocTableRowToggle(0); + await dataGrid.clickRowToggle(); await PageObjects.discover.isShowingDocViewer(); await PageObjects.discover.clickDocViewerTab(1); await PageObjects.discover.expectSourceViewerToExist(); @@ -74,7 +74,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setDefaultAbsoluteRange(); - expect(await PageObjects.discover.getDocHeader()).to.have.string('_source'); + expect(await PageObjects.discover.getDocHeader()).to.have.string('Document'); }); it('switches to Document column when fields API is used', async function () { diff --git a/test/functional/apps/discover/_field_data.ts b/test/functional/apps/discover/_field_data.ts index d13baf9948171..27b786a2abfc1 100644 --- a/test/functional/apps/discover/_field_data.ts +++ b/test/functional/apps/discover/_field_data.ts @@ -18,8 +18,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const queryBar = getService('queryBar'); const browser = getService('browser'); const PageObjects = getPageObjects(['common', 'header', 'discover', 'visualize', 'timePicker']); - const find = getService('find'); - const testSubjects = getService('testSubjects'); describe('discover tab', function describeIndexTests() { this.tags('includeFirefox'); @@ -97,38 +95,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const marks = await PageObjects.discover.getMarks(); expect(marks.length).to.be(0); }); - - describe('legacy table tests', async function () { - before(async function () { - await kibanaServer.uiSettings.update({ 'doc_table:legacy': true }); - await PageObjects.common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - it('doc view should show @timestamp and _source columns', async function () { - const expectedHeader = '@timestamp\n_source'; - const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); - const docHeaderText = await docHeader.getVisibleText(); - expect(docHeaderText).to.be(expectedHeader); - }); - - it('doc view should sort ascending', async function () { - const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - - // we don't technically need this sleep here because the tryForTime will retry and the - // results will match on the 2nd or 3rd attempt, but that debug output is huge in this - // case and it can be avoided with just a few seconds sleep. - await PageObjects.common.sleep(2000); - await retry.try(async function tryingForTime() { - const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); - const rowData = await row.getVisibleText(); - expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); - }); - }); - }); }); }); } diff --git a/test/functional/apps/discover/_field_data_with_fields_api.ts b/test/functional/apps/discover/_field_data_with_fields_api.ts index d7912d6d0959f..85bb26df24129 100644 --- a/test/functional/apps/discover/_field_data_with_fields_api.ts +++ b/test/functional/apps/discover/_field_data_with_fields_api.ts @@ -18,8 +18,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const queryBar = getService('queryBar'); const browser = getService('browser'); const PageObjects = getPageObjects(['common', 'header', 'discover', 'visualize', 'timePicker']); - const find = getService('find'); - const testSubjects = getService('testSubjects'); describe('discover tab with new fields API', function describeIndexTests() { this.tags('includeFirefox'); @@ -104,33 +102,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(marks.length).to.be.above(0); expect(marks).to.contain('election'); }); - - describe('legacy table tests', async function () { - before(async function () { - await kibanaServer.uiSettings.update({ 'doc_table:legacy': true }); - await PageObjects.common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - - it('doc view should sort ascending', async function () { - const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - - // we don't technically need this sleep here because the tryForTime will retry and the - // results will match on the 2nd or 3rd attempt, but that debug output is huge in this - // case and it can be avoided with just a few seconds sleep. - await PageObjects.common.sleep(2000); - await retry.try(async function tryingForTime() { - const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); - const rowData = await row.getVisibleText(); - - expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); - }); - }); - }); }); }); } diff --git a/test/functional/apps/discover/_classic_table_doc_navigation.ts b/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts similarity index 97% rename from test/functional/apps/discover/_classic_table_doc_navigation.ts rename to test/functional/apps/discover/classic/_classic_table_doc_navigation.ts index c768d9600c189..a27d3df81d32f 100644 --- a/test/functional/apps/discover/_classic_table_doc_navigation.ts +++ b/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const docTable = getService('docTable'); diff --git a/test/functional/apps/discover/classic/_discover_fields_api.ts b/test/functional/apps/discover/classic/_discover_fields_api.ts new file mode 100644 index 0000000000000..7108cc2911be8 --- /dev/null +++ b/test/functional/apps/discover/classic/_discover_fields_api.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker', 'settings']); + const defaultSettings = { + defaultIndex: 'logstash-*', + 'discover:searchFieldsFromSource': false, + 'doc_table:legacy': true, + }; + describe('discover uses fields API test', function describeIndexTests() { + before(async function () { + log.debug('load kibana index with default index pattern'); + await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.uiSettings.replace(defaultSettings); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + }); + + after(async () => { + await kibanaServer.uiSettings.replace({}); + }); + + it('should correctly display documents', async function () { + log.debug('check if Document title exists in the grid'); + expect(await PageObjects.discover.getDocHeader()).to.have.string('Document'); + const rowData = await PageObjects.discover.getDocTableIndex(1); + log.debug('check the newest doc timestamp in UTC (check diff timezone in last test)'); + expect(rowData.startsWith('Sep 22, 2015 @ 23:50:13.253')).to.be.ok(); + const expectedHitCount = '14,004'; + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be(expectedHitCount); + }); + }); + + it('adding a column removes a default column', async function () { + await PageObjects.discover.clickFieldListItemAdd('_score'); + expect(await PageObjects.discover.getDocHeader()).to.have.string('_score'); + expect(await PageObjects.discover.getDocHeader()).not.to.have.string('Document'); + }); + + it('removing a column adds a default column', async function () { + await PageObjects.discover.clickFieldListItemRemove('_score'); + expect(await PageObjects.discover.getDocHeader()).not.to.have.string('_score'); + expect(await PageObjects.discover.getDocHeader()).to.have.string('Document'); + }); + + it('displays _source viewer in doc viewer', async function () { + await PageObjects.discover.clickDocTableRowToggle(0); + await PageObjects.discover.isShowingDocViewer(); + await PageObjects.discover.clickDocViewerTab(1); + await PageObjects.discover.expectSourceViewerToExist(); + }); + + it('switches to _source column when fields API is no longer used', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaSettings(); + await PageObjects.settings.toggleAdvancedSettingCheckbox('discover:searchFieldsFromSource'); + + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + + expect(await PageObjects.discover.getDocHeader()).to.have.string('_source'); + }); + + it('switches to Document column when fields API is used', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaSettings(); + await PageObjects.settings.toggleAdvancedSettingCheckbox('discover:searchFieldsFromSource'); + + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + + expect(await PageObjects.discover.getDocHeader()).to.have.string('Document'); + }); + }); +} diff --git a/test/functional/apps/discover/_doc_table.ts b/test/functional/apps/discover/classic/_doc_table.ts similarity index 98% rename from test/functional/apps/discover/_doc_table.ts rename to test/functional/apps/discover/classic/_doc_table.ts index 321c41b92e9be..bfc813f2d822e 100644 --- a/test/functional/apps/discover/_doc_table.ts +++ b/test/functional/apps/discover/classic/_doc_table.ts @@ -7,7 +7,7 @@ */ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); @@ -40,6 +40,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.navigateToApp('discover'); }); + after(async function () { + await kibanaServer.uiSettings.replace({}); + }); + it('should show records by default', async function () { // with the default range the number of hits is ~14000 const rows = await PageObjects.discover.getDocTableRows(); diff --git a/test/functional/apps/discover/_doc_table_newline.ts b/test/functional/apps/discover/classic/_doc_table_newline.ts similarity index 92% rename from test/functional/apps/discover/_doc_table_newline.ts rename to test/functional/apps/discover/classic/_doc_table_newline.ts index a02d31d5c76f4..112fff800cd41 100644 --- a/test/functional/apps/discover/_doc_table_newline.ts +++ b/test/functional/apps/discover/classic/_doc_table_newline.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); @@ -35,8 +35,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await security.testUser.restoreDefaults(); await esArchiver.unload('test/functional/fixtures/es_archiver/message_with_newline'); await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.uiSettings.unset('defaultIndex'); - await kibanaServer.uiSettings.unset('doc_table:legacy'); + await kibanaServer.uiSettings.replace({}); }); it('should break text on newlines', async function () { @@ -47,6 +46,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const heightWithoutNewline = await dscTableRows[0].getAttribute('clientHeight'); const heightWithNewline = await dscTableRows[1].getAttribute('clientHeight'); log.debug(`Without newlines: ${heightWithoutNewline}, With newlines: ${heightWithNewline}`); + + await PageObjects.common.sleep(10000); return Number(heightWithNewline) > Number(heightWithoutNewline); }); }); diff --git a/test/functional/apps/discover/classic/_field_data.ts b/test/functional/apps/discover/classic/_field_data.ts new file mode 100644 index 0000000000000..f574a36dea028 --- /dev/null +++ b/test/functional/apps/discover/classic/_field_data.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'header', 'discover', 'visualize', 'timePicker']); + const find = getService('find'); + const testSubjects = getService('testSubjects'); + + describe('discover tab', function describeIndexTests() { + this.tags('includeFirefox'); + before(async function () { + await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.uiSettings.replace({ + defaultIndex: 'logstash-*', + 'discover:searchFieldsFromSource': true, + 'doc_table:legacy': true, + }); + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await PageObjects.common.navigateToApp('discover'); + }); + + after(async function () { + await kibanaServer.uiSettings.replace({}); + }); + + it('doc view should show @timestamp and _source columns', async function () { + const expectedHeader = '@timestamp\n_source'; + const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); + const docHeaderText = await docHeader.getVisibleText(); + expect(docHeaderText).to.be(expectedHeader); + }); + + it('doc view should sort ascending', async function () { + const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + + // we don't technically need this sleep here because the tryForTime will retry and the + // results will match on the 2nd or 3rd attempt, but that debug output is huge in this + // case and it can be avoided with just a few seconds sleep. + await PageObjects.common.sleep(2000); + await retry.try(async function tryingForTime() { + const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); + const rowData = await row.getVisibleText(); + expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); + }); + }); + }); +} diff --git a/test/functional/apps/discover/classic/_field_data_with_fields_api.ts b/test/functional/apps/discover/classic/_field_data_with_fields_api.ts new file mode 100644 index 0000000000000..efa680bfbfa3a --- /dev/null +++ b/test/functional/apps/discover/classic/_field_data_with_fields_api.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const retry = getService('retry'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'header', 'discover', 'visualize', 'timePicker']); + const find = getService('find'); + const testSubjects = getService('testSubjects'); + + describe('discover tab with new fields API', function describeIndexTests() { + before(async function () { + await kibanaServer.uiSettings.update({ 'doc_table:legacy': true }); + await PageObjects.common.navigateToApp('discover'); + }); + + after(async function () { + await kibanaServer.uiSettings.replace({}); + }); + + it('doc view should sort ascending', async function () { + const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + + // we don't technically need this sleep here because the tryForTime will retry and the + // results will match on the 2nd or 3rd attempt, but that debug output is huge in this + // case and it can be avoided with just a few seconds sleep. + await PageObjects.common.sleep(2000); + await retry.try(async function tryingForTime() { + const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); + const rowData = await row.getVisibleText(); + + expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); + }); + }); + }); +} diff --git a/test/functional/apps/discover/index.ts b/test/functional/apps/discover/index.ts index db72e270fd337..cd2742abe8e13 100644 --- a/test/functional/apps/discover/index.ts +++ b/test/functional/apps/discover/index.ts @@ -30,21 +30,24 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_discover')); loadTestFile(require.resolve('./_discover_accessibility')); loadTestFile(require.resolve('./_discover_histogram')); - loadTestFile(require.resolve('./_doc_table')); - loadTestFile(require.resolve('./_doc_table_newline')); + loadTestFile(require.resolve('./classic/_doc_table')); + loadTestFile(require.resolve('./classic/_doc_table_newline')); loadTestFile(require.resolve('./_filter_editor')); loadTestFile(require.resolve('./_errors')); loadTestFile(require.resolve('./_field_data')); + loadTestFile(require.resolve('./classic/_field_data')); loadTestFile(require.resolve('./_field_data_with_fields_api')); + loadTestFile(require.resolve('./classic/_field_data_with_fields_api')); loadTestFile(require.resolve('./_shared_links')); loadTestFile(require.resolve('./_sidebar')); loadTestFile(require.resolve('./_source_filters')); loadTestFile(require.resolve('./_large_string')); loadTestFile(require.resolve('./_inspector')); - loadTestFile(require.resolve('./_classic_table_doc_navigation')); + loadTestFile(require.resolve('./classic/_classic_table_doc_navigation')); loadTestFile(require.resolve('./_date_nanos')); loadTestFile(require.resolve('./_date_nanos_mixed')); loadTestFile(require.resolve('./_indexpattern_without_timefield')); + loadTestFile(require.resolve('./classic/_discover_fields_api')); loadTestFile(require.resolve('./_discover_fields_api')); loadTestFile(require.resolve('./_data_grid')); loadTestFile(require.resolve('./_data_grid_context')); diff --git a/test/functional/apps/kibana_overview/_analytics.ts b/test/functional/apps/kibana_overview/_analytics.ts new file mode 100644 index 0000000000000..296256d924b24 --- /dev/null +++ b/test/functional/apps/kibana_overview/_analytics.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { WebElementWrapper } from '../../services/lib/web_element_wrapper'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const find = getService('find'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'header']); + + describe('overview page - Analytics apps', function describeIndexTests() { + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + }); + + const apps = ['dashboard', 'discover', 'canvas', 'maps', 'ml']; + + it('should display Analytics apps cards', async () => { + const kbnOverviewAppsCards = await find.allByCssSelector('.kbnOverviewApps__item'); + expect(kbnOverviewAppsCards.length).to.be(apps.length); + + const verifyImageUrl = async (el: WebElementWrapper, imgName: string) => { + const image = await el.findByCssSelector('img'); + const imageUrl = await image.getAttribute('src'); + expect(imageUrl.includes(imgName)).to.be(true); + }; + + for (let i = 0; i < apps.length; i++) { + verifyImageUrl(kbnOverviewAppsCards[i], `kibana_${apps[i]}_light.svg`); + } + }); + + it('click on a card should lead to the appropriate app', async () => { + const kbnOverviewAppsCards = await find.allByCssSelector('.kbnOverviewApps__item'); + const dashboardCard = kbnOverviewAppsCards.at(0); + expect(dashboardCard).not.to.be(undefined); + if (dashboardCard) { + await dashboardCard.click(); + await PageObjects.common.waitUntilUrlIncludes('app/dashboards'); + } + }); + }); +} diff --git a/test/functional/apps/kibana_overview/_footer.ts b/test/functional/apps/kibana_overview/_footer.ts new file mode 100644 index 0000000000000..c44d399154f14 --- /dev/null +++ b/test/functional/apps/kibana_overview/_footer.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const find = getService('find'); + const esArchiver = getService('esArchiver'); + const retry = getService('retry'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'header']); + + const defaultSettings = { + default_route: 'app/home', + }; + + describe('overview page - footer', function describeIndexTests() { + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await kibanaServer.uiSettings.replace(defaultSettings); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + await kibanaServer.uiSettings.replace(defaultSettings); + }); + + it('clicking footer updates landing page', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + let footerButton = await find.byCssSelector('.kbnOverviewPageFooter__button'); + await footerButton.click(); + + await retry.try(async () => { + footerButton = await find.byCssSelector('.kbnOverviewPageFooter__button'); + const text = await ( + await footerButton.findByCssSelector('.euiButtonEmpty__text') + ).getVisibleText(); + expect(text.toString().includes('Display a different page on log in')).to.be(true); + }); + }); + }); +} diff --git a/test/functional/apps/kibana_overview/_no_data.ts b/test/functional/apps/kibana_overview/_no_data.ts new file mode 100644 index 0000000000000..8dec616eb8afe --- /dev/null +++ b/test/functional/apps/kibana_overview/_no_data.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const find = getService('find'); + const testSubjects = getService('testSubjects'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'header']); + + describe('overview page - no data', function describeIndexTests() { + before(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + kibanaServer.savedObjects.clean({ types: ['index-pattern'] }); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + }); + + it('should display no data page', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); + const exists = await find.byClassName('kbnNoDataPageContents'); + expect(exists).not.to.be(undefined); + }); + + it('click on add data opens integrations', async () => { + const addIntegrations = await testSubjects.find('kbnOverviewAddIntegrations'); + await addIntegrations.click(); + await PageObjects.common.waitUntilUrlIncludes('integrations/browse'); + }); + }); +} diff --git a/test/functional/apps/kibana_overview/_page_header.ts b/test/functional/apps/kibana_overview/_page_header.ts new file mode 100644 index 0000000000000..8c254948676fc --- /dev/null +++ b/test/functional/apps/kibana_overview/_page_header.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const find = getService('find'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'header', 'dashboard']); + + describe('overview page - page header', function describeIndexTests() { + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + }); + + it('click on integrations leads to integrations', async () => { + const headerItems = await find.byCssSelector('.euiPageHeaderContent__rightSideItems'); + const items = await headerItems.findAllByCssSelector('.kbnRedirectCrossAppLinks'); + expect(items!.length).to.be(3); + + const integrations = await items!.at(0); + await integrations!.click(); + await PageObjects.common.waitUntilUrlIncludes('app/integrations/browse'); + }); + + it('click on management leads to management', async () => { + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const headerItems = await find.byCssSelector('.euiPageHeaderContent__rightSideItems'); + const items = await headerItems.findAllByCssSelector('.kbnRedirectCrossAppLinks'); + + const management = await items!.at(1); + await management!.click(); + await PageObjects.common.waitUntilUrlIncludes('app/management'); + }); + + it('click on dev tools leads to dev tools', async () => { + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + const headerItems = await find.byCssSelector('.euiPageHeaderContent__rightSideItems'); + const items = await headerItems.findAllByCssSelector('.kbnRedirectCrossAppLinks'); + + const devTools = await items!.at(2); + await devTools!.click(); + await PageObjects.common.waitUntilUrlIncludes('app/dev_tools'); + }); + }); +} diff --git a/test/functional/apps/kibana_overview/_solutions.ts b/test/functional/apps/kibana_overview/_solutions.ts new file mode 100644 index 0000000000000..97af7f7242eff --- /dev/null +++ b/test/functional/apps/kibana_overview/_solutions.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const find = getService('find'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const retry = getService('retry'); + const PageObjects = getPageObjects(['common', 'header']); + + describe('overview page - solutions', function describeIndexTests() { + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/kibana_sample_data_flights_index_pattern' + ); + }); + + it('contains the appropriate solutions', async () => { + const solutionCards = await find.allByCssSelector('.kbnOverviewMore__item'); + expect(solutionCards.length).to.be(2); + + const observabilityImage = await solutionCards[0].findByCssSelector('img'); + const observabilityImageUrl = await observabilityImage.getAttribute('src'); + expect(observabilityImageUrl.includes('/solutions_observability.svg')).to.be(true); + + const securityImage = await solutionCards[1].findByCssSelector('img'); + const securityImageUrl = await securityImage.getAttribute('src'); + expect(securityImageUrl.includes('/solutions_security_solution.svg')).to.be(true); + }); + + it('click on Observability card leads to Observability', async () => { + let solutionCards: string | any[] = []; + await retry.waitForWithTimeout('all solutions to be present', 5000, async () => { + solutionCards = await find.allByCssSelector('.kbnOverviewMore__item'); + return solutionCards.length === 2; + }); + await solutionCards[0].click(); + await PageObjects.common.waitUntilUrlIncludes('app/observability'); + }); + + it('click on Security card leads to Security', async () => { + await PageObjects.common.navigateToUrl('kibana_overview', '', { useActualUrl: true }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + let solutionCards: string | any[] = []; + await retry.waitForWithTimeout('all solutions to be present', 5000, async () => { + solutionCards = await find.allByCssSelector('.kbnOverviewMore__item'); + return solutionCards.length === 2; + }); + await solutionCards[1].click(); + await PageObjects.common.waitUntilUrlIncludes('app/security'); + }); + }); +} diff --git a/test/functional/apps/kibana_overview/config.ts b/test/functional/apps/kibana_overview/config.ts new file mode 100644 index 0000000000000..e487d31dcb657 --- /dev/null +++ b/test/functional/apps/kibana_overview/config.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/kibana_overview/index.js b/test/functional/apps/kibana_overview/index.js new file mode 100644 index 0000000000000..40dd47f6b69ef --- /dev/null +++ b/test/functional/apps/kibana_overview/index.js @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export default function ({ getService, loadTestFile }) { + const browser = getService('browser'); + + describe('kibana overview app', function () { + before(function () { + return browser.setWindowSize(1200, 800); + }); + + loadTestFile(require.resolve('./_no_data')); + loadTestFile(require.resolve('./_page_header')); + loadTestFile(require.resolve('./_analytics')); + loadTestFile(require.resolve('./_solutions')); + loadTestFile(require.resolve('./_footer')); + }); +} diff --git a/test/functional/apps/management/_scripted_fields.ts b/test/functional/apps/management/_scripted_fields.ts index a6bbe798cf56b..cefaa5b295369 100644 --- a/test/functional/apps/management/_scripted_fields.ts +++ b/test/functional/apps/management/_scripted_fields.ts @@ -32,6 +32,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const testSubjects = getService('testSubjects'); const filterBar = getService('filterBar'); + const find = getService('find'); + const dataGrid = getService('dataGrid'); const PageObjects = getPageObjects([ 'common', 'header', @@ -48,7 +50,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.setWindowSize(1200, 800); await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); await kibanaServer.uiSettings.replace({}); - await kibanaServer.uiSettings.update({ 'doc_table:legacy': true }); }); after(async function afterAll() { @@ -56,6 +57,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.replace({}); }); + /** + * @param field field name to sort + * @param optionIndex index of the option to choose in dropdown + */ + const clickSort = async (field: string, optionIndex: number) => { + await testSubjects.click(`dataGridHeaderCell-${field}`); + const optionButtons = await find.allByCssSelector('.euiListGroupItem__button'); + await optionButtons[optionIndex].click(); + }; + it('should not allow saving of invalid scripts', async function () { await PageObjects.settings.navigateTo(); await PageObjects.settings.clickKibanaIndexPatterns(); @@ -146,29 +157,37 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\n18'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.91618'); }); }); // add a test to sort numeric scripted field it('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); + await clickSort(scriptedPainlessFieldName, 1); + await PageObjects.common.sleep(500); + // after the first click on the scripted field, it becomes secondary sort after time. // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await clickSort('@timestamp', 1); + await clickSort('@timestamp', 0); + await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 10:53:14.181\n-1'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 17, 2015 @ 10:53:14.181-1'); }); - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); + await clickSort(scriptedPainlessFieldName, 2); + // after the first click on the scripted field, it becomes primary sort after time. + // click on the scripted field twice then, makes it be the secondary sort key. + await clickSort(scriptedPainlessFieldName, 2); + await clickSort(scriptedPainlessFieldName, 2); + await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\n20'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.47920'); }); }); @@ -233,29 +252,37 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ngood'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916good'); }); }); // add a test to sort string scripted field it('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + await clickSort(scriptedPainlessFieldName2, 1); + // await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + await PageObjects.common.sleep(500); + // after the first click on the scripted field, it becomes secondary sort after time. // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await clickSort('@timestamp', 1); + await clickSort('@timestamp', 0); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 09:48:40.594\nbad'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 17, 2015 @ 09:48:40.594bad'); }); - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + await clickSort(scriptedPainlessFieldName2, 2); + // after the first click on the scripted field, it becomes primary sort after time. + // click on the scripted field twice then, makes it be the secondary sort key. + await clickSort(scriptedPainlessFieldName2, 2); + await clickSort(scriptedPainlessFieldName2, 2); + await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\ngood'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479good'); }); }); @@ -319,8 +346,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ntrue'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916true'); }); }); @@ -406,8 +433,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.953\n2015-09-18 07:00'); + const rowData = (await dataGrid.getRowsText())[0]; + expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.9532015-09-18 07:00'); }); }); diff --git a/test/functional/apps/management/_scripted_fields_classic_table.ts b/test/functional/apps/management/_scripted_fields_classic_table.ts new file mode 100644 index 0000000000000..a6bbe798cf56b --- /dev/null +++ b/test/functional/apps/management/_scripted_fields_classic_table.ts @@ -0,0 +1,459 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// Tests for 4 scripted fields; +// 1. Painless (number type) +// 2. Painless (string type) +// 3. Painless (boolean type) +// 4. Painless (date type) +// +// Each of these scripted fields has 4 tests (12 tests total); +// 1. Create scripted field +// 2. See the expected value of the scripted field in Discover doc view +// 3. Filter in Discover by the scripted field +// 4. Visualize with aggregation on the scripted field by clicking discover.clickFieldListItemVisualize + +// NOTE: Scripted field input is managed by Ace editor, which automatically +// appends closing braces, for exmaple, if you type opening square brace [ +// it will automatically insert a a closing square brace ], etc. + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const log = getService('log'); + const browser = getService('browser'); + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + const filterBar = getService('filterBar'); + const PageObjects = getPageObjects([ + 'common', + 'header', + 'settings', + 'visualize', + 'discover', + 'timePicker', + ]); + + describe('scripted fields', function () { + this.tags(['skipFirefox']); + + before(async function () { + await browser.setWindowSize(1200, 800); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.uiSettings.replace({}); + await kibanaServer.uiSettings.update({ 'doc_table:legacy': true }); + }); + + after(async function afterAll() { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + await kibanaServer.uiSettings.replace({}); + }); + + it('should not allow saving of invalid scripts', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + await PageObjects.settings.clickScriptedFieldsTab(); + await PageObjects.settings.clickAddScriptedField(); + await PageObjects.settings.setScriptedFieldName('doomedScriptedField'); + await PageObjects.settings.setScriptedFieldScript(`i n v a l i d s c r i p t`); + await PageObjects.settings.clickSaveScriptedField(); + await retry.try(async () => { + const invalidScriptErrorExists = await testSubjects.exists('invalidScriptError'); + expect(invalidScriptErrorExists).to.be(true); + }); + }); + + describe('testing regression for issue #33251', function describeIndexTests() { + const scriptedPainlessFieldName = 'ram_Pain_reg'; + + it('should create and edit scripted field', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); + await PageObjects.settings.clickScriptedFieldsTab(); + await log.debug('add scripted field'); + const script = `1`; + await PageObjects.settings.addScriptedField( + scriptedPainlessFieldName, + 'painless', + 'number', + null, + '1', + script + ); + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + + for (let i = 0; i < 3; i++) { + await PageObjects.settings.editScriptedField(scriptedPainlessFieldName); + const fieldSaveButton = await testSubjects.exists('fieldSaveButton'); + expect(fieldSaveButton).to.be(true); + await PageObjects.settings.clickSaveScriptedField(); + } + }); + }); + + describe('creating and using Painless numeric scripted fields', function describeIndexTests() { + const scriptedPainlessFieldName = 'ram_Pain1'; + + it('should create scripted field', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); + await PageObjects.settings.clickScriptedFieldsTab(); + await log.debug('add scripted field'); + const script = `if (doc['machine.ram'].size() == 0) return -1; + else return doc['machine.ram'].value / (1024 * 1024 * 1024); + `; + await PageObjects.settings.addScriptedField( + scriptedPainlessFieldName, + 'painless', + 'number', + null, + '100', + script + ); + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + }); + + it('should see scripted field value in Discover', async function () { + const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; + const toTime = 'Sep 18, 2015 @ 18:31:44.000'; + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName); + await retry.try(async function () { + await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName); + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\n18'); + }); + }); + + // add a test to sort numeric scripted field + it('should sort scripted field value in Discover', async function () { + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); + // after the first click on the scripted field, it becomes secondary sort after time. + // click on the timestamp twice to make it be the secondary sort key. + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 17, 2015 @ 10:53:14.181\n-1'); + }); + + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\n20'); + }); + }); + + it('should filter by scripted field value in Discover', async function () { + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName); + await log.debug('filter by the first value (14) in the expanded scripted field list'); + await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName, '14'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be('31'); + }); + }); + + it('should visualize scripted field in vertical bar chart', async function () { + await filterBar.removeAllFilters(); + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName); + await PageObjects.header.waitUntilLoadingHasFinished(); + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( + '@timestamp', + 'Median of ram_Pain1' + ); + }); + }); + + describe('creating and using Painless string scripted fields', function describeIndexTests() { + const scriptedPainlessFieldName2 = 'painString'; + + it('should create scripted field', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); + await PageObjects.settings.clickScriptedFieldsTab(); + await log.debug('add scripted field'); + await PageObjects.settings.addScriptedField( + scriptedPainlessFieldName2, + 'painless', + 'string', + null, + '1', + "if (doc['response.raw'].value == '200') { return 'good'} else { return 'bad'}" + ); + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + }); + + it('should see scripted field value in Discover', async function () { + const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; + const toTime = 'Sep 18, 2015 @ 18:31:44.000'; + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); + await retry.try(async function () { + await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ngood'); + }); + }); + + // add a test to sort string scripted field + it('should sort scripted field value in Discover', async function () { + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + // after the first click on the scripted field, it becomes secondary sort after time. + // click on the timestamp twice to make it be the secondary sort key. + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 17, 2015 @ 09:48:40.594\nbad'); + }); + + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\ngood'); + }); + }); + + it('should filter by scripted field value in Discover', async function () { + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); + await log.debug('filter by "bad" in the expanded scripted field list'); + await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, 'bad'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be('27'); + }); + await filterBar.removeAllFilters(); + }); + + it('should visualize scripted field in vertical bar chart', async function () { + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); + await PageObjects.header.waitUntilLoadingHasFinished(); + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( + 'Top 5 values of painString' + ); + }); + }); + + describe('creating and using Painless boolean scripted fields', function describeIndexTests() { + const scriptedPainlessFieldName2 = 'painBool'; + + it('should create scripted field', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); + await PageObjects.settings.clickScriptedFieldsTab(); + await log.debug('add scripted field'); + await PageObjects.settings.addScriptedField( + scriptedPainlessFieldName2, + 'painless', + 'boolean', + null, + '1', + "doc['response.raw'].value == '200'" + ); + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + }); + + it('should see scripted field value in Discover', async function () { + const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; + const toTime = 'Sep 18, 2015 @ 18:31:44.000'; + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); + await retry.try(async function () { + await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ntrue'); + }); + }); + + it('should filter by scripted field value in Discover', async function () { + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); + await log.debug('filter by "true" in the expanded scripted field list'); + await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, 'true'); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be('359'); + }); + await filterBar.removeAllFilters(); + }); + + // add a test to sort boolean + // existing bug: https://github.com/elastic/kibana/issues/75519 hence the issue is skipped. + it.skip('should sort scripted field value in Discover', async function () { + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + // after the first click on the scripted field, it becomes secondary sort after time. + // click on the timestamp twice to make it be the secondary sort key. + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('updateExpectedResultHere\ntrue'); + }); + + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('updateExpectedResultHere\nfalse'); + }); + }); + + it('should visualize scripted field in vertical bar chart', async function () { + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); + await PageObjects.header.waitUntilLoadingHasFinished(); + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( + 'Top 5 values of painBool' + ); + }); + }); + + describe('creating and using Painless date scripted fields', function describeIndexTests() { + const scriptedPainlessFieldName2 = 'painDate'; + + it('should create scripted field', async function () { + await PageObjects.settings.navigateTo(); + await PageObjects.settings.clickKibanaIndexPatterns(); + await PageObjects.settings.clickIndexPatternLogstash(); + const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); + await PageObjects.settings.clickScriptedFieldsTab(); + await log.debug('add scripted field'); + await PageObjects.settings.addScriptedField( + scriptedPainlessFieldName2, + 'painless', + 'date', + { format: 'date', datePattern: 'YYYY-MM-DD HH:00' }, + '1', + "doc['utc_time'].value.toEpochMilli() + (1000) * 60 * 60" + ); + await retry.try(async function () { + expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( + startingCount + 1 + ); + }); + }); + + it('should see scripted field value in Discover', async function () { + const fromTime = 'Sep 17, 2015 @ 19:22:00.000'; + const toTime = 'Sep 18, 2015 @ 07:00:00.000'; + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); + await retry.try(async function () { + await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); + }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.953\n2015-09-18 07:00'); + }); + }); + + // add a test to sort date scripted field + // https://github.com/elastic/kibana/issues/75711 + it.skip('should sort scripted field value in Discover', async function () { + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + // after the first click on the scripted field, it becomes secondary sort after time. + // click on the timestamp twice to make it be the secondary sort key. + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await testSubjects.click('docTableHeaderFieldSort_@timestamp'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); + }); + + await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.try(async function () { + const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); + }); + }); + + it('should filter by scripted field value in Discover', async function () { + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); + await log.debug('filter by "Sep 17, 2015 @ 23:00" in the expanded scripted field list'); + await PageObjects.discover.clickFieldListPlusFilter( + scriptedPainlessFieldName2, + '1442531297065' + ); + await PageObjects.header.waitUntilLoadingHasFinished(); + + await retry.try(async function () { + expect(await PageObjects.discover.getHitCount()).to.be('1'); + }); + await filterBar.removeAllFilters(); + }); + + it('should visualize scripted field in vertical bar chart', async function () { + await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); + await PageObjects.header.waitUntilLoadingHasFinished(); + // verify Lens opens a visualization + expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain('painDate'); + }); + }); + }); +} diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index 09f9001d0236a..48cb90393d372 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -30,6 +30,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_mgmt_import_saved_objects')); loadTestFile(require.resolve('./_index_patterns_empty')); loadTestFile(require.resolve('./_scripted_fields')); + loadTestFile(require.resolve('./_scripted_fields_classic_table')); loadTestFile(require.resolve('./_runtime_fields')); loadTestFile(require.resolve('./_field_formatter')); loadTestFile(require.resolve('./_legacy_url_redirect')); diff --git a/test/functional/config.base.js b/test/functional/config.base.js index 147fef2685f5d..f7f210aa7de32 100644 --- a/test/functional/config.base.js +++ b/test/functional/config.base.js @@ -90,6 +90,9 @@ export default async function ({ readConfigFile }) { integrations: { pathname: '/app/integrations', }, + kibana_overview: { + pathname: '/app/kibana_overview', + }, }, junit: { reportName: 'Chrome UI Functional Tests', diff --git a/x-pack/packages/ml/agg_utils/BUILD.bazel b/x-pack/packages/ml/agg_utils/BUILD.bazel new file mode 100644 index 0000000000000..0d59aca092fd5 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/BUILD.bazel @@ -0,0 +1,125 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "agg_utils" +PKG_REQUIRE_NAME = "@kbn/ml-agg-utils" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +# In this array place runtime dependencies, including other packages and NPM packages +# which must be available for this code to run. +# +# To reference other packages use: +# "//repo/relative/path/to/package" +# eg. "//packages/kbn-utils" +# +# To reference a NPM package use: +# "@npm//name-of-package" +# eg. "@npm//lodash" +RUNTIME_DEPS = [ + "@npm//@elastic/elasticsearch", + "@npm//lodash", + "//packages/kbn-field-types", + "//x-pack/packages/ml/is_populated_object", + "//x-pack/packages/ml/string_hash", +] + +# In this array place dependencies necessary to build the types, which will include the +# :npm_module_types target of other packages and packages from NPM, including @types/* +# packages. +# +# To reference the types for another package use: +# "//repo/relative/path/to/package:npm_module_types" +# eg. "//packages/kbn-utils:npm_module_types" +# +# References to NPM packages work the same as RUNTIME_DEPS +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//@types/lodash", + "@npm//@elastic/elasticsearch", + "@npm//tslib", + "//packages/kbn-field-types:npm_module_types", + "//x-pack/packages/ml/is_populated_object:npm_module_types", + "//x-pack/packages/ml/string_hash:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/x-pack/packages/ml/agg_utils/README.md b/x-pack/packages/ml/agg_utils/README.md new file mode 100644 index 0000000000000..63a30e1f1cbef --- /dev/null +++ b/x-pack/packages/ml/agg_utils/README.md @@ -0,0 +1,32 @@ +# @kbn/ml-agg-utils + +This package includes utility functions provided by the ML team to be used in Kibana plugins related to data manipulation and verification. + + + +### `buildSamplerAggregation` (function) + +Wraps the supplied aggregations in a sampler aggregation. +A supplied samplerShardSize (the shard_size parameter of the sampler aggregation) +of less than 1 indicates no sampling, and the aggs are returned as-is. + +**Parameters:** + +- aggs (`any`) +- samplerShardSize (`number`) + +**returns:** Record + +### `getSamplerAggregationsResponsePath` (function) + +**Parameters:** + +- samplerShardSize (`number`) + +**returns:** string[] + +### `getAggIntervals` (function) + +Returns aggregation intervals for the supplied document fields. + + diff --git a/x-pack/packages/ml/agg_utils/jest.config.js b/x-pack/packages/ml/agg_utils/jest.config.js new file mode 100644 index 0000000000000..a22a76d5bf951 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/jest.config.js @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/x-pack/packages/ml/agg_utils'], +}; diff --git a/x-pack/packages/ml/agg_utils/package.json b/x-pack/packages/ml/agg_utils/package.json new file mode 100644 index 0000000000000..11f2fe9d4d450 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/package.json @@ -0,0 +1,13 @@ +{ + "name": "@kbn/ml-agg-utils", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0", + "devDependencies": { + "ts-readme": "^1.1.3" + }, + "scripts": { + "generate-docs": "ts-readme src/index.ts" + } +} diff --git a/x-pack/packages/ml/agg_utils/src/build_sampler_aggregation.test.ts b/x-pack/packages/ml/agg_utils/src/build_sampler_aggregation.test.ts new file mode 100644 index 0000000000000..c792b331ef5b2 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/src/build_sampler_aggregation.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { buildSamplerAggregation } from './build_sampler_aggregation'; + +describe('buildSamplerAggregation', () => { + const testAggs = { + bytes_stats: { + stats: { field: 'bytes' }, + }, + }; + + test('returns wrapped sampler aggregation for sampler shard size of 1000', () => { + expect(buildSamplerAggregation(testAggs, 1000)).toEqual({ + sample: { + sampler: { + shard_size: 1000, + }, + aggs: testAggs, + }, + }); + }); + + test('returns un-sampled aggregation as-is for sampler shard size of 0', () => { + expect(buildSamplerAggregation(testAggs, 0)).toEqual(testAggs); + }); +}); diff --git a/x-pack/packages/ml/agg_utils/src/build_sampler_aggregation.ts b/x-pack/packages/ml/agg_utils/src/build_sampler_aggregation.ts new file mode 100644 index 0000000000000..30345b00caf2f --- /dev/null +++ b/x-pack/packages/ml/agg_utils/src/build_sampler_aggregation.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +/** + * Wraps the supplied aggregations in a sampler aggregation. + * A supplied samplerShardSize (the shard_size parameter of the sampler aggregation) + * of less than 1 indicates no sampling, and the aggs are returned as-is. + */ +export function buildSamplerAggregation( + aggs: any, + samplerShardSize: number +): Record { + if (samplerShardSize < 1) { + return aggs; + } + + return { + sample: { + sampler: { + shard_size: samplerShardSize, + }, + aggs, + }, + }; +} diff --git a/x-pack/packages/ml/agg_utils/src/get_agg_intervals.ts b/x-pack/packages/ml/agg_utils/src/get_agg_intervals.ts new file mode 100644 index 0000000000000..67a6f28497d6e --- /dev/null +++ b/x-pack/packages/ml/agg_utils/src/get_agg_intervals.ts @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { get } from 'lodash'; + +import type { Client } from '@elastic/elasticsearch'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import { KBN_FIELD_TYPES } from '@kbn/field-types'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; +import { stringHash } from '@kbn/ml-string-hash'; + +import { buildSamplerAggregation } from './build_sampler_aggregation'; +import { getSamplerAggregationsResponsePath } from './get_sampler_aggregations_response_path'; + +// TODO Temporary type definition until we can import from `@kbn/core`. +// Copied from src/core/server/elasticsearch/client/types.ts +// as these types aren't part of any package yet. Once they are, remove this completely + +/** + * Client used to query the elasticsearch cluster. + * @deprecated At some point use the one from src/core/server/elasticsearch/client/types.ts when it is made into a package. If it never is, then keep using this one. + * @public + */ +type ElasticsearchClient = Omit< + Client, + 'connectionPool' | 'serializer' | 'extend' | 'close' | 'diagnostic' +>; + +const MAX_CHART_COLUMNS = 20; + +interface HistogramField { + fieldName: string; + type: string; +} + +interface NumericColumnStats { + interval: number; + min: number; + max: number; +} +type NumericColumnStatsMap = Record; + +/** + * Returns aggregation intervals for the supplied document fields. + */ +export const getAggIntervals = async ( + client: ElasticsearchClient, + indexPattern: string, + query: estypes.QueryDslQueryContainer, + fields: HistogramField[], + samplerShardSize: number, + runtimeMappings?: estypes.MappingRuntimeFields +): Promise => { + const numericColumns = fields.filter((field) => { + return field.type === KBN_FIELD_TYPES.NUMBER || field.type === KBN_FIELD_TYPES.DATE; + }); + + if (numericColumns.length === 0) { + return {}; + } + + const minMaxAggs = numericColumns.reduce((aggs, c) => { + const id = stringHash(c.fieldName); + aggs[id] = { + stats: { + field: c.fieldName, + }, + }; + return aggs; + }, {} as Record); + + const body = await client.search({ + index: indexPattern, + size: 0, + body: { + query, + aggs: buildSamplerAggregation(minMaxAggs, samplerShardSize), + size: 0, + ...(isPopulatedObject(runtimeMappings) ? { runtime_mappings: runtimeMappings } : {}), + }, + }); + + const aggsPath = getSamplerAggregationsResponsePath(samplerShardSize); + const aggregations = aggsPath.length > 0 ? get(body.aggregations, aggsPath) : body.aggregations; + + return Object.keys(aggregations).reduce((p, aggName) => { + const stats = [aggregations[aggName].min, aggregations[aggName].max]; + if (!stats.includes(null)) { + const delta = aggregations[aggName].max - aggregations[aggName].min; + + let aggInterval = 1; + + if (delta > MAX_CHART_COLUMNS || delta <= 1) { + aggInterval = delta / (MAX_CHART_COLUMNS - 1); + } + + p[aggName] = { interval: aggInterval, min: stats[0], max: stats[1] }; + } + + return p; + }, {} as NumericColumnStatsMap); +}; diff --git a/x-pack/packages/ml/agg_utils/src/get_sampler_aggregations_response_path.test.ts b/x-pack/packages/ml/agg_utils/src/get_sampler_aggregations_response_path.test.ts new file mode 100644 index 0000000000000..78b30d27aada0 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/src/get_sampler_aggregations_response_path.test.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getSamplerAggregationsResponsePath } from './get_sampler_aggregations_response_path'; + +describe('getSamplerAggregationsResponsePath', () => { + test('returns correct path for sampler shard size of 1000', () => { + expect(getSamplerAggregationsResponsePath(1000)).toEqual(['sample']); + }); + + test('returns correct path for sampler shard size of 0', () => { + expect(getSamplerAggregationsResponsePath(0)).toEqual([]); + }); +}); diff --git a/x-pack/packages/ml/agg_utils/src/get_sampler_aggregations_response_path.ts b/x-pack/packages/ml/agg_utils/src/get_sampler_aggregations_response_path.ts new file mode 100644 index 0000000000000..48a9e5051cacd --- /dev/null +++ b/x-pack/packages/ml/agg_utils/src/get_sampler_aggregations_response_path.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// Returns the path of aggregations in the elasticsearch response, as an array, +// depending on whether sampling is being used. +// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation) +// of less than 1 indicates no sampling, and an empty array is returned. +export function getSamplerAggregationsResponsePath(samplerShardSize: number): string[] { + return samplerShardSize > 0 ? ['sample'] : []; +} diff --git a/x-pack/packages/ml/agg_utils/src/index.ts b/x-pack/packages/ml/agg_utils/src/index.ts new file mode 100644 index 0000000000000..6705a28579b40 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/src/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { buildSamplerAggregation } from './build_sampler_aggregation'; +export { getAggIntervals } from './get_agg_intervals'; +export { getSamplerAggregationsResponsePath } from './get_sampler_aggregations_response_path'; diff --git a/x-pack/packages/ml/agg_utils/tsconfig.json b/x-pack/packages/ml/agg_utils/tsconfig.json new file mode 100644 index 0000000000000..b74cfcda5ee73 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node", + ], + }, + "include": [ + "src/**/*", + ] +} diff --git a/x-pack/packages/ml/agg_utils/yarn.lock b/x-pack/packages/ml/agg_utils/yarn.lock new file mode 100644 index 0000000000000..e826cf14c9da2 --- /dev/null +++ b/x-pack/packages/ml/agg_utils/yarn.lock @@ -0,0 +1,300 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@types/command-line-args@^5.0.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@types/command-line-args/-/command-line-args-5.2.0.tgz#adbb77980a1cc376bb208e3f4142e907410430f6" + integrity sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA== + +"@types/command-line-usage@^5.0.1": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@types/command-line-usage/-/command-line-usage-5.0.2.tgz#ba5e3f6ae5a2009d466679cc431b50635bf1a064" + integrity sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +command-line-application@^0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/command-line-application/-/command-line-application-0.9.6.tgz#03da3db29a0dbee1af601f03198a2f2425d67803" + integrity sha512-7wc7YX7s/hqZWKp4r37IBlW/Bhh92HWeQW2VV++Mt9x35AKFntz9f7A94Zz+AsImHZmRGHd8iNW5m0jUd4GQpg== + dependencies: + "@types/command-line-args" "^5.0.0" + "@types/command-line-usage" "^5.0.1" + chalk "^2.4.1" + command-line-args "^5.1.1" + command-line-usage "^6.0.0" + meant "^1.0.1" + remove-markdown "^0.3.0" + tslib "1.10.0" + +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.0.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + +deep-extend@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +fast-glob@^3.1.1: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +meant@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.3.tgz#67769af9de1d158773e928ae82c456114903554c" + integrity sha512-88ZRGcNxAq4EH38cQ4D85PM57pikCwS8Z99EWHODxN7KBY+UuPiqzRTtZzS8KTXO/ywSWbdjjJST2Hly/EQxLw== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prettier@1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== + +remove-markdown@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/remove-markdown/-/remove-markdown-0.3.0.tgz#5e4b667493a93579728f3d52ecc1db9ca505dc98" + integrity sha512-5392eIuy1mhjM74739VunOlsOYKjsH82rQcTBlJ1bkICVC3dQ3ksQzTHh4jGHQFnM+1xzLzcFOMH+BofqXhroQ== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-readme@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ts-readme/-/ts-readme-1.1.3.tgz#18a73d21f3bb50ee8e2df819bcbbe3a76385b15a" + integrity sha512-GvI+Vu3m/LGBlgrWwzSmvslnz8msJLNrZ7hQ3Ko2B6PMxeXidqsn6fi20IWgepFjOzhKGw/WlG8NmM7jl3DWeg== + dependencies: + command-line-application "^0.9.6" + fast-glob "^3.1.1" + prettier "1.19.1" + +tslib@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" diff --git a/x-pack/packages/ml/is_populated_object/BUILD.bazel b/x-pack/packages/ml/is_populated_object/BUILD.bazel new file mode 100644 index 0000000000000..e89b39af7c986 --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/BUILD.bazel @@ -0,0 +1,114 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "is_populated_object" +PKG_REQUIRE_NAME = "@kbn/ml-is-populated-object" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +# In this array place runtime dependencies, including other packages and NPM packages +# which must be available for this code to run. +# +# To reference other packages use: +# "//repo/relative/path/to/package" +# eg. "//packages/kbn-utils" +# +# To reference a NPM package use: +# "@npm//name-of-package" +# eg. "@npm//lodash" +RUNTIME_DEPS = [ +] + +# In this array place dependencies necessary to build the types, which will include the +# :npm_module_types target of other packages and packages from NPM, including @types/* +# packages. +# +# To reference the types for another package use: +# "//repo/relative/path/to/package:npm_module_types" +# eg. "//packages/kbn-utils:npm_module_types" +# +# References to NPM packages work the same as RUNTIME_DEPS +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/x-pack/packages/ml/is_populated_object/README.md b/x-pack/packages/ml/is_populated_object/README.md new file mode 100644 index 0000000000000..8d2d47329a3fa --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/README.md @@ -0,0 +1,24 @@ +# @kbn/ml-is-populated-object + + + +### `isPopulatedObject` (function) + +A type guard to check record like object structures. + +Examples: + +- `isPopulatedObject({...})` + Limits type to Record + +- `isPopulatedObject({...}, ['attribute'])` + Limits type to Record<'attribute', unknown> + +- `isPopulatedObject({...})` + Limits type to a record with keys of the given interface. + Note that you might want to add keys from the interface to the + array of requiredAttributes to satisfy runtime requirements. + Otherwise you'd just satisfy TS requirements but might still + run into runtime issues. + + diff --git a/x-pack/packages/ml/is_populated_object/jest.config.js b/x-pack/packages/ml/is_populated_object/jest.config.js new file mode 100644 index 0000000000000..8ce420d82a0a4 --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/jest.config.js @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/x-pack/packages/ml/is_populated_object'], +}; diff --git a/x-pack/packages/ml/is_populated_object/package.json b/x-pack/packages/ml/is_populated_object/package.json new file mode 100644 index 0000000000000..3ca3e0fcffb01 --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/package.json @@ -0,0 +1,13 @@ +{ + "name": "@kbn/ml-is-populated-object", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0", + "devDependencies": { + "ts-readme": "^1.1.3" + }, + "scripts": { + "generate-docs": "ts-readme src/index.ts" + } +} diff --git a/x-pack/packages/ml/is_populated_object/src/index.ts b/x-pack/packages/ml/is_populated_object/src/index.ts new file mode 100644 index 0000000000000..b2b1532739628 --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/src/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { isPopulatedObject } from './is_populated_object'; diff --git a/x-pack/packages/ml/is_populated_object/src/is_populated_object.test.ts b/x-pack/packages/ml/is_populated_object/src/is_populated_object.test.ts new file mode 100644 index 0000000000000..c606c0677cf67 --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/src/is_populated_object.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isPopulatedObject } from './is_populated_object'; + +describe('isPopulatedObject', () => { + it('does not allow numbers', () => { + expect(isPopulatedObject(0)).toBe(false); + }); + it('does not allow strings', () => { + expect(isPopulatedObject('')).toBe(false); + }); + it('does not allow null', () => { + expect(isPopulatedObject(null)).toBe(false); + }); + it('does not allow an empty object', () => { + expect(isPopulatedObject({})).toBe(false); + }); + it('allows an object with an attribute', () => { + expect(isPopulatedObject({ attribute: 'value' })).toBe(true); + }); + it('does not allow an object with a non-existing required attribute', () => { + expect(isPopulatedObject({ attribute: 'value' }, ['otherAttribute'])).toBe(false); + }); + it('allows an object with an existing required attribute', () => { + expect(isPopulatedObject({ attribute: 'value' }, ['attribute'])).toBe(true); + }); + it('allows an object with two existing required attributes', () => { + expect( + isPopulatedObject({ attribute1: 'value1', attribute2: 'value2' }, [ + 'attribute1', + 'attribute2', + ]) + ).toBe(true); + }); + it('does not allow an object with two required attributes where one does not exist', () => { + expect( + isPopulatedObject({ attribute1: 'value1', attribute2: 'value2' }, [ + 'attribute1', + 'otherAttribute', + ]) + ).toBe(false); + }); +}); diff --git a/x-pack/plugins/data_visualizer/common/utils/object_utils.ts b/x-pack/packages/ml/is_populated_object/src/is_populated_object.ts similarity index 99% rename from x-pack/plugins/data_visualizer/common/utils/object_utils.ts rename to x-pack/packages/ml/is_populated_object/src/is_populated_object.ts index 537ee9202b4de..43c529206bb63 100644 --- a/x-pack/plugins/data_visualizer/common/utils/object_utils.ts +++ b/x-pack/packages/ml/is_populated_object/src/is_populated_object.ts @@ -5,7 +5,7 @@ * 2.0. */ -/* +/** * A type guard to check record like object structures. * * Examples: diff --git a/x-pack/packages/ml/is_populated_object/tsconfig.json b/x-pack/packages/ml/is_populated_object/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/x-pack/packages/ml/is_populated_object/yarn.lock b/x-pack/packages/ml/is_populated_object/yarn.lock new file mode 100644 index 0000000000000..e826cf14c9da2 --- /dev/null +++ b/x-pack/packages/ml/is_populated_object/yarn.lock @@ -0,0 +1,300 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@types/command-line-args@^5.0.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@types/command-line-args/-/command-line-args-5.2.0.tgz#adbb77980a1cc376bb208e3f4142e907410430f6" + integrity sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA== + +"@types/command-line-usage@^5.0.1": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@types/command-line-usage/-/command-line-usage-5.0.2.tgz#ba5e3f6ae5a2009d466679cc431b50635bf1a064" + integrity sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +command-line-application@^0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/command-line-application/-/command-line-application-0.9.6.tgz#03da3db29a0dbee1af601f03198a2f2425d67803" + integrity sha512-7wc7YX7s/hqZWKp4r37IBlW/Bhh92HWeQW2VV++Mt9x35AKFntz9f7A94Zz+AsImHZmRGHd8iNW5m0jUd4GQpg== + dependencies: + "@types/command-line-args" "^5.0.0" + "@types/command-line-usage" "^5.0.1" + chalk "^2.4.1" + command-line-args "^5.1.1" + command-line-usage "^6.0.0" + meant "^1.0.1" + remove-markdown "^0.3.0" + tslib "1.10.0" + +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.0.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + +deep-extend@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +fast-glob@^3.1.1: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +meant@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.3.tgz#67769af9de1d158773e928ae82c456114903554c" + integrity sha512-88ZRGcNxAq4EH38cQ4D85PM57pikCwS8Z99EWHODxN7KBY+UuPiqzRTtZzS8KTXO/ywSWbdjjJST2Hly/EQxLw== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prettier@1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== + +remove-markdown@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/remove-markdown/-/remove-markdown-0.3.0.tgz#5e4b667493a93579728f3d52ecc1db9ca505dc98" + integrity sha512-5392eIuy1mhjM74739VunOlsOYKjsH82rQcTBlJ1bkICVC3dQ3ksQzTHh4jGHQFnM+1xzLzcFOMH+BofqXhroQ== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-readme@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ts-readme/-/ts-readme-1.1.3.tgz#18a73d21f3bb50ee8e2df819bcbbe3a76385b15a" + integrity sha512-GvI+Vu3m/LGBlgrWwzSmvslnz8msJLNrZ7hQ3Ko2B6PMxeXidqsn6fi20IWgepFjOzhKGw/WlG8NmM7jl3DWeg== + dependencies: + command-line-application "^0.9.6" + fast-glob "^3.1.1" + prettier "1.19.1" + +tslib@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" diff --git a/x-pack/packages/ml/string_hash/BUILD.bazel b/x-pack/packages/ml/string_hash/BUILD.bazel new file mode 100644 index 0000000000000..50e89a8975b51 --- /dev/null +++ b/x-pack/packages/ml/string_hash/BUILD.bazel @@ -0,0 +1,114 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "string_hash" +PKG_REQUIRE_NAME = "@kbn/ml-string-hash" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +# In this array place runtime dependencies, including other packages and NPM packages +# which must be available for this code to run. +# +# To reference other packages use: +# "//repo/relative/path/to/package" +# eg. "//packages/kbn-utils" +# +# To reference a NPM package use: +# "@npm//name-of-package" +# eg. "@npm//lodash" +RUNTIME_DEPS = [ +] + +# In this array place dependencies necessary to build the types, which will include the +# :npm_module_types target of other packages and packages from NPM, including @types/* +# packages. +# +# To reference the types for another package use: +# "//repo/relative/path/to/package:npm_module_types" +# eg. "//packages/kbn-utils:npm_module_types" +# +# References to NPM packages work the same as RUNTIME_DEPS +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + emit_declaration_only = True, + out_dir = "target_types", + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/x-pack/packages/ml/string_hash/README.md b/x-pack/packages/ml/string_hash/README.md new file mode 100644 index 0000000000000..32ea547e20f37 --- /dev/null +++ b/x-pack/packages/ml/string_hash/README.md @@ -0,0 +1,15 @@ +# @kbn/ml-string-hash + + + +### `stringHash` (function) + +Creates a deterministic number based hash out of a string. + +**Parameters:** + +- str (`string`) + +**returns:** number + + diff --git a/x-pack/packages/ml/string_hash/jest.config.js b/x-pack/packages/ml/string_hash/jest.config.js new file mode 100644 index 0000000000000..4f9fe0d1c70e0 --- /dev/null +++ b/x-pack/packages/ml/string_hash/jest.config.js @@ -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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/x-pack/packages/ml/string_hash'], +}; diff --git a/x-pack/packages/ml/string_hash/package.json b/x-pack/packages/ml/string_hash/package.json new file mode 100644 index 0000000000000..81a0bf1c743f5 --- /dev/null +++ b/x-pack/packages/ml/string_hash/package.json @@ -0,0 +1,13 @@ +{ + "name": "@kbn/ml-string-hash", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0", + "devDependencies": { + "ts-readme": "^1.1.3" + }, + "scripts": { + "generate-docs": "ts-readme src/index.ts" + } +} diff --git a/x-pack/packages/ml/string_hash/src/index.ts b/x-pack/packages/ml/string_hash/src/index.ts new file mode 100644 index 0000000000000..f833c95914fb2 --- /dev/null +++ b/x-pack/packages/ml/string_hash/src/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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { stringHash } from './string_hash'; diff --git a/x-pack/packages/ml/string_hash/src/string_hash.test.ts b/x-pack/packages/ml/string_hash/src/string_hash.test.ts new file mode 100644 index 0000000000000..3354e36455790 --- /dev/null +++ b/x-pack/packages/ml/string_hash/src/string_hash.test.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { stringHash } from './string_hash'; + +describe('stringHash', () => { + test('should return a unique number based off a string', () => { + const hash1 = stringHash('the-string-1'); + const hash2 = stringHash('the-string-2'); + expect(hash1).not.toBe(hash2); + }); +}); diff --git a/x-pack/plugins/data_visualizer/common/utils/string_utils.ts b/x-pack/packages/ml/string_hash/src/string_hash.ts similarity index 100% rename from x-pack/plugins/data_visualizer/common/utils/string_utils.ts rename to x-pack/packages/ml/string_hash/src/string_hash.ts diff --git a/x-pack/packages/ml/string_hash/tsconfig.json b/x-pack/packages/ml/string_hash/tsconfig.json new file mode 100644 index 0000000000000..97a3644c3c703 --- /dev/null +++ b/x-pack/packages/ml/string_hash/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "rootDir": "src", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "src/**/*" + ] +} diff --git a/x-pack/packages/ml/string_hash/yarn.lock b/x-pack/packages/ml/string_hash/yarn.lock new file mode 100644 index 0000000000000..e826cf14c9da2 --- /dev/null +++ b/x-pack/packages/ml/string_hash/yarn.lock @@ -0,0 +1,300 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@types/command-line-args@^5.0.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@types/command-line-args/-/command-line-args-5.2.0.tgz#adbb77980a1cc376bb208e3f4142e907410430f6" + integrity sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA== + +"@types/command-line-usage@^5.0.1": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@types/command-line-usage/-/command-line-usage-5.0.2.tgz#ba5e3f6ae5a2009d466679cc431b50635bf1a064" + integrity sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +command-line-application@^0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/command-line-application/-/command-line-application-0.9.6.tgz#03da3db29a0dbee1af601f03198a2f2425d67803" + integrity sha512-7wc7YX7s/hqZWKp4r37IBlW/Bhh92HWeQW2VV++Mt9x35AKFntz9f7A94Zz+AsImHZmRGHd8iNW5m0jUd4GQpg== + dependencies: + "@types/command-line-args" "^5.0.0" + "@types/command-line-usage" "^5.0.1" + chalk "^2.4.1" + command-line-args "^5.1.1" + command-line-usage "^6.0.0" + meant "^1.0.1" + remove-markdown "^0.3.0" + tslib "1.10.0" + +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.0.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + +deep-extend@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +fast-glob@^3.1.1: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +meant@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.3.tgz#67769af9de1d158773e928ae82c456114903554c" + integrity sha512-88ZRGcNxAq4EH38cQ4D85PM57pikCwS8Z99EWHODxN7KBY+UuPiqzRTtZzS8KTXO/ywSWbdjjJST2Hly/EQxLw== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prettier@1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== + +remove-markdown@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/remove-markdown/-/remove-markdown-0.3.0.tgz#5e4b667493a93579728f3d52ecc1db9ca505dc98" + integrity sha512-5392eIuy1mhjM74739VunOlsOYKjsH82rQcTBlJ1bkICVC3dQ3ksQzTHh4jGHQFnM+1xzLzcFOMH+BofqXhroQ== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-readme@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ts-readme/-/ts-readme-1.1.3.tgz#18a73d21f3bb50ee8e2df819bcbbe3a76385b15a" + integrity sha512-GvI+Vu3m/LGBlgrWwzSmvslnz8msJLNrZ7hQ3Ko2B6PMxeXidqsn6fi20IWgepFjOzhKGw/WlG8NmM7jl3DWeg== + dependencies: + command-line-application "^0.9.6" + fast-glob "^3.1.1" + prettier "1.19.1" + +tslib@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" diff --git a/x-pack/plugins/apm/dev_docs/local_setup.md b/x-pack/plugins/apm/dev_docs/local_setup.md index 42aaf686dac5b..24a8db44a3cce 100644 --- a/x-pack/plugins/apm/dev_docs/local_setup.md +++ b/x-pack/plugins/apm/dev_docs/local_setup.md @@ -90,8 +90,8 @@ node x-pack/plugins/apm/scripts/create_apm_users.js --username admin --password This will create: -- **viewer_user**: User with `viewer` role (read-only) -- **editor_user**: User with `editor` role (read/write) +- **viewer**: User with `viewer` role (read-only) +- **editor**: User with `editor` role (read/write) # Debugging Elasticsearch queries diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts index 65591bf991ab8..c7f33301a5dfc 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/no_data_screen.ts @@ -29,7 +29,7 @@ describe('No data screen', () => { headers: { 'kbn-xsrf': true, }, - auth: { user: 'editor_user', pass: 'changeme' }, + auth: { user: 'editor', pass: 'changeme' }, }); }); @@ -57,7 +57,7 @@ describe('No data screen', () => { metric: '', }, headers: { 'kbn-xsrf': true }, - auth: { user: 'editor_user', pass: 'changeme' }, + auth: { user: 'editor', pass: 'changeme' }, }); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts index bf0be24353847..94c1f44cbcffc 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts @@ -11,11 +11,11 @@ import moment from 'moment'; import { AXE_CONFIG, AXE_OPTIONS } from '@kbn/axe-config'; Cypress.Commands.add('loginAsViewerUser', () => { - cy.loginAs({ username: 'viewer_user', password: 'changeme' }); + cy.loginAs({ username: 'viewer', password: 'changeme' }); }); Cypress.Commands.add('loginAsEditorUser', () => { - cy.loginAs({ username: 'editor_user', password: 'changeme' }); + cy.loginAs({ username: 'editor', password: 'changeme' }); }); Cypress.Commands.add( diff --git a/x-pack/plugins/apm/scripts/create_apm_users.js b/x-pack/plugins/apm/scripts/create_apm_users.js index 37a70c70ef3b0..8cef6ebb6c7ae 100644 --- a/x-pack/plugins/apm/scripts/create_apm_users.js +++ b/x-pack/plugins/apm/scripts/create_apm_users.js @@ -7,8 +7,8 @@ /* * This script will create two users - * - editor_user - * - viewer_user + * - editor + * - viewer * * Usage: node create-apm-users.js ******************************/ diff --git a/x-pack/plugins/apm/scripts/create_apm_users/create_apm_users.ts b/x-pack/plugins/apm/scripts/create_apm_users/create_apm_users.ts index f7d0ea2e78ed8..7532392c9a8b4 100644 --- a/x-pack/plugins/apm/scripts/create_apm_users/create_apm_users.ts +++ b/x-pack/plugins/apm/scripts/create_apm_users/create_apm_users.ts @@ -42,8 +42,8 @@ export async function createApmUsers({ // user definitions const users = [ - { username: 'viewer_user', roles: ['viewer'] }, - { username: 'editor_user', roles: ['editor'] }, + { username: 'viewer', roles: ['viewer'] }, + { username: 'editor', roles: ['editor'] }, ]; // create users diff --git a/x-pack/plugins/data_visualizer/common/types/field_stats.ts b/x-pack/plugins/data_visualizer/common/types/field_stats.ts index 9cc1f7d84f4e2..75fa662281fb3 100644 --- a/x-pack/plugins/data_visualizer/common/types/field_stats.ts +++ b/x-pack/plugins/data_visualizer/common/types/field_stats.ts @@ -8,7 +8,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Query } from '@kbn/es-query'; import { IKibanaSearchResponse } from '@kbn/data-plugin/common'; -import { isPopulatedObject } from '../utils/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { TimeBucketsInterval } from '../services/time_buckets'; export interface FieldData { diff --git a/x-pack/plugins/data_visualizer/common/types/index.ts b/x-pack/plugins/data_visualizer/common/types/index.ts index 6ab0649bfb9e6..395c9f2f595c2 100644 --- a/x-pack/plugins/data_visualizer/common/types/index.ts +++ b/x-pack/plugins/data_visualizer/common/types/index.ts @@ -6,7 +6,7 @@ */ import type { SimpleSavedObject } from '@kbn/core/public'; -import { isPopulatedObject } from '../utils/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export type { JobFieldType } from './job_field_type'; export type { FieldRequestConfig, diff --git a/x-pack/plugins/data_visualizer/common/utils/query_utils.ts b/x-pack/plugins/data_visualizer/common/utils/query_utils.ts index dc21bbcae96c3..9f0f746f8909b 100644 --- a/x-pack/plugins/data_visualizer/common/utils/query_utils.ts +++ b/x-pack/plugins/data_visualizer/common/utils/query_utils.ts @@ -40,35 +40,6 @@ export function buildBaseFilterCriteria( return filterCriteria; } -// Wraps the supplied aggregations in a sampler aggregation. -// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation) -// of less than 1 indicates no sampling, and the aggs are returned as-is. -export function buildSamplerAggregation( - aggs: any, - samplerShardSize: number -): Record { - if (samplerShardSize < 1) { - return aggs; - } - - return { - sample: { - sampler: { - shard_size: samplerShardSize, - }, - aggs, - }, - }; -} - -// Returns the path of aggregations in the elasticsearch response, as an array, -// depending on whether sampling is being used. -// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation) -// of less than 1 indicates no sampling, and an empty array is returned. -export function getSamplerAggregationsResponsePath(samplerShardSize: number): string[] { - return samplerShardSize > 0 ? ['sample'] : []; -} - // Returns a name which is safe to use in elasticsearch aggregations for the supplied // field name. Aggregation names must be alpha-numeric and can only contain '_' and '-' characters, // so if the supplied field names contains disallowed characters, the provided index diff --git a/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts b/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts index 6b2cb78d73274..10179d5e51732 100644 --- a/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts +++ b/x-pack/plugins/data_visualizer/common/utils/runtime_field_utils.ts @@ -6,7 +6,7 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RUNTIME_FIELD_TYPES } from '@kbn/data-plugin/common'; -import { isPopulatedObject } from './object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; type RuntimeType = typeof RUNTIME_FIELD_TYPES[number]; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts index c7cfc11c4d630..36b84afadfb04 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/components/full_time_range_selector/full_time_range_selector_service.ts @@ -12,7 +12,7 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { i18n } from '@kbn/i18n'; import type { ToastsStart } from '@kbn/core/public'; import { DataView } from '@kbn/data-views-plugin/public'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { getTimeFieldRange } from '../../services/time_field_range'; import type { GetTimeFieldRangeResponse } from '../../../../../common/types/time_field_request'; import { addExcludeFrozenToQuery } from '../../utils/query_utils'; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_boolean_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_boolean_field_stats.ts index bceb354295d9c..5b91d3716ffd9 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_boolean_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_boolean_field_stats.ts @@ -14,11 +14,9 @@ import type { ISearchOptions, ISearchStart, } from '@kbn/data-plugin/public'; -import { - buildSamplerAggregation, - getSamplerAggregationsResponsePath, -} from '../../../../../common/utils/query_utils'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; +import { buildSamplerAggregation, getSamplerAggregationsResponsePath } from '@kbn/ml-agg-utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + import type { Field, BooleanFieldStats, diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_date_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_date_field_stats.ts index 705fe8c002319..1f55f8117c1be 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_date_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_date_field_stats.ts @@ -15,11 +15,8 @@ import type { ISearchOptions, ISearchStart, } from '@kbn/data-plugin/public'; -import { - buildSamplerAggregation, - getSamplerAggregationsResponsePath, -} from '../../../../../common/utils/query_utils'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; +import { buildSamplerAggregation, getSamplerAggregationsResponsePath } from '@kbn/ml-agg-utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { FieldStatsCommonRequestParams } from '../../../../../common/types/field_stats'; import type { Field, DateFieldStats, Aggs } from '../../../../../common/types/field_stats'; import { FieldStatsError, isIKibanaSearchResponse } from '../../../../../common/types/field_stats'; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_document_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_document_stats.ts index 6cd04de16fa6c..dd654e312e0ef 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_document_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_document_stats.ts @@ -7,8 +7,8 @@ import { each, get } from 'lodash'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { buildBaseFilterCriteria } from '../../../../../common/utils/query_utils'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; import type { DocumentCountStats, OverallStatsSearchStrategyParams, diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_field_examples.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_field_examples.ts index 8b057caecee7c..0e04665256e20 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_field_examples.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_field_examples.ts @@ -14,8 +14,8 @@ import type { ISearchOptions, ISearchStart, } from '@kbn/data-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { buildBaseFilterCriteria } from '../../../../../common/utils/query_utils'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; import type { Field, FieldExamples, diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_numeric_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_numeric_field_stats.ts index 163cb2585f3a6..033f4469b0bc2 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_numeric_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_numeric_field_stats.ts @@ -16,17 +16,14 @@ import { ISearchOptions, } from '@kbn/data-plugin/common'; import type { ISearchStart } from '@kbn/data-plugin/public'; +import { buildSamplerAggregation, getSamplerAggregationsResponsePath } from '@kbn/ml-agg-utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { MAX_PERCENT, PERCENTILE_SPACING, SAMPLER_TOP_TERMS_SHARD_SIZE, SAMPLER_TOP_TERMS_THRESHOLD, } from './constants'; -import { - buildSamplerAggregation, - getSamplerAggregationsResponsePath, -} from '../../../../../common/utils/query_utils'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; import type { Aggs, FieldStatsCommonRequestParams } from '../../../../../common/types/field_stats'; import type { Field, diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_string_field_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_string_field_stats.ts index af4777a677bf9..60306ded5d8f4 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_string_field_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/get_string_field_stats.ts @@ -15,12 +15,9 @@ import type { ISearchOptions, ISearchStart, } from '@kbn/data-plugin/public'; +import { buildSamplerAggregation, getSamplerAggregationsResponsePath } from '@kbn/ml-agg-utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { SAMPLER_TOP_TERMS_SHARD_SIZE, SAMPLER_TOP_TERMS_THRESHOLD } from './constants'; -import { - buildSamplerAggregation, - getSamplerAggregationsResponsePath, -} from '../../../../../common/utils/query_utils'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; import type { Aggs, Bucket, diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/overall_stats.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/overall_stats.ts index 6a25fac65efe5..a25b3974d45b0 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/overall_stats.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/search_strategy/requests/overall_stats.ts @@ -9,14 +9,13 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { get } from 'lodash'; import { Query } from '@kbn/es-query'; import { IKibanaSearchResponse } from '@kbn/data-plugin/common'; +import { buildSamplerAggregation, getSamplerAggregationsResponsePath } from '@kbn/ml-agg-utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { buildBaseFilterCriteria, - buildSamplerAggregation, getSafeAggregationName, - getSamplerAggregationsResponsePath, } from '../../../../../common/utils/query_utils'; import { getDatafeedAggregations } from '../../../../../common/utils/datafeed_utils'; -import { isPopulatedObject } from '../../../../../common/utils/object_utils'; import { AggregatableField, NonAggregatableField } from '../../types/overall_stats'; import { AggCardinality, Aggs } from '../../../../../common/types/field_stats'; diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/error_utils.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/error_utils.ts index d89a9aca112b3..e8992764a7f97 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/error_utils.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/error_utils.ts @@ -7,7 +7,7 @@ import { HttpFetchError } from '@kbn/core/public'; import Boom from '@hapi/boom'; -import { isPopulatedObject } from '../../../../common/utils/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export interface WrappedError { body: { diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/query_utils.ts b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/query_utils.ts index 43c5d49d1986f..5ceda44fa44b3 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/query_utils.ts +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/utils/query_utils.ts @@ -7,7 +7,7 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { cloneDeep } from 'lodash'; -import { isPopulatedObject } from '../../../../common/utils/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export const addExcludeFrozenToQuery = (originalQuery: QueryDslQueryContainer | undefined) => { const FROZEN_TIER_TERM = { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx index e7c98332ee651..b4ddf18b8adb0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/shared_columns.tsx @@ -86,9 +86,9 @@ export const ACTIONS_COLUMN = { try { const query = (item as Query).key || (item as RecentQuery).query_string || '""'; - const response = await http.get<{ id: string }>( + const response = await http.post<{ id: string }>( `/internal/app_search/engines/${engineName}/curations/find_or_create`, - { query: { query } } + { body: JSON.stringify({ query }) } ); navigateToUrl(generateEnginePath(ENGINE_CURATION_PATH, { curationId: response.id })); } catch (e) { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/test_helpers/shared_columns_tests.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/test_helpers/shared_columns_tests.tsx index d9ffb83a561c4..3033c1dcbeea0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/test_helpers/shared_columns_tests.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/analytics/components/analytics_tables/test_helpers/shared_columns_tests.tsx @@ -44,35 +44,35 @@ export const runActionColumnTests = (wrapper: ReactWrapper) => { describe('edit action', () => { it('calls the find_or_create curation API, then navigates the user to the curation', async () => { - http.get.mockReturnValue(Promise.resolve({ id: 'cur-123456789' })); + http.post.mockReturnValue(Promise.resolve({ id: 'cur-123456789' })); wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').first().simulate('click'); await nextTick(); - expect(http.get).toHaveBeenCalledWith( + expect(http.post).toHaveBeenCalledWith( '/internal/app_search/engines/some-engine/curations/find_or_create', { - query: { query: 'some search' }, + body: JSON.stringify({ query: 'some search' }), } ); expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-123456789'); }); it('falls back to "" for the empty query', async () => { - http.get.mockReturnValue(Promise.resolve({ id: 'cur-987654321' })); + http.post.mockReturnValue(Promise.resolve({ id: 'cur-987654321' })); wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').last().simulate('click'); await nextTick(); - expect(http.get).toHaveBeenCalledWith( + expect(http.post).toHaveBeenCalledWith( '/internal/app_search/engines/some-engine/curations/find_or_create', { - query: { query: '""' }, + body: JSON.stringify({ query: '""' }), } ); expect(navigateToUrl).toHaveBeenCalledWith('/engines/some-engine/curations/cur-987654321'); }); it('handles API errors', async () => { - http.get.mockReturnValue(Promise.reject()); + http.post.mockReturnValue(Promise.reject()); wrapper.find('[data-test-subj="AnalyticsTableEditQueryButton"]').first().simulate('click'); await nextTick(); diff --git a/x-pack/plugins/enterprise_search/server/integrations.ts b/x-pack/plugins/enterprise_search/server/integrations.ts index 140e36ba15555..ec3a13f526528 100644 --- a/x-pack/plugins/enterprise_search/server/integrations.ts +++ b/x-pack/plugins/enterprise_search/server/integrations.ts @@ -175,7 +175,7 @@ const workplaceSearchIntegrations: WorkplaceSearchIntegration[] = [ } ), categories: ['enterprise_search', 'file_storage'], - uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/network_drive', + uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/network_drive/custom', }, { id: 'onedrive', @@ -203,7 +203,7 @@ const workplaceSearchIntegrations: WorkplaceSearchIntegration[] = [ } ), categories: ['enterprise_search', 'microsoft_365', 'communications', 'productivity'], - uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/outlook', + uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/outlook/custom', }, { id: 'salesforce', @@ -280,7 +280,7 @@ const workplaceSearchIntegrations: WorkplaceSearchIntegration[] = [ } ), categories: ['enterprise_search', 'file_storage', 'microsoft_365'], - uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/sharepoint_server', + uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/share_point_server/custom', }, { id: 'slack', @@ -308,7 +308,7 @@ const workplaceSearchIntegrations: WorkplaceSearchIntegration[] = [ } ), categories: ['enterprise_search', 'microsoft_365', 'communications', 'productivity'], - uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/teams', + uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/teams/custom', }, { id: 'zendesk', @@ -336,7 +336,7 @@ const workplaceSearchIntegrations: WorkplaceSearchIntegration[] = [ } ), categories: ['enterprise_search', 'communications', 'productivity'], - uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/zoom', + uiInternalPath: '/app/enterprise_search/workplace_search/sources/add/zoom/custom', }, ]; diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts index b930b449e97d1..8e2221b8d8f32 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.test.ts @@ -195,13 +195,13 @@ describe('curations routes', () => { }); }); - describe('GET /internal/app_search/engines/{engineName}/curations/find_or_create', () => { + describe('POST /internal/app_search/engines/{engineName}/curations/find_or_create', () => { let mockRouter: MockRouter; beforeEach(() => { jest.clearAllMocks(); mockRouter = new MockRouter({ - method: 'get', + method: 'post', path: '/internal/app_search/engines/{engineName}/curations/find_or_create', }); @@ -219,12 +219,12 @@ describe('curations routes', () => { describe('validates', () => { it('required query param', () => { - const request = { query: { query: 'some query' } }; + const request = { body: { query: 'some query' } }; mockRouter.shouldValidate(request); }); it('missing query', () => { - const request = { query: {} }; + const request = { body: {} }; mockRouter.shouldThrow(request); }); }); diff --git a/x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts index a7282e5dc6cc4..27927f2c36913 100644 --- a/x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts +++ b/x-pack/plugins/enterprise_search/server/routes/app_search/curations.ts @@ -105,14 +105,14 @@ export function registerCurationsRoutes({ }) ); - router.get( + router.post( { path: '/internal/app_search/engines/{engineName}/curations/find_or_create', validate: { params: schema.object({ engineName: schema.string(), }), - query: schema.object({ + body: schema.object({ query: schema.string(), }), }, diff --git a/x-pack/plugins/file_upload/common/utils.ts b/x-pack/plugins/file_upload/common/utils.ts deleted file mode 100644 index 5ef6c56392e56..0000000000000 --- a/x-pack/plugins/file_upload/common/utils.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const isPopulatedObject = ( - arg: unknown, - requiredAttributes: U[] = [] -): arg is Record => { - return ( - typeof arg === 'object' && - arg !== null && - Object.keys(arg).length > 0 && - (requiredAttributes.length === 0 || - requiredAttributes.every((d) => ({}.hasOwnProperty.call(arg, d)))) - ); -}; diff --git a/x-pack/plugins/file_upload/public/importer/importer.ts b/x-pack/plugins/file_upload/public/importer/importer.ts index 58809e736720c..8928c4849435f 100644 --- a/x-pack/plugins/file_upload/public/importer/importer.ts +++ b/x-pack/plugins/file_upload/public/importer/importer.ts @@ -8,6 +8,7 @@ import { chunk, intersection } from 'lodash'; import moment from 'moment'; import { i18n } from '@kbn/i18n'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { getHttp } from '../kibana_services'; import { MB } from '../../common/constants'; import type { @@ -19,7 +20,6 @@ import type { IngestPipeline, } from '../../common/types'; import { CreateDocsResponse, IImporter, ImportResults } from './types'; -import { isPopulatedObject } from '../../common/utils'; const CHUNK_SIZE = 5000; const REDUCED_CHUNK_SIZE = 100; diff --git a/x-pack/plugins/file_upload/server/get_time_field_range.ts b/x-pack/plugins/file_upload/server/get_time_field_range.ts index e8b21e6807a8f..32bf1766f8d90 100644 --- a/x-pack/plugins/file_upload/server/get_time_field_range.ts +++ b/x-pack/plugins/file_upload/server/get_time_field_range.ts @@ -7,7 +7,7 @@ import { IScopedClusterClient } from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { isPopulatedObject } from '../common/utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export async function getTimeFieldRange( client: IScopedClusterClient, diff --git a/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts b/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts index 0daf9713d8263..75c2aa886ef68 100644 --- a/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts +++ b/x-pack/plugins/file_upload/server/utils/runtime_field_utils.ts @@ -7,7 +7,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RUNTIME_FIELD_TYPES } from '@kbn/data-plugin/common'; -import { isPopulatedObject } from '../../common/utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; type RuntimeType = typeof RUNTIME_FIELD_TYPES[number]; diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx index 8ecdffce3ed44..02cc458295677 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/advanced_tab.tsx @@ -63,7 +63,7 @@ export const AdvancedTab: React.FunctionComponent = ({ selecte isFleetServerReady, serviceToken, fleetServerHost: fleetServerHostForm.fleetServerHost, - fleetServerPolicyId, + fleetServerPolicyId: fleetServerPolicyId || selectedPolicyId, deploymentMode, disabled: !Boolean(serviceToken), }), diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/select_agent_policy.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/select_agent_policy.tsx index d7f2301b663f1..24099534db80c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/select_agent_policy.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/fleet_server_instructions/steps/select_agent_policy.tsx @@ -26,7 +26,7 @@ export const getSelectAgentPolicyStep = ({ }): EuiStepProps => { return { title: - eligibleFleetServerPolicies.length === 0 + eligibleFleetServerPolicies.length === 0 && !policyId ? i18n.translate('xpack.fleet.fleetServerSetup.stepCreateAgentPolicyTitle', { defaultMessage: 'Create a policy for Fleet Server', }) diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_policy_select_create.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_policy_select_create.tsx index 4dab3b054bc8d..35a65deffc70b 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_policy_select_create.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_policy_select_create.tsx @@ -79,9 +79,9 @@ export const SelectCreateAgentPolicy: React.FC = ({ ); useEffect(() => { - setShowCreatePolicy(regularAgentPolicies.length === 0); + setShowCreatePolicy(regularAgentPolicies.length === 0 && !selectedPolicyId); setNewName(incrementPolicyName(regularAgentPolicies, isFleetServerPolicy)); - }, [regularAgentPolicies, isFleetServerPolicy]); + }, [regularAgentPolicies, isFleetServerPolicy, selectedPolicyId]); const onAgentPolicyCreated = useCallback( async (policy: AgentPolicy | null, errorMessage?: JSX.Element) => { diff --git a/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx b/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx index 1d6c14c09136a..c0d7766fc22d8 100644 --- a/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx +++ b/x-pack/plugins/lens/public/drag_drop/drag_drop.test.tsx @@ -41,7 +41,14 @@ describe('DragDrop', () => { const value = { id: '1', - humanData: { label: 'hello', groupLabel: 'X', position: 1, canSwap: true, canDuplicate: true }, + humanData: { + label: 'hello', + groupLabel: 'X', + position: 1, + canSwap: true, + canDuplicate: true, + layerNumber: 0, + }, }; test('renders if nothing is being dragged', () => { @@ -205,7 +212,7 @@ describe('DragDrop', () => { order={[2, 0, 1, 0]} onDrop={(x: unknown) => {}} dropTypes={undefined} - value={{ id: '2', humanData: { label: 'label2' } }} + value={{ id: '2', humanData: { label: 'label2', layerNumber: 0 } }} > @@ -231,7 +238,7 @@ describe('DragDrop', () => { }} > @@ -286,7 +293,7 @@ describe('DragDrop', () => { registerDropTarget={jest.fn()} > @@ -329,7 +336,7 @@ describe('DragDrop', () => { draggable: true, value: { id: '1', - humanData: { label: 'Label1', position: 1 }, + humanData: { label: 'Label1', position: 1, layerNumber: 0 }, }, children: '1', order: [2, 0, 0, 0], @@ -341,7 +348,7 @@ describe('DragDrop', () => { value: { id: '2', - humanData: { label: 'label2', position: 1 }, + humanData: { label: 'label2', position: 1, layerNumber: 0 }, }, onDrop, dropTypes: ['move_compatible'] as DropType[], @@ -358,6 +365,7 @@ describe('DragDrop', () => { groupLabel: 'Y', canSwap: true, canDuplicate: true, + layerNumber: 0, }, }, onDrop, @@ -373,7 +381,7 @@ describe('DragDrop', () => { dragType: 'move' as 'copy' | 'move', value: { id: '4', - humanData: { label: 'label4', position: 2, groupLabel: 'Y' }, + humanData: { label: 'label4', position: 2, groupLabel: 'Y', layerNumber: 0 }, }, order: [2, 0, 2, 1], }, @@ -415,11 +423,11 @@ describe('DragDrop', () => { }); keyboardHandler.simulate('keydown', { key: 'Enter' }); expect(setA11yMessage).toBeCalledWith( - `You're dragging Label1 from at position 1 over label3 from Y group at position 1. Press space or enter to replace label3 with Label1. Hold alt or option to duplicate. Hold shift to swap.` + `You're dragging Label1 from at position 1 in layer 0 over label3 from Y group at position 1 in layer 0. Press space or enter to replace label3 with Label1. Hold alt or option to duplicate. Hold shift to swap.` ); expect(setActiveDropTarget).toBeCalledWith(undefined); expect(onDrop).toBeCalledWith( - { humanData: { label: 'Label1', position: 1 }, id: '1' }, + { humanData: { label: 'Label1', position: 1, layerNumber: 0 }, id: '1' }, 'move_compatible' ); }); @@ -474,7 +482,7 @@ describe('DragDrop', () => { draggable: true, value: { id: '1', - humanData: { label: 'Label1', position: 1 }, + humanData: { label: 'Label1', position: 1, layerNumber: 0 }, }, children: '1', order: [2, 0, 0, 0], @@ -486,7 +494,7 @@ describe('DragDrop', () => { value: { id: '2', - humanData: { label: 'label2', position: 1 }, + humanData: { label: 'label2', position: 1, layerNumber: 0 }, }, onDrop, dropTypes: ['move_compatible'] as DropType[], @@ -533,7 +541,7 @@ describe('DragDrop', () => { component = mount( { registerDropTarget={jest.fn()} > @@ -629,18 +637,24 @@ describe('DragDrop', () => { component.find('SingleDropInner').at(0).simulate('dragover'); component.find('SingleDropInner').at(0).simulate('drop'); - expect(onDrop).toBeCalledWith({ humanData: { label: 'Label1' }, id: '1' }, 'move_compatible'); + expect(onDrop).toBeCalledWith( + { humanData: { label: 'Label1', layerNumber: 0 }, id: '1' }, + 'move_compatible' + ); component.find('SingleDropInner').at(1).simulate('dragover'); component.find('SingleDropInner').at(1).simulate('drop'); expect(onDrop).toBeCalledWith( - { humanData: { label: 'Label1' }, id: '1' }, + { humanData: { label: 'Label1', layerNumber: 0 }, id: '1' }, 'duplicate_compatible' ); component.find('SingleDropInner').at(2).simulate('dragover'); component.find('SingleDropInner').at(2).simulate('drop'); - expect(onDrop).toBeCalledWith({ humanData: { label: 'Label1' }, id: '1' }, 'swap_compatible'); + expect(onDrop).toBeCalledWith( + { humanData: { label: 'Label1', layerNumber: 0 }, id: '1' }, + 'swap_compatible' + ); }); test('pressing Alt or Shift when dragging over the main drop target sets extra drop target as active', () => { @@ -693,7 +707,7 @@ describe('DragDrop', () => { draggable: true, value: { id: '1', - humanData: { label: 'Label1', position: 1 }, + humanData: { label: 'Label1', position: 1, layerNumber: 0 }, }, children: '1', order: [2, 0, 0, 0], @@ -705,7 +719,7 @@ describe('DragDrop', () => { value: { id: '2', - humanData: { label: 'label2', position: 1 }, + humanData: { label: 'label2', position: 1, layerNumber: 0 }, }, onDrop, dropTypes: ['move_compatible', 'duplicate_compatible', 'swap_compatible'] as DropType[], @@ -716,7 +730,7 @@ describe('DragDrop', () => { dragType: 'move' as const, value: { id: '3', - humanData: { label: 'label3', position: 1, groupLabel: 'Y' }, + humanData: { label: 'label3', position: 1, groupLabel: 'Y', layerNumber: 0 }, }, onDrop, dropTypes: ['replace_compatible'] as DropType[], @@ -734,6 +748,7 @@ describe('DragDrop', () => { humanData: { label: 'label2', position: 1, + layerNumber: 0, }, id: '2', onDrop, @@ -743,6 +758,7 @@ describe('DragDrop', () => { humanData: { label: 'label2', position: 1, + layerNumber: 0, }, id: '2', onDrop, @@ -753,6 +769,7 @@ describe('DragDrop', () => { groupLabel: 'Y', label: 'label3', position: 1, + layerNumber: 0, }, id: '3', onDrop, @@ -942,18 +959,18 @@ describe('DragDrop', () => { const items = [ { id: '1', - humanData: { label: 'Label1', position: 1, groupLabel: 'X' }, + humanData: { label: 'Label1', position: 1, groupLabel: 'X', layerNumber: 0 }, onDrop, draggable: true, }, { id: '2', - humanData: { label: 'label2', position: 2, groupLabel: 'X' }, + humanData: { label: 'label2', position: 2, groupLabel: 'X', layerNumber: 0 }, onDrop, }, { id: '3', - humanData: { label: 'label3', position: 3, groupLabel: 'X' }, + humanData: { label: 'label3', position: 3, groupLabel: 'X', layerNumber: 0 }, onDrop, }, ]; diff --git a/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx b/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx index 0d247825b6a17..a21656421a96f 100644 --- a/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx +++ b/x-pack/plugins/lens/public/drag_drop/providers/announcements.tsx @@ -22,19 +22,21 @@ interface CustomAnnouncementsType { const replaceAnnouncement = { selectedTarget: ( - { label, groupLabel, position }: HumanData, + { label, groupLabel, position, layerNumber }: HumanData, { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, canSwap, canDuplicate, + canCombine, + layerNumber: dropLayerNumber, }: HumanData, announceModifierKeys?: boolean ) => { if (announceModifierKeys && (canSwap || canDuplicate)) { return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.replaceMain', { - defaultMessage: `You're dragging {label} from {groupLabel} at position {position} over {dropLabel} from {dropGroupLabel} group at position {dropPosition}. Press space or enter to replace {dropLabel} with {label}.{duplicateCopy}{swapCopy}`, + defaultMessage: `You're dragging {label} from {groupLabel} at position {position} in layer {layerNumber} over {dropLabel} from {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Press space or enter to replace {dropLabel} with {label}.{duplicateCopy}{swapCopy}{combineCopy}`, values: { label, groupLabel, @@ -44,63 +46,76 @@ const replaceAnnouncement = { dropPosition, duplicateCopy: canDuplicate ? DUPLICATE_SHORT : '', swapCopy: canSwap ? SWAP_SHORT : '', + combineCopy: canCombine ? COMBINE_SHORT : '', + layerNumber, + dropLayerNumber, }, }); } - return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.replace', { - defaultMessage: `Replace {dropLabel} in {dropGroupLabel} group at position {dropPosition} with {label}. Press space or enter to replace.`, + defaultMessage: `Replace {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber} with {label}. Press space or enter to replace.`, values: { label, dropLabel, dropGroupLabel, dropPosition, + dropLayerNumber, }, }); }, - dropped: ({ label }: HumanData, { label: dropLabel, groupLabel, position }: HumanData) => - i18n.translate('xpack.lens.dragDrop.announce.duplicated.replace', { - defaultMessage: 'Replaced {dropLabel} with {label} in {groupLabel} at position {position}', + dropped: ( + { label }: HumanData, + { label: dropLabel, groupLabel, position, layerNumber: dropLayerNumber }: HumanData + ) => { + return i18n.translate('xpack.lens.dragDrop.announce.duplicated.replace', { + defaultMessage: + 'Replaced {dropLabel} with {label} in {groupLabel} at position {position} in layer {dropLayerNumber}', values: { label, dropLabel, groupLabel, position, + dropLayerNumber, }, - }), + }); + }, }; const duplicateAnnouncement = { selectedTarget: ( - { label, groupLabel }: HumanData, + { label, groupLabel, layerNumber }: HumanData, { groupLabel: dropGroupLabel, position }: HumanData ) => { if (groupLabel !== dropGroupLabel) { return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.duplicated', { - defaultMessage: `Duplicate {label} to {dropGroupLabel} group at position {position}. Hold Alt or Option and press space or enter to duplicate`, + defaultMessage: `Duplicate {label} to {dropGroupLabel} group at position {position} in layer {layerNumber}. Hold Alt or Option and press space or enter to duplicate`, values: { label, dropGroupLabel, position, + layerNumber, }, }); } return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.duplicatedInGroup', { - defaultMessage: `Duplicate {label} to {dropGroupLabel} group at position {position}. Press space or enter to duplicate`, + defaultMessage: `Duplicate {label} to {dropGroupLabel} group at position {position} in layer {layerNumber}. Press space or enter to duplicate`, values: { label, dropGroupLabel, position, + layerNumber, }, }); }, - dropped: ({ label }: HumanData, { groupLabel, position }: HumanData) => + dropped: ({ label }: HumanData, { groupLabel, position, layerNumber }: HumanData) => i18n.translate('xpack.lens.dragDrop.announce.dropped.duplicated', { - defaultMessage: 'Duplicated {label} in {groupLabel} group at position {position}', + defaultMessage: + 'Duplicated {label} in {groupLabel} group at position {position} in layer {layerNumber}', values: { label, groupLabel, position, + layerNumber, }, }), }; @@ -109,8 +124,8 @@ const reorderAnnouncement = { selectedTarget: ( { label, groupLabel, position: prevPosition }: HumanData, { position }: HumanData - ) => - prevPosition === position + ) => { + return prevPosition === position ? i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.reorderedBack', { defaultMessage: `{label} returned to its initial position {prevPosition}`, values: { @@ -121,12 +136,13 @@ const reorderAnnouncement = { : i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.reordered', { defaultMessage: `Reorder {label} in {groupLabel} group from position {prevPosition} to position {position}. Press space or enter to reorder`, values: { - groupLabel, label, + groupLabel, position, prevPosition, }, - }), + }); + }, dropped: ({ label, groupLabel, position: prevPosition }: HumanData, { position }: HumanData) => i18n.translate('xpack.lens.dragDrop.announce.dropped.reordered', { defaultMessage: @@ -142,7 +158,7 @@ const reorderAnnouncement = { const combineAnnouncement = { selectedTarget: ( - { label, groupLabel, position }: HumanData, + { label, groupLabel, position, layerNumber }: HumanData, { label: dropLabel, groupLabel: dropGroupLabel, @@ -150,12 +166,13 @@ const combineAnnouncement = { canSwap, canDuplicate, canCombine, + layerNumber: dropLayerNumber, }: HumanData, announceModifierKeys?: boolean ) => { if (announceModifierKeys && (canSwap || canDuplicate || canCombine)) { return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combineMain', { - defaultMessage: `You're dragging {label} from {groupLabel} at position {position} over {dropLabel} from {dropGroupLabel} group at position {dropPosition}. Press space or enter to combine {dropLabel} with {label}.{duplicateCopy}{swapCopy}{combineCopy}`, + defaultMessage: `You're dragging {label} from {groupLabel} at position {position} in layer {layerNumber} over {dropLabel} from {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Press space or enter to combine {dropLabel} with {label}.{duplicateCopy}{swapCopy}{combineCopy}`, values: { label, groupLabel, @@ -166,28 +183,35 @@ const combineAnnouncement = { duplicateCopy: canDuplicate ? DUPLICATE_SHORT : '', swapCopy: canSwap ? SWAP_SHORT : '', combineCopy: canCombine ? COMBINE_SHORT : '', + layerNumber, + dropLayerNumber, }, }); } - return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combine', { - defaultMessage: `Combine {dropLabel} in {dropGroupLabel} group at position {dropPosition} with {label}. Press space or enter to combine.`, + defaultMessage: `Combine {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber} with {label}. Press space or enter to combine.`, values: { label, dropLabel, dropGroupLabel, dropPosition, + dropLayerNumber, }, }); }, - dropped: ({ label }: HumanData, { label: dropLabel, groupLabel, position }: HumanData) => + dropped: ( + { label }: HumanData, + { label: dropLabel, groupLabel, position, layerNumber: dropLayerNumber }: HumanData + ) => i18n.translate('xpack.lens.dragDrop.announce.duplicated.combine', { - defaultMessage: 'Combine {dropLabel} with {label} in {groupLabel} at position {position}', + defaultMessage: + 'Combine {dropLabel} with {label} in {groupLabel} at position {position} in layer {dropLayerNumber}', values: { label, dropLabel, groupLabel, position, + dropLayerNumber, }, }), }; @@ -212,7 +236,7 @@ export const announcements: CustomAnnouncementsType = { field_combine: combineAnnouncement.selectedTarget, replace_compatible: replaceAnnouncement.selectedTarget, replace_incompatible: ( - { label, groupLabel, position }: HumanData, + { label, groupLabel, position, layerNumber }: HumanData, { label: dropLabel, groupLabel: dropGroupLabel, @@ -220,14 +244,16 @@ export const announcements: CustomAnnouncementsType = { nextLabel, canSwap, canDuplicate, + canCombine, + layerNumber: dropLayerNumber, }: HumanData, announceModifierKeys?: boolean ) => { - if (announceModifierKeys && (canSwap || canDuplicate)) { + if (announceModifierKeys && (canSwap || canDuplicate || canCombine)) { return i18n.translate( 'xpack.lens.dragDrop.announce.selectedTarget.replaceIncompatibleMain', { - defaultMessage: `You're dragging {label} from {groupLabel} at position {position} over {dropLabel} from {dropGroupLabel} group at position {dropPosition}. Press space or enter to convert {label} to {nextLabel} and replace {dropLabel}.{duplicateCopy}{swapCopy}`, + defaultMessage: `You're dragging {label} from {groupLabel} at position {position} in layer {layerNumber} over {dropLabel} from {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Press space or enter to convert {label} to {nextLabel} and replace {dropLabel}.{duplicateCopy}{swapCopy}{combineCopy}`, values: { label, groupLabel, @@ -238,35 +264,40 @@ export const announcements: CustomAnnouncementsType = { nextLabel, duplicateCopy: canDuplicate ? DUPLICATE_SHORT : '', swapCopy: canSwap ? SWAP_SHORT : '', + combineCopy: canCombine ? COMBINE_SHORT : '', + layerNumber, + dropLayerNumber, }, } ); } return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.replaceIncompatible', { - defaultMessage: `Convert {label} to {nextLabel} and replace {dropLabel} in {dropGroupLabel} group at position {dropPosition}. Press space or enter to replace`, + defaultMessage: `Convert {label} to {nextLabel} and replace {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Press space or enter to replace`, values: { label, - nextLabel, dropLabel, dropGroupLabel, dropPosition, + nextLabel, + dropLayerNumber, }, }); }, move_incompatible: ( - { label, groupLabel, position }: HumanData, + { label, groupLabel, position, layerNumber }: HumanData, { groupLabel: dropGroupLabel, position: dropPosition, nextLabel, canSwap, canDuplicate, + layerNumber: dropLayerNumber, }: HumanData, announceModifierKeys?: boolean ) => { if (announceModifierKeys && (canSwap || canDuplicate)) { return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.moveIncompatibleMain', { - defaultMessage: `You're dragging {label} from {groupLabel} at position {position} over position {dropPosition} in {dropGroupLabel} group. Press space or enter to convert {label} to {nextLabel} and move.{duplicateCopy}{swapCopy}`, + defaultMessage: `You're dragging {label} from {groupLabel} at position {position} in layer {layerNumber} over position {dropPosition} in {dropGroupLabel} group in layer {dropLayerNumber}. Press space or enter to convert {label} to {nextLabel} and move.{duplicateCopy}`, values: { label, groupLabel, @@ -275,29 +306,37 @@ export const announcements: CustomAnnouncementsType = { dropPosition, nextLabel, duplicateCopy: canDuplicate ? DUPLICATE_SHORT : '', - swapCopy: canSwap ? SWAP_SHORT : '', + layerNumber, + dropLayerNumber, }, }); } return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.moveIncompatible', { - defaultMessage: `Convert {label} to {nextLabel} and move to {dropGroupLabel} group at position {dropPosition}. Press space or enter to move`, + defaultMessage: `Convert {label} to {nextLabel} and move to {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Press space or enter to move`, values: { label, - nextLabel, dropGroupLabel, dropPosition, + nextLabel, + dropLayerNumber, }, }); }, move_compatible: ( { label, groupLabel, position }: HumanData, - { groupLabel: dropGroupLabel, position: dropPosition, canSwap, canDuplicate }: HumanData, + { + groupLabel: dropGroupLabel, + position: dropPosition, + canSwap, + canDuplicate, + layerNumber: dropLayerNumber, + }: HumanData, announceModifierKeys?: boolean ) => { if (announceModifierKeys && (canSwap || canDuplicate)) { return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.moveCompatibleMain', { - defaultMessage: `You're dragging {label} from {groupLabel} at position {position} over position {dropPosition} in {dropGroupLabel} group. Press space or enter to move.{duplicateCopy}{swapCopy}`, + defaultMessage: `You're dragging {label} from {groupLabel} at position {position} over position {dropPosition} in {dropGroupLabel} group in layer {dropLayerNumber}. Press space or enter to move.{duplicateCopy}`, values: { label, groupLabel, @@ -305,69 +344,78 @@ export const announcements: CustomAnnouncementsType = { dropGroupLabel, dropPosition, duplicateCopy: canDuplicate ? DUPLICATE_SHORT : '', - swapCopy: canSwap ? SWAP_SHORT : '', + dropLayerNumber, }, }); } return i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.moveCompatible', { - defaultMessage: `Move {label} to {dropGroupLabel} group at position {dropPosition}. Press space or enter to move`, + defaultMessage: `Move {label} to {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Press space or enter to move`, values: { label, dropGroupLabel, dropPosition, + dropLayerNumber, }, }); }, duplicate_incompatible: ( { label }: HumanData, - { groupLabel, position, nextLabel }: HumanData + { groupLabel, position, nextLabel, layerNumber: dropLayerNumber }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.duplicateIncompatible', { defaultMessage: - 'Convert copy of {label} to {nextLabel} and add to {groupLabel} group at position {position}. Hold Alt or Option and press space or enter to duplicate', + 'Convert copy of {label} to {nextLabel} and add to {groupLabel} group at position {position} in layer {dropLayerNumber}. Hold Alt or Option and press space or enter to duplicate', values: { label, groupLabel, position, nextLabel, + dropLayerNumber, }, }), replace_duplicate_incompatible: ( { label }: HumanData, - { label: dropLabel, groupLabel, position, nextLabel }: HumanData + { label: dropLabel, groupLabel, position, nextLabel, layerNumber: dropLayerNumber }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateIncompatible', { defaultMessage: - 'Convert copy of {label} to {nextLabel} and replace {dropLabel} in {groupLabel} group at position {position}. Hold Alt or Option and press space or enter to duplicate and replace', + 'Convert copy of {label} to {nextLabel} and replace {dropLabel} in {groupLabel} group at position {position} in layer {dropLayerNumber}. Hold Alt or Option and press space or enter to duplicate and replace', values: { label, groupLabel, position, dropLabel, nextLabel, + dropLayerNumber, }, }), replace_duplicate_compatible: ( { label }: HumanData, - { label: dropLabel, groupLabel, position }: HumanData + { label: dropLabel, groupLabel, position, layerNumber: dropLayerNumber }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateCompatible', { defaultMessage: - 'Duplicate {label} and replace {dropLabel} in {groupLabel} at position {position}. Hold Alt or Option and press space or enter to duplicate and replace', + 'Duplicate {label} and replace {dropLabel} in {groupLabel} at position {position} in layer {dropLayerNumber}. Hold Alt or Option and press space or enter to duplicate and replace', values: { label, dropLabel, groupLabel, position, + dropLayerNumber, }, }), swap_compatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition }: HumanData + { label, groupLabel, position, layerNumber }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.swapCompatible', { defaultMessage: - 'Swap {label} in {groupLabel} group at position {position} with {dropLabel} in {dropGroupLabel} group at position {dropPosition}. Hold Shift and press space or enter to swap', + 'Swap {label} in {groupLabel} group at position {position} in layer {layerNumber} with {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Hold Shift and press space or enter to swap', values: { label, groupLabel, @@ -375,15 +423,23 @@ export const announcements: CustomAnnouncementsType = { dropLabel, dropGroupLabel, dropPosition, + layerNumber, + dropLayerNumber, }, }), swap_incompatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + { label, groupLabel, position, layerNumber }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + nextLabel, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.swapIncompatible', { defaultMessage: - 'Convert {label} to {nextLabel} in {groupLabel} group at position {position} and swap with {dropLabel} in {dropGroupLabel} group at position {dropPosition}. Hold Shift and press space or enter to swap', + 'Convert {label} to {nextLabel} in {groupLabel} group at position {position} in layer {layerNumber} and swap with {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Hold Shift and press space or enter to swap', values: { label, groupLabel, @@ -392,15 +448,22 @@ export const announcements: CustomAnnouncementsType = { dropGroupLabel, dropPosition, nextLabel, + layerNumber, + dropLayerNumber, }, }), combine_compatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + { label, groupLabel, position, layerNumber }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combineCompatible', { defaultMessage: - 'Combine {label} in {groupLabel} group at position {position} with {dropLabel} in {dropGroupLabel} group at position {dropPosition}. Hold Control and press space or enter to combine', + 'Combine {label} in {groupLabel} group at position {position} in layer {layerNumber} with {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Hold Control and press space or enter to combine', values: { label, groupLabel, @@ -408,15 +471,23 @@ export const announcements: CustomAnnouncementsType = { dropLabel, dropGroupLabel, dropPosition, + layerNumber, + dropLayerNumber, }, }), combine_incompatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + { label, groupLabel, position, layerNumber }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + nextLabel, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.combineIncompatible', { defaultMessage: - 'Convert {label} to {nextLabel} in {groupLabel} group at position {position} and combine with {dropLabel} in {dropGroupLabel} group at position {dropPosition}. Hold Control and press space or enter to combine', + 'Convert {label} to {nextLabel} in {groupLabel} group at position {position} in layer {layerNumber} and combine with {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}. Hold Control and press space or enter to combine', values: { label, groupLabel, @@ -425,6 +496,8 @@ export const announcements: CustomAnnouncementsType = { dropGroupLabel, dropPosition, nextLabel, + dropLayerNumber, + layerNumber, }, }), }, @@ -436,92 +509,110 @@ export const announcements: CustomAnnouncementsType = { replace_compatible: replaceAnnouncement.dropped, replace_incompatible: ( { label }: HumanData, - { label: dropLabel, groupLabel, position, nextLabel }: HumanData + { label: dropLabel, groupLabel, position, nextLabel, layerNumber: dropLayerNumber }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.replaceIncompatible', { defaultMessage: - 'Converted {label} to {nextLabel} and replaced {dropLabel} in {groupLabel} group at position {position}', + 'Converted {label} to {nextLabel} and replaced {dropLabel} in {groupLabel} group at position {position} in layer {dropLayerNumber}', values: { label, nextLabel, dropLabel, groupLabel, position, + dropLayerNumber, }, }), - move_incompatible: ({ label }: HumanData, { groupLabel, position, nextLabel }: HumanData) => + move_incompatible: ( + { label }: HumanData, + { groupLabel, position, nextLabel, layerNumber: dropLayerNumber }: HumanData + ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.moveIncompatible', { defaultMessage: - 'Converted {label} to {nextLabel} and moved to {groupLabel} group at position {position}', + 'Converted {label} to {nextLabel} and moved to {groupLabel} group at position {position} in layer {dropLayerNumber}', values: { label, nextLabel, groupLabel, position, + dropLayerNumber, }, }), - move_compatible: ({ label }: HumanData, { groupLabel, position }: HumanData) => + move_compatible: ( + { label }: HumanData, + { groupLabel, position, layerNumber: dropLayerNumber }: HumanData + ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.moveCompatible', { - defaultMessage: 'Moved {label} to {groupLabel} group at position {position}', + defaultMessage: + 'Moved {label} to {groupLabel} group at position {position} in layer {dropLayerNumber}', values: { label, groupLabel, position, + dropLayerNumber, }, }), duplicate_incompatible: ( { label }: HumanData, - { groupLabel, position, nextLabel }: HumanData + { groupLabel, position, nextLabel, layerNumber: dropLayerNumber }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.duplicateIncompatible', { defaultMessage: - 'Converted copy of {label} to {nextLabel} and added to {groupLabel} group at position {position}', + 'Converted copy of {label} to {nextLabel} and added to {groupLabel} group at position {position} in layer {dropLayerNumber}', values: { label, groupLabel, position, nextLabel, + dropLayerNumber, }, }), replace_duplicate_incompatible: ( { label }: HumanData, - { label: dropLabel, groupLabel, position, nextLabel }: HumanData + { label: dropLabel, groupLabel, position, nextLabel, layerNumber: dropLayerNumber }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.replaceDuplicateIncompatible', { defaultMessage: - 'Converted copy of {label} to {nextLabel} and replaced {dropLabel} in {groupLabel} group at position {position}', + 'Converted copy of {label} to {nextLabel} and replaced {dropLabel} in {groupLabel} group at position {position} in layer {dropLayerNumber}', values: { label, dropLabel, groupLabel, position, nextLabel, + dropLayerNumber, }, }), replace_duplicate_compatible: ( { label }: HumanData, - { label: dropLabel, groupLabel, position }: HumanData + { label: dropLabel, groupLabel, position, layerNumber: dropLayerNumber }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.duplicated.replaceDuplicateCompatible', { defaultMessage: - 'Replaced {dropLabel} with a copy of {label} in {groupLabel} at position {position}', + 'Replaced {dropLabel} with a copy of {label} in {groupLabel} at position {position} in layer {dropLayerNumber}', values: { label, dropLabel, groupLabel, position, + dropLayerNumber, }, }), swap_compatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition }: HumanData + { label, groupLabel, position, layerNumber }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.swapCompatible', { defaultMessage: - 'Moved {label} to {dropGroupLabel} at position {dropPosition} and {dropLabel} to {groupLabel} group at position {position}', + 'Moved {label} to {dropGroupLabel} at position {dropPosition} in layer {dropLayerNumber} and {dropLabel} to {groupLabel} group at position {position} in layer {layerNumber}', values: { label, groupLabel, @@ -529,15 +620,23 @@ export const announcements: CustomAnnouncementsType = { dropLabel, dropGroupLabel, dropPosition, + layerNumber, + dropLayerNumber, }, }), swap_incompatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + { label, groupLabel, position, layerNumber }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + nextLabel, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.swapIncompatible', { defaultMessage: - 'Converted {label} to {nextLabel} in {groupLabel} group at position {position} and swapped with {dropLabel} in {dropGroupLabel} group at position {dropPosition}', + 'Converted {label} to {nextLabel} in {groupLabel} group at position {position} in layer {layerNumber} and swapped with {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}', values: { label, groupLabel, @@ -546,31 +645,44 @@ export const announcements: CustomAnnouncementsType = { dropLabel, dropPosition, nextLabel, + dropLayerNumber, + layerNumber, }, }), combine_compatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition }: HumanData + { label, groupLabel }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.combineCompatible', { defaultMessage: - 'Combined {label} to {dropGroupLabel} at position {dropPosition} and {dropLabel} to {groupLabel} group at position {position}', + 'Combined {label} in group {groupLabel} to {dropLabel} in group {dropGroupLabel} at position {dropPosition} in layer {dropLayerNumber}', values: { label, groupLabel, - position, dropLabel, dropGroupLabel, dropPosition, + dropLayerNumber, }, }), combine_incompatible: ( - { label, groupLabel, position }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position: dropPosition, nextLabel }: HumanData + { label, groupLabel, position, layerNumber }: HumanData, + { + label: dropLabel, + groupLabel: dropGroupLabel, + position: dropPosition, + nextLabel, + layerNumber: dropLayerNumber, + }: HumanData ) => i18n.translate('xpack.lens.dragDrop.announce.dropped.combineIncompatible', { defaultMessage: - 'Converted {label} to {nextLabel} in {groupLabel} group at position {position} and combined with {dropLabel} in {dropGroupLabel} group at position {dropPosition}', + 'Converted {label} to {nextLabel} in {groupLabel} group at position {position} and combined with {dropLabel} in {dropGroupLabel} group at position {dropPosition} in layer {dropLayerNumber}', values: { label, groupLabel, @@ -579,6 +691,7 @@ export const announcements: CustomAnnouncementsType = { dropLabel, dropPosition, nextLabel, + dropLayerNumber, }, }), }, @@ -620,15 +733,22 @@ const defaultAnnouncements = { dropped: ( { label }: HumanData, - { groupLabel: dropGroupLabel, position, label: dropLabel }: HumanData + { + groupLabel: dropGroupLabel, + position, + label: dropLabel, + layerNumber: dropLayerNumber, + }: HumanData ) => dropGroupLabel && position ? i18n.translate('xpack.lens.dragDrop.announce.droppedDefault', { - defaultMessage: 'Added {label} in {dropGroupLabel} group at position {position}', + defaultMessage: + 'Added {label} in {dropGroupLabel} group at position {position} in layer {dropLayerNumber}', values: { label, dropGroupLabel, position, + dropLayerNumber, }, }) : i18n.translate('xpack.lens.dragDrop.announce.droppedNoPosition', { @@ -640,15 +760,21 @@ const defaultAnnouncements = { }), selectedTarget: ( { label }: HumanData, - { label: dropLabel, groupLabel: dropGroupLabel, position }: HumanData + { + label: dropLabel, + groupLabel: dropGroupLabel, + position, + layerNumber: dropLayerNumber, + }: HumanData ) => { return dropGroupLabel && position ? i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.default', { - defaultMessage: `Add {label} to {dropGroupLabel} group at position {position}. Press space or enter to add`, + defaultMessage: `Add {label} to {dropGroupLabel} group at position {position} in layer {dropLayerNumber}. Press space or enter to add`, values: { label, dropGroupLabel, position, + dropLayerNumber, }, }) : i18n.translate('xpack.lens.dragDrop.announce.selectedTarget.defaultNoPosition', { @@ -671,8 +797,15 @@ export const announce = { dropElement: HumanData, type?: DropType, announceModifierKeys?: boolean - ) => - (type && - announcements.selectedTarget?.[type]?.(draggedElement, dropElement, announceModifierKeys)) || - defaultAnnouncements.selectedTarget(draggedElement, dropElement), + ) => { + return ( + (type && + announcements.selectedTarget?.[type]?.( + draggedElement, + dropElement, + announceModifierKeys + )) || + defaultAnnouncements.selectedTarget(draggedElement, dropElement) + ); + }, }; diff --git a/x-pack/plugins/lens/public/drag_drop/providers/types.tsx b/x-pack/plugins/lens/public/drag_drop/providers/types.tsx index 921ab897706c0..363f0b41ef3a1 100644 --- a/x-pack/plugins/lens/public/drag_drop/providers/types.tsx +++ b/x-pack/plugins/lens/public/drag_drop/providers/types.tsx @@ -10,6 +10,7 @@ import { DropType } from '../../types'; export interface HumanData { label: string; groupLabel?: string; + layerNumber?: number; position?: number; nextLabel?: string; canSwap?: boolean; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx index f0e0911b708fd..32aba270e846b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/draggable_dimension_button.tsx @@ -10,10 +10,10 @@ import { DragDrop, DragDropIdentifier, DragContext } from '../../../../drag_drop import { Datasource, VisualizationDimensionGroupConfig, - isDraggedOperation, + isOperation, DropType, + DatasourceLayers, } from '../../../../types'; -import { LayerDatasourceDropProps } from '../types'; import { getCustomDropTarget, getAdditionalClassesOnDroppable, @@ -29,45 +29,53 @@ export function DraggableDimensionButton({ layerIndex, columnId, group, - groups, onDrop, onDragStart, onDragEnd, children, - layerDatasourceDropProps, + state, layerDatasource, + datasourceLayers, registerNewButtonRef, }: { layerId: string; groupIndex: number; layerIndex: number; - onDrop: ( - droppedItem: DragDropIdentifier, - dropTarget: DragDropIdentifier, - dropType?: DropType - ) => void; + onDrop: (source: DragDropIdentifier, dropTarget: DragDropIdentifier, dropType?: DropType) => void; onDragStart: () => void; onDragEnd: () => void; group: VisualizationDimensionGroupConfig; - groups: VisualizationDimensionGroupConfig[]; label: string; children: ReactElement; layerDatasource: Datasource; - layerDatasourceDropProps: LayerDatasourceDropProps; + datasourceLayers: DatasourceLayers; + state: unknown; accessorIndex: number; columnId: string; registerNewButtonRef: (id: string, instance: HTMLDivElement | null) => void; }) { const { dragging } = useContext(DragContext); - const dropProps = getDropProps(layerDatasource, { - ...(layerDatasourceDropProps || {}), - dragging, - columnId, - filterOperations: group.filterOperations, - groupId: group.groupId, - dimensionGroups: groups, - }); + const sharedDatasource = + !isOperation(dragging) || + datasourceLayers?.[dragging.layerId]?.datasourceId === datasourceLayers?.[layerId]?.datasourceId + ? layerDatasource + : undefined; + + const dropProps = getDropProps( + { + state, + source: dragging, + target: { + layerId, + columnId, + groupId: group.groupId, + filterOperations: group.filterOperations, + prioritizedOperation: group.prioritizedOperation, + }, + }, + sharedDatasource + ); const dropTypes = dropProps?.dropTypes; const nextLabel = dropProps?.nextLabel; @@ -104,6 +112,7 @@ export function DraggableDimensionButton({ groupLabel: group.groupLabel, position: accessorIndex + 1, nextLabel: nextLabel || '', + layerNumber: layerIndex + 1, }, }), [ @@ -118,10 +127,10 @@ export function DraggableDimensionButton({ canDuplicate, canSwap, canCombine, + layerIndex, ] ); - // todo: simplify by id and use drop targets? const reorderableGroup = useMemo( () => group.accessors.map((g) => ({ @@ -136,7 +145,7 @@ export function DraggableDimensionButton({ ); const handleOnDrop = useCallback( - (droppedItem, selectedDropType) => onDrop(droppedItem, value, selectedDropType), + (source, selectedDropType) => onDrop(source, value, selectedDropType), [value, onDrop] ); return ( @@ -151,7 +160,7 @@ export function DraggableDimensionButton({ getAdditionalClassesOnDroppable={getAdditionalClassesOnDroppable} order={[2, layerIndex, groupIndex, accessorIndex]} draggable - dragType={isDraggedOperation(dragging) ? 'move' : 'copy'} + dragType={isOperation(dragging) ? 'move' : 'copy'} dropTypes={dropTypes} reorderableGroup={reorderableGroup.length > 1 ? reorderableGroup : undefined} value={value} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.test.tsx new file mode 100644 index 0000000000000..dd5ec847fb5b5 --- /dev/null +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.test.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getDropProps } from './drop_targets_utils'; +import { createMockDatasource } from '../../../../mocks'; + +describe('getDropProps', () => { + it('should run datasource getDropProps if exists', () => { + const mockDatasource = createMockDatasource('testDatasource'); + getDropProps( + { + state: 'datasourceState', + target: { + columnId: 'col1', + groupId: 'x', + layerId: 'first', + filterOperations: () => true, + }, + source: { + columnId: 'col1', + groupId: 'x', + layerId: 'first', + id: 'annotationColumn2', + humanData: { label: 'Event' }, + }, + }, + mockDatasource + ); + expect(mockDatasource.getDropProps).toHaveBeenCalled(); + }); + describe('no datasource', () => { + it('returns reorder for the same group existing columns', () => { + expect( + getDropProps({ + state: 'datasourceState', + target: { + columnId: 'annotationColumn', + groupId: 'xAnnotations', + layerId: 'second', + filterOperations: () => true, + }, + source: { + columnId: 'annotationColumn2', + groupId: 'xAnnotations', + layerId: 'second', + id: 'annotationColumn2', + humanData: { label: 'Event' }, + }, + }) + ).toEqual({ dropTypes: ['reorder'] }); + }); + it('returns duplicate for the same group existing column and not existing column', () => { + expect( + getDropProps({ + state: 'datasourceState', + target: { + columnId: 'annotationColumn', + groupId: 'xAnnotations', + layerId: 'second', + isNewColumn: true, + filterOperations: () => true, + }, + source: { + columnId: 'annotationColumn2', + groupId: 'xAnnotations', + layerId: 'second', + id: 'annotationColumn2', + humanData: { label: 'Event' }, + }, + }) + ).toEqual({ dropTypes: ['duplicate_compatible'] }); + }); + it('returns replace_duplicate and replace for replacing to different layer', () => { + expect( + getDropProps({ + state: 'datasourceState', + target: { + columnId: 'annotationColumn', + groupId: 'xAnnotations', + layerId: 'first', + filterOperations: () => true, + }, + source: { + columnId: 'annotationColumn2', + groupId: 'xAnnotations', + layerId: 'second', + id: 'annotationColumn2', + humanData: { label: 'Event' }, + }, + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'swap_compatible'], + }); + }); + it('returns duplicate and move for replacing to different layer for empty column', () => { + expect( + getDropProps({ + state: 'datasourceState', + target: { + columnId: 'annotationColumn', + groupId: 'xAnnotations', + layerId: 'first', + isNewColumn: true, + filterOperations: () => true, + }, + source: { + columnId: 'annotationColumn2', + groupId: 'xAnnotations', + layerId: 'second', + id: 'annotationColumn2', + humanData: { label: 'Event' }, + }, + }) + ).toEqual({ + dropTypes: ['move_compatible', 'duplicate_compatible'], + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.tsx index 056efbf379d8a..8ce2a4c0cc975 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils.tsx @@ -9,8 +9,17 @@ import React from 'react'; import classNames from 'classnames'; import { EuiIcon, EuiFlexItem, EuiFlexGroup, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { DraggingIdentifier } from '../../../../drag_drop'; -import { Datasource, DropType, GetDropProps } from '../../../../types'; +import { DragDropIdentifier, DraggingIdentifier } from '../../../../drag_drop'; +import { + Datasource, + DropType, + FramePublicAPI, + GetDropPropsArgs, + isOperation, + Visualization, + DragDropOperation, + VisualizationDimensionGroupConfig, +} from '../../../../types'; function getPropsForDropType(type: 'swap' | 'duplicate' | 'combine') { switch (type) { @@ -131,35 +140,97 @@ export const getAdditionalClassesOnDroppable = (dropType?: string) => { } }; -const isOperationFromTheSameGroup = ( - op1?: DraggingIdentifier, - op2?: { layerId: string; groupId: string; columnId: string } -) => { +const isOperationFromCompatibleGroup = (op1?: DraggingIdentifier, op2?: DragDropOperation) => { return ( - op1 && - op2 && - 'columnId' in op1 && + isOperation(op1) && + isOperation(op2) && + op1.columnId !== op2.columnId && + op1.groupId === op2.groupId && + op1.layerId !== op2.layerId + ); +}; + +export const isOperationFromTheSameGroup = (op1?: DraggingIdentifier, op2?: DragDropOperation) => { + return ( + isOperation(op1) && + isOperation(op2) && op1.columnId !== op2.columnId && - 'groupId' in op1 && op1.groupId === op2.groupId && - 'layerId' in op1 && op1.layerId === op2.layerId ); }; +export function getDropPropsForSameGroup( + isNewColumn?: boolean +): { dropTypes: DropType[]; nextLabel?: string } | undefined { + return !isNewColumn ? { dropTypes: ['reorder'] } : { dropTypes: ['duplicate_compatible'] }; +} + export const getDropProps = ( - layerDatasource: Datasource, - dropProps: GetDropProps, - isNew?: boolean + dropProps: GetDropPropsArgs, + sharedDatasource?: Datasource ): { dropTypes: DropType[]; nextLabel?: string } | undefined => { - if (layerDatasource) { - return layerDatasource.getDropProps(dropProps); + if (sharedDatasource) { + return sharedDatasource?.getDropProps(dropProps); } else { - // TODO: refactor & test this - it's too annotations specific - // TODO: allow moving operations between layers for annotations - if (isOperationFromTheSameGroup(dropProps.dragging, dropProps)) { - return { dropTypes: [isNew ? 'duplicate_compatible' : 'reorder'], nextLabel: '' }; + if (isOperationFromTheSameGroup(dropProps.source, dropProps.target)) { + return getDropPropsForSameGroup(dropProps.target.isNewColumn); + } + if (isOperationFromCompatibleGroup(dropProps.source, dropProps.target)) { + return { + dropTypes: dropProps.target.isNewColumn + ? ['move_compatible', 'duplicate_compatible'] + : ['replace_compatible', 'replace_duplicate_compatible', 'swap_compatible'], + }; } } return; }; + +export interface OnVisDropProps { + prevState: T; + target: DragDropOperation; + source: DragDropIdentifier; + frame: FramePublicAPI; + dropType: DropType; + group?: VisualizationDimensionGroupConfig; +} + +export function onDropForVisualization( + props: OnVisDropProps, + activeVisualization: Visualization +) { + const { prevState, target, frame, dropType, source, group } = props; + const { layerId, columnId, groupId } = target; + + const previousColumn = + isOperation(source) && group?.requiresPreviousColumnOnDuplicate ? source.columnId : undefined; + + const newVisState = activeVisualization.setDimension({ + columnId, + groupId, + layerId, + prevState, + previousColumn, + frame, + }); + + // remove source + if ( + isOperation(source) && + (dropType === 'move_compatible' || + dropType === 'move_incompatible' || + dropType === 'combine_incompatible' || + dropType === 'combine_compatible' || + dropType === 'replace_compatible' || + dropType === 'replace_incompatible') + ) { + return activeVisualization.removeDimension({ + columnId: source?.columnId, + layerId: source?.layerId, + prevState: newVisState, + frame, + }); + } + return newVisState; +} diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx index 867ce32ea700e..a35366611ae18 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/buttons/empty_dimension_button.tsx @@ -12,8 +12,13 @@ import { i18n } from '@kbn/i18n'; import { generateId } from '../../../../id_generator'; import { DragDrop, DragDropIdentifier, DragContext } from '../../../../drag_drop'; -import { Datasource, VisualizationDimensionGroupConfig, DropType } from '../../../../types'; -import { LayerDatasourceDropProps } from '../types'; +import { + Datasource, + VisualizationDimensionGroupConfig, + DropType, + DatasourceLayers, + isOperation, +} from '../../../../types'; import { getCustomDropTarget, getAdditionalClassesOnDroppable, @@ -98,31 +103,31 @@ const SuggestedValueButton = ({ columnId, group, onClick }: EmptyButtonProps) => export function EmptyDimensionButton({ group, - groups, layerDatasource, - layerDatasourceDropProps, + state, layerId, groupIndex, layerIndex, onClick, onDrop, + datasourceLayers, }: { layerId: string; groupIndex: number; layerIndex: number; - onDrop: ( - droppedItem: DragDropIdentifier, - dropTarget: DragDropIdentifier, - dropType?: DropType - ) => void; + onDrop: (source: DragDropIdentifier, dropTarget: DragDropIdentifier, dropType?: DropType) => void; onClick: (id: string) => void; group: VisualizationDimensionGroupConfig; - groups: VisualizationDimensionGroupConfig[]; - layerDatasource: Datasource; - layerDatasourceDropProps: LayerDatasourceDropProps; + datasourceLayers: DatasourceLayers; + state: unknown; }) { const { dragging } = useContext(DragContext); + const sharedDatasource = + !isOperation(dragging) || + datasourceLayers?.[dragging.layerId]?.datasourceId === datasourceLayers?.[layerId]?.datasourceId + ? layerDatasource + : undefined; const itemIndex = group.accessors.length; @@ -132,16 +137,19 @@ export function EmptyDimensionButton({ }, [itemIndex]); const dropProps = getDropProps( - layerDatasource, { - ...(layerDatasourceDropProps || {}), - dragging, - columnId: newColumnId, - filterOperations: group.filterOperations, - groupId: group.groupId, - dimensionGroups: groups, + state, + source: dragging, + target: { + layerId, + columnId: newColumnId, + groupId: group.groupId, + filterOperations: group.filterOperations, + prioritizedOperation: group.prioritizedOperation, + isNewColumn: true, + }, }, - true + sharedDatasource ); const dropTypes = dropProps?.dropTypes; @@ -157,6 +165,7 @@ export function EmptyDimensionButton({ columnId: newColumnId, groupId: group.groupId, layerId, + filterOperations: group.filterOperations, id: newColumnId, humanData: { label, @@ -164,13 +173,24 @@ export function EmptyDimensionButton({ position: itemIndex + 1, nextLabel: nextLabel || '', canDuplicate, + layerNumber: layerIndex + 1, }, }), - [newColumnId, group.groupId, layerId, group.groupLabel, itemIndex, nextLabel, canDuplicate] + [ + newColumnId, + group.groupId, + layerId, + group.groupLabel, + group.filterOperations, + itemIndex, + nextLabel, + canDuplicate, + layerIndex, + ] ); const handleOnDrop = React.useCallback( - (droppedItem, selectedDropType) => onDrop(droppedItem, value, selectedDropType), + (source, selectedDropType) => onDrop(source, value, selectedDropType), [value, onDrop] ); diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx index e5da3b0feef03..02c5f1c23967f 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.test.tsx @@ -631,7 +631,7 @@ describe('LayerPanel', () => { expect(mockDatasource.getDropProps).toHaveBeenCalledWith( expect.objectContaining({ - dragging: draggingField, + source: draggingField, }) ); @@ -644,7 +644,7 @@ describe('LayerPanel', () => { expect(mockDatasource.onDrop).toHaveBeenCalledWith( expect.objectContaining({ - droppedItem: draggingField, + source: draggingField, }) ); }); @@ -663,8 +663,8 @@ describe('LayerPanel', () => { ], }); - mockDatasource.getDropProps.mockImplementation(({ columnId }) => - columnId !== 'a' ? { dropTypes: ['field_replace'], nextLabel: '' } : undefined + mockDatasource.getDropProps.mockImplementation(({ target }) => + target.columnId !== 'a' ? { dropTypes: ['field_replace'], nextLabel: '' } : undefined ); const { instance } = await mountWithProvider( @@ -674,7 +674,9 @@ describe('LayerPanel', () => { ); expect(mockDatasource.getDropProps).toHaveBeenCalledWith( - expect.objectContaining({ columnId: 'a' }) + expect.objectContaining({ + target: expect.objectContaining({ columnId: 'a', groupId: 'a', layerId: 'first' }), + }) ); expect( @@ -741,7 +743,7 @@ describe('LayerPanel', () => { expect(mockDatasource.getDropProps).toHaveBeenCalledWith( expect.objectContaining({ - dragging: draggingOperation, + source: draggingOperation, }) ); @@ -755,8 +757,8 @@ describe('LayerPanel', () => { expect(mockDatasource.onDrop).toHaveBeenCalledWith( expect.objectContaining({ - columnId: 'b', - droppedItem: draggingOperation, + target: expect.objectContaining({ columnId: 'b' }), + source: draggingOperation, }) ); @@ -771,8 +773,8 @@ describe('LayerPanel', () => { expect(mockDatasource.onDrop).toHaveBeenCalledWith( expect.objectContaining({ - columnId: 'newid', - droppedItem: draggingOperation, + target: expect.objectContaining({ columnId: 'newid' }), + source: draggingOperation, }) ); }); @@ -816,7 +818,7 @@ describe('LayerPanel', () => { expect(mockDatasource.onDrop).toHaveBeenCalledWith( expect.objectContaining({ dropType: 'reorder', - droppedItem: draggingOperation, + source: draggingOperation, }) ); const secondButton = instance @@ -865,9 +867,9 @@ describe('LayerPanel', () => { }); expect(mockDatasource.onDrop).toHaveBeenCalledWith( expect.objectContaining({ - columnId: 'newid', + target: expect.objectContaining({ columnId: 'newid' }), dropType: 'duplicate_compatible', - droppedItem: draggingOperation, + source: draggingOperation, }) ); }); @@ -907,7 +909,7 @@ describe('LayerPanel', () => { humanData: { label: 'Label' }, }; - mockDatasource.onDrop.mockReturnValue({ deleted: 'a' }); + mockDatasource.onDrop.mockReturnValue(true); const updateVisualization = jest.fn(); const { instance } = await mountWithProvider( @@ -925,9 +927,10 @@ describe('LayerPanel', () => { expect(mockDatasource.onDrop).toHaveBeenCalledWith( expect.objectContaining({ dropType: 'replace_compatible', - droppedItem: draggingOperation, + source: draggingOperation, }) ); + // testing default onDropForVisualization path expect(mockVis.setDimension).toHaveBeenCalledWith( expect.objectContaining({ columnId: 'c', @@ -945,6 +948,85 @@ describe('LayerPanel', () => { ); expect(updateVisualization).toHaveBeenCalledTimes(1); }); + it('should call onDrop and update visualization when replacing between compatible groups2', async () => { + const mockVis = { + ...mockVisualization, + removeDimension: jest.fn(), + setDimension: jest.fn(() => 'modifiedState'), + onDrop: jest.fn(() => 'modifiedState'), + }; + jest.spyOn(mockVis.onDrop, 'bind').mockImplementation((thisVal, ...args) => mockVis.onDrop); + + mockVis.getConfiguration.mockReturnValue({ + groups: [ + { + groupLabel: 'A', + groupId: 'a', + accessors: [{ columnId: 'a' }, { columnId: 'b' }], + filterOperations: () => true, + supportsMoreColumns: true, + dataTestSubj: 'lnsGroup', + }, + { + groupLabel: 'B', + groupId: 'b', + accessors: [{ columnId: 'c' }], + filterOperations: () => true, + supportsMoreColumns: true, + dataTestSubj: 'lnsGroup2', + }, + ], + }); + + const draggingOperation = { + layerId: 'first', + columnId: 'a', + groupId: 'a', + id: 'a', + humanData: { label: 'Label' }, + }; + + mockDatasource.onDrop.mockReturnValue(true); + const updateVisualization = jest.fn(); + + const { instance } = await mountWithProvider( + + + + ); + act(() => { + instance.find(DragDrop).at(3).prop('onDrop')!(draggingOperation, 'replace_compatible'); + }); + + expect(mockDatasource.onDrop).toHaveBeenCalledWith( + expect.objectContaining({ + dropType: 'replace_compatible', + source: draggingOperation, + }) + ); + + expect(mockVis.onDrop).toHaveBeenCalledWith( + expect.objectContaining({ + dropType: 'replace_compatible', + prevState: 'state', + source: draggingOperation, + target: expect.objectContaining({ + columnId: 'c', + groupId: 'b', + id: 'c', + layerId: 'first', + }), + }), + mockVis + ); + expect(mockVis.setDimension).not.toHaveBeenCalled(); + expect(mockVis.removeDimension).not.toHaveBeenCalled(); + expect(updateVisualization).toHaveBeenCalledTimes(1); + }); }); describe('add a new dimension', () => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index c577bf89d6bd1..0c54ca0df5c71 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -19,7 +19,13 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { NativeRenderer } from '../../../native_renderer'; -import { StateSetter, Visualization, DraggedOperation, DropType } from '../../../types'; +import { + StateSetter, + Visualization, + DragDropOperation, + DropType, + isOperation, +} from '../../../types'; import { DragDropIdentifier, ReorderProvider } from '../../../drag_drop'; import { LayerSettings } from './layer_settings'; import { trackUiEvent } from '../../../lens_ui_telemetry'; @@ -36,6 +42,7 @@ import { selectResolvedDateRange, selectDatasourceStates, } from '../../../state_management'; +import { onDropForVisualization } from './buttons/drop_targets_utils'; const initialActiveDimensionState = { isNew: false, @@ -109,19 +116,12 @@ export function LayerPanel( const layerDatasourceState = datasourceStates?.[datasourceId]?.state; const layerDatasource = props.datasourceMap[datasourceId]; - const layerDatasourceDropProps = useMemo( - () => ({ - layerId, - state: layerDatasourceState, - setState: (newState: unknown) => { - updateDatasource(datasourceId, newState); - }, - }), - [layerId, layerDatasourceState, datasourceId, updateDatasource] - ); - const layerDatasourceConfigProps = { - ...layerDatasourceDropProps, + state: layerDatasourceState, + setState: (newState: unknown) => { + updateDatasource(datasourceId, newState); + }, + layerId, frame: props.framePublicAPI, dateRange, }; @@ -155,105 +155,70 @@ export function LayerPanel( registerNewRef: registerNewButtonRef, } = useFocusUpdate(allAccessors); - const layerDatasourceOnDrop = layerDatasource?.onDrop; - const onDrop = useMemo(() => { - return ( - droppedItem: DragDropIdentifier, - targetItem: DragDropIdentifier, - dropType?: DropType - ) => { + return (source: DragDropIdentifier, target: DragDropIdentifier, dropType?: DropType) => { if (!dropType) { return; } - const { - columnId, - groupId, - layerId: targetLayerId, - } = targetItem as unknown as DraggedOperation; + if (!isOperation(target)) { + throw new Error('Drop target should be an operation'); + } + if (dropType === 'reorder' || dropType === 'field_replace' || dropType === 'field_add') { - setNextFocusedButtonId(droppedItem.id); + setNextFocusedButtonId(source.id); } else { - setNextFocusedButtonId(columnId); + setNextFocusedButtonId(target.columnId); } + let hasDropSucceeded = true; if (layerDatasource) { - const group = groups.find(({ groupId: gId }) => gId === groupId); - const filterOperations = group?.filterOperations || (() => false); - const dropResult = layerDatasourceOnDrop({ - ...layerDatasourceDropProps, - droppedItem, - columnId, - layerId: targetLayerId, - filterOperations, - dimensionGroups: groups, - groupId, - dropType, - }); - if (dropResult) { - let previousColumn = - typeof droppedItem.column === 'string' ? droppedItem.column : undefined; - - // make it inherit only for moving and duplicate - if (!previousColumn) { - // when duplicating check if the previous column is required - if ( - dropType === 'duplicate_compatible' && - typeof droppedItem.columnId === 'string' && - group?.requiresPreviousColumnOnDuplicate - ) { - previousColumn = droppedItem.columnId; - } else { - previousColumn = typeof dropResult === 'object' ? dropResult.deleted : undefined; - } - } - const newVisState = activeVisualization.setDimension({ - columnId, - groupId, - layerId: targetLayerId, - prevState: props.visualizationState, - previousColumn, - frame: framePublicAPI, - }); + hasDropSucceeded = Boolean( + layerDatasource?.onDrop({ + state: layerDatasourceState, + setState: (newState: unknown) => { + updateDatasource(datasourceId, newState); + }, + source, + target: { + ...(target as unknown as DragDropOperation), + filterOperations: + groups.find(({ groupId: gId }) => gId === target.groupId)?.filterOperations || + Boolean, + }, + dimensionGroups: groups, + dropType, + }) + ); + } + if (hasDropSucceeded) { + activeVisualization.onDrop = activeVisualization.onDrop?.bind(activeVisualization); - if (typeof dropResult === 'object') { - // When a column is moved, we delete the reference to the old - updateVisualization( - activeVisualization.removeDimension({ - columnId: dropResult.deleted, - layerId: targetLayerId, - prevState: newVisState, - frame: framePublicAPI, - }) - ); - } else { - updateVisualization(newVisState); - } - } - } else { - if (dropType === 'duplicate_compatible' || dropType === 'reorder') { - const newVisState = activeVisualization.setDimension({ - columnId, - groupId, - layerId: targetLayerId, - prevState: props.visualizationState, - previousColumn: droppedItem.id, - frame: framePublicAPI, - }); - updateVisualization(newVisState); - } + updateVisualization( + (activeVisualization.onDrop || onDropForVisualization)?.( + { + prevState: props.visualizationState, + frame: framePublicAPI, + target, + source, + dropType, + group: groups.find(({ groupId: gId }) => gId === target.groupId), + }, + activeVisualization + ) + ); } }; }, [ layerDatasource, + layerDatasourceState, setNextFocusedButtonId, groups, - layerDatasourceOnDrop, - layerDatasourceDropProps, activeVisualization, props.visualizationState, framePublicAPI, updateVisualization, + datasourceId, + updateDatasource, ]); const isDimensionPanelOpen = Boolean(activeId); @@ -462,15 +427,15 @@ export function LayerPanel( return ( setHideTooltip(true)} @@ -562,12 +527,12 @@ export function LayerPanel( {group.supportsMoreColumns ? ( { props.onEmptyDimensionAdd(id, group); setActiveDimension({ diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts index 66a30b0a405e8..172e0702f56e8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/types.ts @@ -29,7 +29,6 @@ export interface LayerPanelProps { } export interface LayerDatasourceDropProps { - layerId: string; state: unknown; setState: (newState: unknown) => void; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts deleted file mode 100644 index 66714f494bf53..0000000000000 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/droppable.test.ts +++ /dev/null @@ -1,2332 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; -import { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { IndexPatternDimensionEditorProps } from '../dimension_panel'; -import { onDrop } from './on_drop_handler'; -import { getDropProps } from './get_drop_props'; -import { - IUiSettingsClient, - SavedObjectsClientContract, - HttpSetup, - CoreSetup, -} from '@kbn/core/public'; -import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; -import { IndexPatternLayer, IndexPatternPrivateState } from '../../types'; -import { documentField } from '../../document_field'; -import { OperationMetadata, DropType } from '../../../types'; -import { - DateHistogramIndexPatternColumn, - GenericIndexPatternColumn, - MedianIndexPatternColumn, - TermsIndexPatternColumn, -} from '../../operations'; -import { getFieldByNameFactory } from '../../pure_helpers'; -import { generateId } from '../../../id_generator'; -import { layerTypes } from '../../../../common'; - -jest.mock('../../../id_generator'); - -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, - }, - { - name: 'src', - displayName: 'src', - type: 'string', - aggregatable: true, - searchable: true, - exists: true, - }, - { - name: 'dest', - displayName: 'dest', - type: 'string', - aggregatable: true, - searchable: true, - exists: true, - }, - documentField, -]; - -const expectedIndexPatterns = { - foo: { - id: 'foo', - title: 'my-fake-index-pattern', - timeFieldName: 'timestamp', - hasExistence: true, - hasRestrictions: false, - fields, - getFieldByName: getFieldByNameFactory(fields), - }, -}; - -const dimensionGroups = [ - { - accessors: [], - groupId: 'a', - supportsMoreColumns: true, - hideGrouping: true, - groupLabel: '', - filterOperations: (op: OperationMetadata) => op.isBucketed, - }, - { - accessors: [{ columnId: 'col1' }, { columnId: 'col2' }, { columnId: 'col3' }], - groupId: 'b', - supportsMoreColumns: true, - hideGrouping: true, - groupLabel: '', - filterOperations: (op: OperationMetadata) => op.isBucketed, - }, - { - accessors: [{ columnId: 'col4' }], - groupId: 'c', - supportsMoreColumns: true, - hideGrouping: true, - groupLabel: '', - filterOperations: (op: OperationMetadata) => op.isBucketed === false, - }, -]; - -const oneColumnLayer: IndexPatternLayer = { - indexPatternId: 'foo', - columnOrder: ['col1'], - columns: { - col1: { - label: 'Date histogram of timestamp', - customLabel: true, - dataType: 'date', - isBucketed: true, - - // Private - operationType: 'date_histogram', - params: { - interval: '1d', - }, - sourceField: 'timestamp', - } as DateHistogramIndexPatternColumn, - }, - incompleteColumns: {}, -}; - -const multipleColumnsLayer: IndexPatternLayer = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3', 'col4'], - columns: { - col1: oneColumnLayer.columns.col1, - col2: { - label: 'Top 10 values of src', - dataType: 'string', - isBucketed: true, - // Private - operationType: 'terms', - params: { - orderBy: { type: 'alphabetical' }, - orderDirection: 'desc', - size: 10, - }, - sourceField: 'src', - } as TermsIndexPatternColumn, - col3: { - label: 'Top 10 values of dest', - dataType: 'string', - isBucketed: true, - - // Private - operationType: 'terms', - params: { - orderBy: { type: 'alphabetical' }, - orderDirection: 'desc', - size: 10, - }, - sourceField: 'dest', - } as TermsIndexPatternColumn, - col4: { - label: 'Median of bytes', - dataType: 'number', - isBucketed: false, - - // Private - operationType: 'median', - sourceField: 'bytes', - }, - }, -}; - -const draggingField = { - field: { type: 'number', name: 'bytes', aggregatable: true }, - indexPatternId: 'foo', - id: 'bar', - humanData: { label: 'Label' }, -}; - -const draggingCol1 = { - columnId: 'col1', - groupId: 'a', - layerId: 'first', - id: 'col1', - humanData: { label: 'Column 1' }, -}; - -const draggingCol2 = { - columnId: 'col2', - groupId: 'b', - layerId: 'first', - id: 'col2', - humanData: { label: 'Column 2' }, - filterOperations: (op: OperationMetadata) => op.isBucketed, -}; - -const draggingCol3 = { - columnId: 'col3', - groupId: 'b', - layerId: 'first', - id: 'col3', - humanData: { - label: '', - }, -}; - -const draggingCol4 = { - columnId: 'col4', - groupId: 'c', - layerId: 'first', - id: 'col4', - humanData: { - label: '', - }, - filterOperations: (op: OperationMetadata) => op.isBucketed === false, -}; - -/** - * The datasource exposes four main pieces of code which are tested at - * an integration test level. The main reason for this fairly high level - * of testing is that there is a lot of UI logic that isn't easily - * unit tested, such as the transient invalid state. - * - * - Dimension trigger: Not tested here - * - Dimension editor component: First half of the tests - * - * - getDropProps: Returns drop types that are possible for the current dragging field or other dimension - * - onDrop: Correct application of drop logic - */ -describe('IndexPatternDimensionEditorPanel', () => { - let state: IndexPatternPrivateState; - let setState: jest.Mock; - let defaultProps: IndexPatternDimensionEditorProps; - - function getStateWithMultiFieldColumn() { - return { - ...state, - layers: { - ...state.layers, - first: { - ...state.layers.first, - columns: { - ...state.layers.first.columns, - col1: { - label: 'Top values of dest', - dataType: 'string', - isBucketed: true, - - // Private - operationType: 'terms', - params: { - orderBy: { type: 'alphabetical' }, - orderDirection: 'desc', - size: 10, - }, - sourceField: 'dest', - } as TermsIndexPatternColumn, - }, - }, - }, - }; - } - - beforeEach(() => { - state = { - indexPatternRefs: [], - indexPatterns: expectedIndexPatterns, - currentIndexPatternId: 'foo', - isFirstExistenceFetch: false, - existingFields: { - 'my-fake-index-pattern': { - timestamp: true, - bytes: true, - memory: true, - source: true, - }, - }, - layers: { first: { ...oneColumnLayer } }, - }; - - setState = jest.fn(); - - defaultProps = { - state, - setState, - dateRange: { fromDate: 'now-1d', toDate: 'now' }, - columnId: 'col1', - layerId: 'first', - uniqueLabel: 'stuff', - groupId: 'group1', - filterOperations: () => true, - storage: {} as IStorageWrapper, - uiSettings: {} as IUiSettingsClient, - savedObjectsClient: {} as SavedObjectsClientContract, - http: {} as HttpSetup, - data: { - fieldFormats: { - getType: jest.fn().mockReturnValue({ - id: 'number', - title: 'Number', - }), - getDefaultType: jest.fn().mockReturnValue({ - id: 'bytes', - title: 'Bytes', - }), - } as unknown as DataPublicPluginStart['fieldFormats'], - } as unknown as DataPublicPluginStart, - unifiedSearch: {} as UnifiedSearchPublicPluginStart, - dataViews: {} as DataViewsPublicPluginStart, - core: {} as CoreSetup, - dimensionGroups: [], - isFullscreen: false, - toggleFullscreen: () => {}, - supportStaticValue: false, - layerType: layerTypes.DATA, - }; - - jest.clearAllMocks(); - }); - - const groupId = 'a'; - - describe('getDropProps', () => { - it('returns undefined if no drag is happening', () => { - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { name: 'bar', id: 'bar', humanData: { label: 'Label' } }, - }) - ).toBe(undefined); - }); - - it('returns undefined if the dragged item has no field', () => { - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { - name: 'bar', - id: 'bar', - humanData: { label: 'Label' }, - }, - }) - ).toBe(undefined); - }); - - describe('dragging a field', () => { - it('returns undefined if field is not supported by filterOperations', () => { - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: draggingField, - filterOperations: () => false, - }) - ).toBe(undefined); - }); - - it('returns field_replace if the field is supported by filterOperations and the dropTarget is an existing column', () => { - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: draggingField, - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - }) - ).toEqual({ dropTypes: ['field_replace'], nextLabel: 'Intervals' }); - }); - - it('returns field_add if the field is supported by filterOperations and the dropTarget is an empty column', () => { - expect( - getDropProps({ - ...defaultProps, - columnId: 'newId', - groupId, - dragging: draggingField, - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - }) - ).toEqual({ dropTypes: ['field_add'], nextLabel: 'Intervals' }); - }); - - it('returns undefined if the field belongs to another index pattern', () => { - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { - field: { type: 'number', name: 'bar', aggregatable: true }, - indexPatternId: 'foo2', - id: 'bar', - humanData: { label: 'Label' }, - }, - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - }) - ).toBe(undefined); - }); - - it('returns undefined if the dragged field is already in use by this operation', () => { - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { - field: { - name: 'timestamp', - displayName: 'timestampLabel', - type: 'date', - aggregatable: true, - searchable: true, - exists: true, - }, - indexPatternId: 'foo', - id: 'bar', - humanData: { label: 'Label' }, - }, - }) - ).toBe(undefined); - }); - - it('returns also field_combine if the field is supported by filterOperations and the dropTarget is an existing column that supports multiple fields', () => { - // replace the state with a top values column to enable the multi fields behaviour - state = getStateWithMultiFieldColumn(); - expect( - getDropProps({ - ...defaultProps, - state, - groupId, - dragging: draggingField, - filterOperations: (op: OperationMetadata) => op.dataType !== 'date', - }) - ).toEqual({ dropTypes: ['field_replace', 'field_combine'] }); - }); - }); - - describe('dragging a column', () => { - it('returns undefined if the dragged column from different group uses the same field as the dropTarget', () => { - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - label: 'Date histogram of timestamp (1)', - customLabel: true, - dataType: 'date', - isBucketed: true, - - // Private - operationType: 'date_histogram', - params: { - interval: '1d', - }, - sourceField: 'timestamp', - } as DateHistogramIndexPatternColumn, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual(undefined); - }); - - it('returns undefined if the dragged column from different group uses the same fields as the dropTarget', () => { - state = getStateWithMultiFieldColumn(); - const sourceMultiFieldColumn = { - ...state.layers.first.columns.col1, - sourceField: 'bytes', - params: { - ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, - secondaryFields: ['dest'], - }, - } as TermsIndexPatternColumn; - // invert the fields - const targetMultiFieldColumn = { - ...state.layers.first.columns.col1, - sourceField: 'dest', - params: { - ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, - secondaryFields: ['bytes'], - }, - } as TermsIndexPatternColumn; - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2'], - columns: { - col1: sourceMultiFieldColumn, - col2: targetMultiFieldColumn, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - state, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual(undefined); - }); - - it('returns duplicate and replace if the dragged column from different group uses the same field as the dropTarget, but this last one is multifield, and can be swappable', () => { - state = getStateWithMultiFieldColumn(); - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - ...state.layers.first.columns.col1, - sourceField: 'bytes', - params: { - ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, - secondaryFields: ['dest'], - }, - } as TermsIndexPatternColumn, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - state, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual({ - dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], - }); - }); - - it('returns swap, duplicate and replace if the dragged column from different group uses the same field as the dropTarget, but this last one is multifield', () => { - state = getStateWithMultiFieldColumn(); - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - ...state.layers.first.columns.col1, - sourceField: 'bytes', - params: { - ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, - secondaryFields: ['dest'], - }, - } as TermsIndexPatternColumn, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - state, - // make it swappable - dimensionGroups: [ - { - accessors: [{ columnId: 'col1' }], - filterOperations: jest.fn(() => true), - groupId, - groupLabel: '', - supportsMoreColumns: false, - }, - ], - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual({ - dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'swap_compatible'], - }); - }); - - it('returns reorder if drop target and droppedItem columns are from the same group and both are existing', () => { - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - label: 'Sum of bytes', - dataType: 'number', - isBucketed: false, - - // Private - operationType: 'sum', - sourceField: 'bytes', - }, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { ...draggingCol1, groupId }, - columnId: 'col2', - filterOperations: (op: OperationMetadata) => op.isBucketed === false, - }) - ).toEqual({ - dropTypes: ['reorder'], - }); - }); - - it('returns duplicate_compatible if drop target and droppedItem columns are from the same group and drop target id is a new column', () => { - expect( - getDropProps({ - ...defaultProps, - columnId: 'newId', - groupId, - dragging: { - ...draggingCol1, - groupId, - }, - }) - ).toEqual({ dropTypes: ['duplicate_compatible'] }); - }); - - it('returns compatible drop types if the dragged column is compatible', () => { - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual({ dropTypes: ['move_compatible', 'duplicate_compatible'] }); - }); - - it('returns incompatible drop target types if dropping column to existing incompatible column', () => { - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - label: 'Sum of bytes', - dataType: 'number', - isBucketed: false, - - // Private - operationType: 'sum', - sourceField: 'bytes', - }, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - filterOperations: (op: OperationMetadata) => op.isBucketed === false, - }) - ).toEqual({ - dropTypes: [ - 'replace_incompatible', - 'replace_duplicate_incompatible', - 'swap_incompatible', - ], - nextLabel: 'Minimum', - }); - }); - - it('does not return swap_incompatible if current dropTarget column cannot be swapped to the group of dragging column', () => { - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - label: 'Count of records', - dataType: 'number', - isBucketed: false, - sourceField: '___records___', - operationType: 'count', - }, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - groupId, - dragging: { - columnId: 'col1', - groupId: 'b', - layerId: 'first', - id: 'col1', - humanData: { label: 'Label' }, - filterOperations: (op: OperationMetadata) => op.isBucketed === true, - }, - columnId: 'col2', - filterOperations: (op: OperationMetadata) => op.isBucketed === false, - }) - ).toEqual({ - dropTypes: ['replace_incompatible', 'replace_duplicate_incompatible'], - nextLabel: 'Minimum', - }); - }); - - it('returns combine_compatible drop type if the dragged column is compatible and the target one support multiple fields', () => { - state = getStateWithMultiFieldColumn(); - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - ...state.layers.first.columns.col1, - sourceField: 'bytes', - }, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - state, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual({ - dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'combine_compatible'], - }); - }); - - it('returns no combine_compatible drop type if the target column uses rarity ordering', () => { - state = getStateWithMultiFieldColumn(); - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - ...state.layers.first.columns.col1, - sourceField: 'bytes', - params: { - ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, - orderBy: { type: 'rare' }, - }, - } as TermsIndexPatternColumn, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - state, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual({ - dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], - }); - }); - - it('returns no combine drop type if the dragged column is compatible, the target one supports multiple fields but there are too many fields', () => { - state = getStateWithMultiFieldColumn(); - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - ...state.layers.first.columns.col1, - sourceField: 'source', - params: { - ...(state.layers.first.columns.col1 as TermsIndexPatternColumn).params, - secondaryFields: ['memory', 'bytes', 'geo.src'], // too many fields here - }, - } as TermsIndexPatternColumn, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - state, - groupId, - dragging: { - ...draggingCol1, - groupId: 'c', - }, - columnId: 'col2', - }) - ).toEqual({ - dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], - }); - }); - - it('returns combine_incompatible drop target types if dropping column to existing incompatible column which supports multiple fields', () => { - state = getStateWithMultiFieldColumn(); - state.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: state.layers.first.columns.col1, - - col2: { - label: 'Sum of bytes', - dataType: 'number', - isBucketed: false, - - // Private - operationType: 'sum', - sourceField: 'bytes', - }, - }, - }; - - expect( - getDropProps({ - ...defaultProps, - state, - groupId, - // drag the sum over the top values - dragging: { - ...draggingCol2, - groupId: 'c', - filterOperation: undefined, - }, - columnId: 'col1', - filterOperations: (op: OperationMetadata) => op.isBucketed, - }) - ).toEqual({ - dropTypes: [ - 'replace_incompatible', - 'replace_duplicate_incompatible', - 'swap_incompatible', - 'combine_incompatible', - ], - nextLabel: 'Top values', - }); - }); - }); - }); - - describe('onDrop', () => { - describe('dropping a field', () => { - it('updates a column when a field is dropped', () => { - onDrop({ - ...defaultProps, - droppedItem: draggingField, - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - dropType: 'field_replace', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: expect.objectContaining({ - columns: expect.objectContaining({ - col1: expect.objectContaining({ - dataType: 'number', - sourceField: 'bytes', - }), - }), - }), - }, - }); - }); - it('selects the specific operation that was valid on drop', () => { - onDrop({ - ...defaultProps, - droppedItem: draggingField, - columnId: 'col2', - filterOperations: (op: OperationMetadata) => op.isBucketed, - dropType: 'field_replace', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: { - ...state.layers.first, - columnOrder: ['col1', 'col2'], - columns: { - ...state.layers.first.columns, - col2: expect.objectContaining({ - dataType: 'number', - sourceField: 'bytes', - }), - }, - }, - }, - }); - }); - it('keeps the operation when dropping a different compatible field', () => { - onDrop({ - ...defaultProps, - droppedItem: { - field: { name: 'memory', type: 'number', aggregatable: true }, - indexPatternId: 'foo', - id: '1', - }, - state: { - ...state, - layers: { - first: { - indexPatternId: 'foo', - columnOrder: ['col1'], - columns: { - col1: { - label: 'Sum of bytes', - dataType: 'number', - isBucketed: false, - - // Private - operationType: 'sum', - sourceField: 'bytes', - }, - }, - }, - }, - }, - dropType: 'field_replace', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: expect.objectContaining({ - columns: expect.objectContaining({ - col1: expect.objectContaining({ - operationType: 'sum', - dataType: 'number', - sourceField: 'memory', - }), - }), - }), - }, - }); - }); - it('appends the dropped column when a field is dropped', () => { - onDrop({ - ...defaultProps, - droppedItem: draggingField, - dropType: 'field_replace', - columnId: 'col2', - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: { - ...state.layers.first, - columnOrder: ['col1', 'col2'], - columns: { - ...state.layers.first.columns, - col2: expect.objectContaining({ - dataType: 'number', - sourceField: 'bytes', - }), - }, - }, - }, - }); - }); - it('dimensionGroups are defined - appends the dropped column in the right place when a field is dropped', () => { - const testState = { ...state }; - testState.layers.first = { ...multipleColumnsLayer }; - // config: - // a: - // b: col1, col2, col3 - // c: col4 - // dragging field into newCol in group a - - onDrop({ - ...defaultProps, - droppedItem: draggingField, - columnId: 'newCol', - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - groupId: 'a', - dimensionGroups, - dropType: 'field_add', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['newCol', 'col1', 'col2', 'col3', 'col4'], - columns: { - newCol: expect.objectContaining({ - dataType: 'number', - sourceField: 'bytes', - }), - col1: testState.layers.first.columns.col1, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - incompleteColumns: {}, - }, - }, - }); - }); - - it('appends the new field to the column that supports multiple fields when a field is dropped', () => { - state = getStateWithMultiFieldColumn(); - onDrop({ - ...defaultProps, - state, - droppedItem: draggingField, - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - dropType: 'field_combine', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: expect.objectContaining({ - columns: expect.objectContaining({ - col1: expect.objectContaining({ - dataType: 'string', - sourceField: 'dest', - params: expect.objectContaining({ secondaryFields: ['bytes'] }), - }), - }), - }), - }, - }); - }); - }); - - describe('dropping a dimension', () => { - const dragging = { - columnId: 'col1', - groupId: 'a', - layerId: 'first', - id: 'col1', - humanData: { label: 'Label' }, - }; - - it('sets correct order in group for metric and bucket columns when duplicating a column in group', () => { - const testState: IndexPatternPrivateState = { - ...state, - layers: { - first: { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: { - label: 'Date histogram of timestamp', - dataType: 'date', - isBucketed: true, - operationType: 'date_histogram', - params: { - interval: '1d', - }, - sourceField: 'timestamp', - } as DateHistogramIndexPatternColumn, - col2: { - label: 'Top values of bar', - dataType: 'number', - isBucketed: true, - operationType: 'terms', - sourceField: 'bar', - params: { - orderBy: { type: 'alphabetical' }, - orderDirection: 'asc', - size: 5, - }, - } as TermsIndexPatternColumn, - col3: { - operationType: 'average', - sourceField: 'memory', - label: 'average of memory', - dataType: 'number', - isBucketed: false, - }, - }, - }, - }, - }; - - const referenceDragging = { - columnId: 'col3', - groupId: 'a', - layerId: 'first', - id: 'col3', - humanData: { label: 'Label' }, - }; - - onDrop({ - ...defaultProps, - droppedItem: referenceDragging, - state: testState, - dropType: 'duplicate_compatible', - columnId: 'newCol', - }); - // metric is appended - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col3', 'newCol'], - columns: { - col1: testState.layers.first.columns.col1, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - newCol: testState.layers.first.columns.col3, - }, - }, - }, - }); - - const bucketDragging = { - columnId: 'col2', - groupId: 'a', - layerId: 'first', - id: 'col2', - humanData: { label: 'Label' }, - }; - - onDrop({ - ...defaultProps, - droppedItem: bucketDragging, - state: testState, - dropType: 'duplicate_compatible', - columnId: 'newCol', - }); - - // bucket is placed after the last existing bucket - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'newCol', 'col3'], - columns: { - col1: testState.layers.first.columns.col1, - col2: testState.layers.first.columns.col2, - newCol: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - }, - }, - }, - }); - }); - - it('when duplicating fullReference column, the referenced columns get duplicated too', () => { - (generateId as jest.Mock).mockReturnValue(`ref1Copy`); - const testState: IndexPatternPrivateState = { - ...state, - layers: { - first: { - indexPatternId: '1', - columnOrder: ['col1', 'ref1'], - columns: { - col1: { - label: 'Test reference', - dataType: 'number', - isBucketed: false, - operationType: 'cumulative_sum', - references: ['ref1'], - }, - ref1: { - label: 'Count of records', - dataType: 'number', - isBucketed: false, - sourceField: '___records___', - operationType: 'count', - }, - }, - }, - }, - }; - const referenceDragging = { - columnId: 'col1', - groupId: 'a', - layerId: 'first', - id: 'col1', - humanData: { label: 'Label' }, - }; - onDrop({ - ...defaultProps, - droppedItem: referenceDragging, - state: testState, - dropType: 'duplicate_compatible', - columnId: 'col1Copy', - }); - - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'ref1', 'ref1Copy', 'col1Copy'], - columns: { - ref1: testState.layers.first.columns.ref1, - col1: testState.layers.first.columns.col1, - ref1Copy: { ...testState.layers.first.columns.ref1 }, - col1Copy: { - ...testState.layers.first.columns.col1, - references: ['ref1Copy'], - }, - }, - }, - }, - }); - }); - - it('when duplicating fullReference column, the multiple referenced columns get duplicated too', () => { - (generateId as jest.Mock).mockReturnValueOnce(`ref1Copy`); - (generateId as jest.Mock).mockReturnValueOnce(`ref2Copy`); - const testState: IndexPatternPrivateState = { - ...state, - layers: { - first: { - indexPatternId: '1', - columnOrder: ['col1', 'ref1'], - columns: { - col1: { - label: 'Test reference', - dataType: 'number', - isBucketed: false, - operationType: 'cumulative_sum', - references: ['ref1', 'ref2'], - }, - ref1: { - label: 'Count of records', - dataType: 'number', - isBucketed: false, - sourceField: '___records___', - operationType: 'count', - }, - ref2: { - label: 'Unique count of bytes', - dataType: 'number', - isBucketed: false, - sourceField: 'bytes', - operationType: 'unique_count', - }, - }, - }, - }, - }; - const metricDragging = { - columnId: 'col1', - groupId: 'a', - layerId: 'first', - id: 'col1', - humanData: { label: 'Label' }, - }; - onDrop({ - ...defaultProps, - droppedItem: metricDragging, - state: testState, - dropType: 'duplicate_compatible', - columnId: 'col1Copy', - }); - - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'ref1', 'ref2', 'ref1Copy', 'col1Copy', 'ref2Copy'], - columns: { - ref1: testState.layers.first.columns.ref1, - ref2: testState.layers.first.columns.ref2, - col1: testState.layers.first.columns.col1, - ref2Copy: { ...testState.layers.first.columns.ref2 }, - ref1Copy: { ...testState.layers.first.columns.ref1 }, - col1Copy: { - ...testState.layers.first.columns.col1, - references: ['ref1Copy', 'ref2Copy'], - }, - }, - }, - }, - }); - }); - - it('when duplicating fullReference column, the referenced columns get duplicated recursively', () => { - (generateId as jest.Mock).mockReturnValueOnce(`ref1Copy`); - (generateId as jest.Mock).mockReturnValueOnce(`innerRef1Copy`); - (generateId as jest.Mock).mockReturnValueOnce(`ref2Copy`); - const testState: IndexPatternPrivateState = { - ...state, - layers: { - first: { - indexPatternId: '1', - columnOrder: ['innerRef1', 'ref2', 'ref1', 'col1'], - columns: { - col1: { - label: 'Test reference', - dataType: 'number', - isBucketed: false, - operationType: 'cumulative_sum', - references: ['ref1', 'ref2'], - }, - ref1: { - label: 'Reference that has a reference', - dataType: 'number', - isBucketed: false, - operationType: 'cumulative_sum', - references: ['innerRef1'], - }, - innerRef1: { - label: 'Count of records', - dataType: 'number', - isBucketed: false, - sourceField: '___records___', - operationType: 'count', - }, - ref2: { - label: 'Unique count of bytes', - dataType: 'number', - isBucketed: false, - sourceField: 'bytes', - operationType: 'unique_count', - }, - }, - }, - }, - }; - const refDragging = { - columnId: 'col1', - groupId: 'a', - layerId: 'first', - id: 'col1', - humanData: { label: 'Label' }, - }; - onDrop({ - ...defaultProps, - droppedItem: refDragging, - state: testState, - dropType: 'duplicate_compatible', - columnId: 'col1Copy', - }); - - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: [ - 'innerRef1', - 'ref2', - 'ref1', - 'col1', - 'innerRef1Copy', - 'ref1Copy', - 'col1Copy', - 'ref2Copy', - ], - columns: { - innerRef1: testState.layers.first.columns.innerRef1, - ref1: testState.layers.first.columns.ref1, - ref2: testState.layers.first.columns.ref2, - col1: testState.layers.first.columns.col1, - - innerRef1Copy: { ...testState.layers.first.columns.innerRef1 }, - ref2Copy: { ...testState.layers.first.columns.ref2 }, - ref1Copy: { - ...testState.layers.first.columns.ref1, - references: ['innerRef1Copy'], - }, - col1Copy: { - ...testState.layers.first.columns.col1, - references: ['ref1Copy', 'ref2Copy'], - }, - }, - }, - }, - }); - }); - - it('when duplicating fullReference column onto exisitng column, the state will not get modified', () => { - (generateId as jest.Mock).mockReturnValue(`ref1Copy`); - const testState: IndexPatternPrivateState = { - ...state, - layers: { - first: { - indexPatternId: '1', - columnOrder: ['col2', 'ref1', 'col1'], - columns: { - col1: { - label: 'Test reference', - dataType: 'number', - isBucketed: false, - operationType: 'cumulative_sum', - references: ['ref1'], - }, - ref1: { - label: 'Count of records', - dataType: 'number', - isBucketed: false, - sourceField: '___records___', - operationType: 'count', - }, - col2: { - label: 'Minimum', - dataType: 'number', - isBucketed: false, - - // Private - operationType: 'min', - sourceField: 'bytes', - customLabel: true, - }, - }, - }, - }, - }; - const referenceDragging = { - columnId: 'col1', - groupId: 'a', - layerId: 'first', - id: 'col1', - humanData: { label: 'Label' }, - }; - onDrop({ - ...defaultProps, - droppedItem: referenceDragging, - state: testState, - dropType: 'duplicate_compatible', - columnId: 'col2', - }); - - expect(setState).toHaveBeenCalledWith(testState); - }); - - it('sets correct order in group when reordering a column in group', () => { - const testState = { - ...state, - layers: { - first: { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: { - label: 'Date histogram of timestamp', - dataType: 'date', - isBucketed: true, - } as GenericIndexPatternColumn, - col2: { - label: 'Top values of bar', - dataType: 'number', - isBucketed: true, - } as GenericIndexPatternColumn, - col3: { - label: 'Top values of memory', - dataType: 'number', - isBucketed: true, - } as GenericIndexPatternColumn, - }, - }, - }, - }; - - const defaultReorderDropParams = { - ...defaultProps, - dragging, - droppedItem: draggingCol1, - state: testState, - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - dropType: 'reorder' as DropType, - }; - - const stateWithColumnOrder = (columnOrder: string[]) => { - return { - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder, - columns: { - ...testState.layers.first.columns, - }, - }, - }, - }; - }; - - // first element to last - onDrop({ - ...defaultReorderDropParams, - columnId: 'col3', - }); - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col2', 'col3', 'col1'])); - - // last element to first - onDrop({ - ...defaultReorderDropParams, - columnId: 'col1', - droppedItem: { - columnId: 'col3', - groupId: 'a', - layerId: 'first', - id: 'col3', - }, - }); - expect(setState).toBeCalledTimes(2); - expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col3', 'col1', 'col2'])); - - // middle column to first - onDrop({ - ...defaultReorderDropParams, - columnId: 'col1', - droppedItem: { - columnId: 'col2', - groupId: 'a', - layerId: 'first', - id: 'col2', - }, - }); - expect(setState).toBeCalledTimes(3); - expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col2', 'col1', 'col3'])); - - // middle column to last - onDrop({ - ...defaultReorderDropParams, - columnId: 'col3', - droppedItem: { - columnId: 'col2', - groupId: 'a', - layerId: 'first', - id: 'col2', - }, - }); - expect(setState).toBeCalledTimes(4); - expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col1', 'col3', 'col2'])); - }); - - it('updates the column id when moving an operation to an empty dimension', () => { - onDrop({ - ...defaultProps, - droppedItem: draggingCol1, - columnId: 'col2', - dropType: 'move_compatible', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: { - ...state.layers.first, - columnOrder: ['col2'], - columns: { - col2: state.layers.first.columns.col1, - }, - }, - }, - }); - }); - - it('replaces an operation when moving to a populated dimension', () => { - const testState = { ...state }; - testState.layers.first = { - indexPatternId: 'foo', - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: testState.layers.first.columns.col1, - - col2: { - label: 'Top 10 values of src', - dataType: 'string', - isBucketed: true, - - // Private - operationType: 'terms', - params: { - orderBy: { type: 'column', columnId: 'col3' }, - orderDirection: 'desc', - size: 10, - }, - sourceField: 'src', - } as TermsIndexPatternColumn, - col3: { - label: 'Count', - dataType: 'number', - isBucketed: false, - - // Private - operationType: 'count', - sourceField: '___records___', - customLabel: true, - }, - }, - }; - - onDrop({ - ...defaultProps, - droppedItem: draggingCol2, - state: testState, - dropType: 'replace_compatible', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col3'], - columns: { - col1: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - }, - }, - }, - }); - }); - - it('when combine compatible columns should append dropped column fields into the target one', () => { - state = getStateWithMultiFieldColumn(); - state.layers.first.columns = { - ...state.layers.first.columns, - col2: { - isBucketed: true, - label: 'Top values of source', - operationType: 'terms', - sourceField: 'bytes', - dataType: 'number', - params: { - orderBy: { - type: 'alphabetical', - }, - orderDirection: 'desc', - size: 10, - }, - } as TermsIndexPatternColumn, - }; - onDrop({ - ...defaultProps, - state, - droppedItem: { - columnId: 'col2', - groupId: 'a', - layerId: 'first', - id: 'col2', - humanData: { label: 'Label' }, - }, - filterOperations: (op: OperationMetadata) => op.isBucketed, - dropType: 'combine_compatible', - columnId: 'col1', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: expect.objectContaining({ - columns: expect.objectContaining({ - col1: expect.objectContaining({ - dataType: 'string', - sourceField: 'dest', - params: expect.objectContaining({ secondaryFields: ['bytes'] }), - }), - }), - }), - }, - }); - }); - - describe('dimension group aware ordering and copying', () => { - let testState: IndexPatternPrivateState; - beforeEach(() => { - testState = { ...state }; - testState.layers.first = { ...multipleColumnsLayer }; - }); - - it('respects groups on moving operations between compatible groups', () => { - // config: - // a: - // b: col1, col2, col3 - // c: col4 - // dragging col2 into newCol in group a - onDrop({ - ...defaultProps, - columnId: 'newCol', - droppedItem: draggingCol2, - state: testState, - groupId: 'a', - dimensionGroups, - dropType: 'move_compatible', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['newCol', 'col1', 'col3', 'col4'], - columns: { - newCol: testState.layers.first.columns.col2, - col1: testState.layers.first.columns.col1, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - }, - }, - }); - }); - - it('respects groups on duplicating operations between compatible groups', () => { - // config: - // a: - // b: col1, col2, col3 - // c: col4 - // dragging col2 into newCol in group a - onDrop({ - ...defaultProps, - columnId: 'newCol', - droppedItem: draggingCol2, - state: testState, - groupId: 'a', - dimensionGroups, - dropType: 'duplicate_compatible', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['newCol', 'col1', 'col2', 'col3', 'col4'], - columns: { - newCol: testState.layers.first.columns.col2, - col1: testState.layers.first.columns.col1, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - }, - }, - }); - }); - - it('respects groups on moving operations between compatible groups with overwrite', () => { - // config: - // a: col1, - // b: col2, col3 - // c: col4 - // dragging col3 onto col1 in group a - onDrop({ - ...defaultProps, - columnId: 'col1', - droppedItem: draggingCol3, - state: testState, - groupId: 'a', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - dropType: 'move_compatible', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col4'], - columns: { - col1: testState.layers.first.columns.col3, - col2: testState.layers.first.columns.col2, - col4: testState.layers.first.columns.col4, - }, - }, - }, - }); - }); - - it('respects groups on moving operations if some columns are not listed in groups', () => { - // config: - // a: col1, - // b: col2, col3 - // c: col4 - // col5, col6 not in visualization groups - // dragging col3 onto col1 in group a - onDrop({ - ...defaultProps, - columnId: 'col1', - droppedItem: draggingCol3, - state: { - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col3', 'col4', 'col5', 'col6'], - columns: { - ...testState.layers.first.columns, - col5: { - dataType: 'number', - operationType: 'count', - label: '', - isBucketed: false, - sourceField: '___records___', - customLabel: true, - }, - col6: { - dataType: 'number', - operationType: 'count', - label: '', - isBucketed: false, - sourceField: '___records___', - customLabel: true, - }, - }, - }, - }, - }, - groupId: 'a', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - dropType: 'move_compatible', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col4', 'col5', 'col6'], - columns: { - col1: testState.layers.first.columns.col3, - col2: testState.layers.first.columns.col2, - col4: testState.layers.first.columns.col4, - col5: expect.objectContaining({ - dataType: 'number', - operationType: 'count', - label: '', - isBucketed: false, - sourceField: '___records___', - }), - col6: expect.objectContaining({ - dataType: 'number', - operationType: 'count', - label: '', - isBucketed: false, - sourceField: '___records___', - }), - }, - }, - }, - }); - }); - - it('respects groups on duplicating operations between compatible groups with overwrite', () => { - // config: - // a: col1, - // b: col2, col3 - // c: col4 - // dragging col3 onto col1 in group a - - onDrop({ - ...defaultProps, - columnId: 'col1', - droppedItem: draggingCol3, - state: testState, - groupId: 'a', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - dropType: 'duplicate_compatible', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col3', 'col4'], - columns: { - col1: testState.layers.first.columns.col3, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - }, - }, - }); - }); - - it('moves newly created dimension to the bottom of the current group', () => { - // config: - // a: col1 - // b: col2, col3 - // c: col4 - // dragging col1 into newCol in group b - onDrop({ - ...defaultProps, - columnId: 'newCol', - dropType: 'move_compatible', - droppedItem: draggingCol1, - state: testState, - groupId: 'b', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col2', 'col3', 'newCol', 'col4'], - columns: { - newCol: testState.layers.first.columns.col1, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - }, - }, - }); - }); - - it('copies column to the bottom of the current group', () => { - // config: - // a: col1 - // b: col2, col3 - // c: col4 - // copying col1 within group a - onDrop({ - ...defaultProps, - columnId: 'newCol', - dropType: 'duplicate_compatible', - droppedItem: draggingCol1, - state: testState, - groupId: 'a', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'newCol', 'col2', 'col3', 'col4'], - columns: { - col1: testState.layers.first.columns.col1, - newCol: testState.layers.first.columns.col1, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - }, - }, - }); - }); - - it('appends the dropped column in the right place respecting custom nestingOrder', () => { - // config: - // a: - // b: col1, col2, col3 - // c: col4 - // dragging field into newCol in group a - - onDrop({ - ...defaultProps, - droppedItem: draggingField, - columnId: 'newCol', - filterOperations: (op: OperationMetadata) => op.dataType === 'number', - groupId: 'a', - dimensionGroups: [ - // a and b are ordered in reverse visually, but nesting order keeps them in place for column order - { ...dimensionGroups[1], nestingOrder: 1 }, - { ...dimensionGroups[0], nestingOrder: 0 }, - { ...dimensionGroups[2] }, - ], - dropType: 'field_add', - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...state, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['newCol', 'col1', 'col2', 'col3', 'col4'], - columns: { - newCol: expect.objectContaining({ - dataType: 'number', - sourceField: 'bytes', - }), - col1: testState.layers.first.columns.col1, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - incompleteColumns: {}, - }, - }, - }); - }); - - it('moves incompatible column to the bottom of the target group', () => { - // config: - // a: col1 - // b: col2, col3 - // c: col4 - // dragging col4 into newCol in group a - - onDrop({ - ...defaultProps, - columnId: 'newCol', - dropType: 'move_incompatible', - droppedItem: draggingCol4, - state: testState, - groupId: 'a', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'newCol', 'col2', 'col3'], - columns: { - col1: testState.layers.first.columns.col1, - newCol: expect.objectContaining({ - sourceField: (testState.layers.first.columns.col4 as MedianIndexPatternColumn) - .sourceField, - }), - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - }, - incompleteColumns: {}, - }, - }, - }); - }); - - it('copies incompatible column to the bottom of the target group', () => { - // config: - // a: col1 - // b: col2, col3 - // c: col4 - // dragging col4 into newCol in group a - - onDrop({ - ...defaultProps, - columnId: 'newCol', - dropType: 'duplicate_incompatible', - droppedItem: draggingCol4, - state: testState, - groupId: 'a', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'newCol', 'col2', 'col3', 'col4'], - columns: { - col1: testState.layers.first.columns.col1, - newCol: expect.objectContaining({ - sourceField: (testState.layers.first.columns.col4 as MedianIndexPatternColumn) - .sourceField, - }), - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col4, - }, - incompleteColumns: {}, - }, - }, - }); - }); - - it('moves incompatible column with overwrite keeping order of target column', () => { - // config: - // a: col1 - // b: col2, col3 - // c: col4 - // dragging col4 into col2 in group b - - onDrop({ - ...defaultProps, - columnId: 'col2', - dropType: 'move_incompatible', - droppedItem: draggingCol4, - state: testState, - groupId: 'b', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col3'], - columns: { - col1: testState.layers.first.columns.col1, - col2: { - isBucketed: true, - label: 'Top 10 values of bytes', - operationType: 'terms', - sourceField: 'bytes', - dataType: 'number', - params: { - orderBy: { - type: 'alphabetical', - }, - orderDirection: 'desc', - size: 10, - parentFormat: { id: 'terms' }, - }, - }, - col3: testState.layers.first.columns.col3, - }, - incompleteColumns: {}, - }, - }, - }); - }); - - it('when swapping compatibly, columns carry order', () => { - // config: - // a: col1 - // b: col2, col3 - // c: col4 - // dragging col4 into col1 - - onDrop({ - ...defaultProps, - columnId: 'col1', - dropType: 'swap_compatible', - droppedItem: draggingCol4, - state: testState, - groupId: 'a', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col3', 'col4'], - columns: { - col1: testState.layers.first.columns.col4, - col2: testState.layers.first.columns.col2, - col3: testState.layers.first.columns.col3, - col4: testState.layers.first.columns.col1, - }, - }, - }, - }); - }); - - it('when swapping incompatibly, newly created columns take order from the columns they replace', () => { - // config: - // a: col1 - // b: col2, col3 - // c: col4 - // dragging col4 into col2 - - onDrop({ - ...defaultProps, - columnId: 'col2', - dropType: 'swap_incompatible', - droppedItem: draggingCol4, - state: testState, - groupId: 'b', - dimensionGroups: [ - { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, - { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, - { ...dimensionGroups[2] }, - ], - }); - - expect(setState).toBeCalledTimes(1); - expect(setState).toHaveBeenCalledWith({ - ...testState, - layers: { - first: { - ...testState.layers.first, - columnOrder: ['col1', 'col2', 'col3', 'col4'], - columns: { - col1: testState.layers.first.columns.col1, - col2: { - isBucketed: true, - label: 'Top 10 values of bytes', - operationType: 'terms', - sourceField: 'bytes', - dataType: 'number', - params: { - orderBy: { - type: 'alphabetical', - }, - orderDirection: 'desc', - parentFormat: { id: 'terms' }, - size: 10, - }, - }, - col3: testState.layers.first.columns.col3, - col4: { - isBucketed: false, - label: 'Unique count of src', - filter: undefined, - operationType: 'unique_count', - sourceField: 'src', - timeShift: undefined, - dataType: 'number', - params: { - emptyAsNull: true, - }, - scale: 'ratio', - }, - }, - incompleteColumns: {}, - }, - }, - }); - }); - }); - }); - }); -}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.test.ts new file mode 100644 index 0000000000000..f9afc9a00c98f --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.test.ts @@ -0,0 +1,767 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DragDropOperation, OperationMetadata } from '../../../types'; +import { TermsIndexPatternColumn } from '../../operations'; +import { getDropProps } from './get_drop_props'; +import { + mockDataViews, + mockedLayers, + mockedDraggedField, + mockedDndOperations, + mockedColumns, +} from './mocks'; +import { generateId } from '../../../id_generator'; + +const getDefaultProps = () => ({ + state: { + indexPatternRefs: [], + indexPatterns: mockDataViews(), + currentIndexPatternId: 'first', + isFirstExistenceFetch: false, + existingFields: { + first: { + timestamp: true, + bytes: true, + memory: true, + source: true, + }, + }, + layers: { first: mockedLayers.doubleColumnLayer(), second: mockedLayers.emptyLayer() }, + }, + target: mockedDndOperations.notFiltering, + source: mockedDndOperations.bucket, +}); + +describe('IndexPatternDimensionEditorPanel#getDropProps', () => { + describe('not dragging', () => { + it('returns undefined if no drag is happening', () => { + expect(getDropProps({ ...getDefaultProps(), source: undefined })).toBe(undefined); + }); + + it('returns undefined if the dragged item has no field', () => { + expect( + getDropProps({ + ...getDefaultProps(), + source: { name: 'bar', id: 'bar', humanData: { label: 'Label' } }, + }) + ).toBe(undefined); + }); + }); + + describe('dragging a field', () => { + it('returns undefined if field is not supported by filterOperations', () => { + expect( + getDropProps({ + ...getDefaultProps(), + source: mockedDraggedField, + target: mockedDndOperations.staticValue, + }) + ).toBe(undefined); + }); + + it('returns field_replace if the field is supported by filterOperations and the dropTarget is an existing column', () => { + expect( + getDropProps({ + ...getDefaultProps(), + target: mockedDndOperations.numericalOnly, + source: mockedDraggedField, + }) + ).toEqual({ dropTypes: ['field_replace'], nextLabel: 'Intervals' }); + }); + + it('returns field_add if the field is supported by filterOperations and the dropTarget is an empty column', () => { + expect( + getDropProps({ + ...getDefaultProps(), + target: { + ...mockedDndOperations.numericalOnly, + columnId: 'newId', + }, + source: mockedDraggedField, + }) + ).toEqual({ dropTypes: ['field_add'], nextLabel: 'Intervals' }); + }); + + it('returns undefined if the field belongs to another data view', () => { + expect( + getDropProps({ + ...getDefaultProps(), + source: { + ...mockedDraggedField, + indexPatternId: 'first2', + }, + }) + ).toBe(undefined); + }); + + it('returns undefined if the dragged field is already in use by this operation', () => { + expect( + getDropProps({ + ...getDefaultProps(), + source: { + ...mockedDraggedField, + field: { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + exists: true, + }, + }, + }) + ).toBe(undefined); + }); + + it('returns also field_combine if the field is supported by filterOperations and the dropTarget is an existing column that supports multiple fields', () => { + // replace the state with a top values column to enable the multi fields behaviour + const props = getDefaultProps(); + expect( + getDropProps({ + ...props, + source: mockedDraggedField, + target: { + ...props.target, + columnId: 'col2', + filterOperations: (op: OperationMetadata) => op.dataType !== 'date', + }, + }) + ).toEqual({ dropTypes: ['field_replace', 'field_combine'] }); + }); + }); + + describe('dragging a column', () => { + it('allows replacing and replace-duplicating when two columns from compatible groups use the same field', () => { + const props = getDefaultProps(); + props.state.layers.first.columns.col2 = mockedColumns.dateHistogramCopy; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + columnId: 'col2', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ dropTypes: ['replace_compatible', 'replace_duplicate_compatible'] }); + }); + + it('returns correct dropTypes if the dragged column from different group uses the same fields as the dropTarget', () => { + const props = getDefaultProps(); + const sourceMultiFieldColumn = { + ...props.state.layers.first.columns.col1, + sourceField: 'bytes', + params: { + ...(props.state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['dest'], + }, + } as TermsIndexPatternColumn; + // invert the fields + const targetMultiFieldColumn = { + ...props.state.layers.first.columns.col1, + sourceField: 'dest', + params: { + ...(props.state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['bytes'], + }, + } as TermsIndexPatternColumn; + props.state.layers.first.columns = { + col1: sourceMultiFieldColumn, + col2: targetMultiFieldColumn, + }; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + columnId: 'col2', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ dropTypes: ['replace_compatible', 'replace_duplicate_compatible'] }); + }); + + it('returns duplicate and replace if the dragged column from different group uses the same field as the dropTarget, but this last one is multifield, and can be swappable', () => { + const props = getDefaultProps(); + props.state.layers.first.columns.col2 = { + ...props.state.layers.first.columns.col1, + sourceField: 'bytes', + params: { + ...(props.state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['dest'], + }, + } as TermsIndexPatternColumn; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + columnId: 'col2', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], + }); + }); + + it('returns swap, duplicate and replace if the dragged column from different group uses the same field as the dropTarget, but this last one is multifield', () => { + const props = getDefaultProps(); + props.state.layers.first.columns.col2 = { + ...props.state.layers.first.columns.col1, + sourceField: 'bytes', + params: { + ...(props.state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['dest'], + }, + } as TermsIndexPatternColumn; + + expect( + getDropProps({ + ...props, + ...props, + // make it swappable + target: { + ...props.target, + filterOperations: (op: OperationMetadata) => op.isBucketed, + groupId: 'a', + columnId: 'col2', + }, + source: { + ...mockedDndOperations.metric, + filterOperations: (op: OperationMetadata) => op.isBucketed, + groupId: 'c', + }, + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'swap_compatible'], + }); + }); + + it('returns reorder if drop target and source columns are from the same group and both are existing', () => { + const props = getDefaultProps(); + props.state.layers.first.columns.col2 = mockedColumns.sum; + + expect( + getDropProps({ + ...props, + source: { ...mockedDndOperations.metric, groupId: 'a' }, + target: { + ...props.target, + columnId: 'col2', + filterOperations: (op: OperationMetadata) => op.isBucketed === false, + }, + }) + ).toEqual({ + dropTypes: ['reorder'], + }); + }); + + it('returns duplicate_compatible if drop target and source columns are from the same group and drop target id is a new column', () => { + const props = getDefaultProps(); + expect( + getDropProps({ + ...props, + target: { + ...props.target, + groupId: 'a', + columnId: 'newId', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'a', + }, + }) + ).toEqual({ dropTypes: ['duplicate_compatible'] }); + }); + + it('returns compatible drop types if the dragged column is compatible', () => { + const props = getDefaultProps(); + expect( + getDropProps({ + ...props, + target: { + ...props.target, + groupId: 'a', + columnId: 'col3', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ dropTypes: ['move_compatible', 'duplicate_compatible'] }); + }); + + it('returns incompatible drop target types if dropping column to existing incompatible column', () => { + const props = getDefaultProps(); + props.state.layers.first.columns = { + col1: mockedColumns.dateHistogram, + col2: mockedColumns.sum, + }; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + columnId: 'col2', + filterOperations: (op: OperationMetadata) => op.isBucketed === false, + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ + dropTypes: ['replace_incompatible', 'replace_duplicate_incompatible', 'swap_incompatible'], + nextLabel: 'Minimum', + }); + }); + + it('does not return swap_incompatible if current dropTarget column cannot be swapped to the group of dragging column', () => { + const props = getDefaultProps(); + props.state.layers.first.columns = { + col1: mockedColumns.dateHistogram, + col2: mockedColumns.count, + }; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + columnId: 'col2', + filterOperations: (op: OperationMetadata) => op.isBucketed === false, + }, + source: { + columnId: 'col1', + groupId: 'b', + layerId: 'first', + id: 'col1', + humanData: { label: 'Label' }, + filterOperations: (op: OperationMetadata) => op.isBucketed === true, + }, + }) + ).toEqual({ + dropTypes: ['replace_incompatible', 'replace_duplicate_incompatible'], + nextLabel: 'Minimum', + }); + }); + + it('returns combine_compatible drop type if the dragged column is compatible and the target one support multiple fields', () => { + const props = getDefaultProps(); + props.state.layers.first.columns = { + col1: mockedColumns.terms, + col2: { + ...mockedColumns.terms, + sourceField: 'bytes', + }, + }; + expect( + getDropProps({ + ...props, + target: { + ...props.target, + columnId: 'col2', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible', 'combine_compatible'], + }); + }); + + it('returns no combine_compatible drop type if the target column uses rarity ordering', () => { + const props = getDefaultProps(); + props.state.layers.first.columns = { + col1: mockedColumns.terms, + col2: { + ...mockedColumns.terms, + sourceField: 'bytes', + params: { + ...(props.state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + orderBy: { type: 'rare' }, + }, + } as TermsIndexPatternColumn, + }; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + groupId: 'a', + columnId: 'col2', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], + }); + }); + + it('returns no combine drop type if the dragged column is compatible, the target one supports multiple fields but there are too many fields', () => { + const props = getDefaultProps(); + props.state.layers.first.columns.col2 = { + ...props.state.layers.first.columns.col1, + sourceField: 'source', + params: { + ...(props.state.layers.first.columns.col1 as TermsIndexPatternColumn).params, + secondaryFields: ['memory', 'bytes', 'geo.src'], // too many fields here + }, + } as TermsIndexPatternColumn; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + groupId: 'a', + columnId: 'col2', + }, + source: { + ...mockedDndOperations.metric, + groupId: 'c', + }, + }) + ).toEqual({ + dropTypes: ['replace_compatible', 'replace_duplicate_compatible'], + }); + }); + + it('returns combine_incompatible drop target types if dropping column to existing incompatible column which supports multiple fields', () => { + const props = getDefaultProps(); + props.state.layers.first.columns = { + col1: mockedColumns.terms, + col2: mockedColumns.sum, + }; + + expect( + getDropProps({ + ...props, + target: { + ...props.target, + groupId: 'a', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + // drag the sum over the top values + source: { + ...mockedDndOperations.bucket, + groupId: 'c', + filterOperation: undefined, + }, + }) + ).toEqual({ + dropTypes: [ + 'replace_incompatible', + 'replace_duplicate_incompatible', + 'swap_incompatible', + 'combine_incompatible', + ], + nextLabel: 'Top values', + }); + }); + }); + + describe('getDropProps between layers', () => { + it('allows dropping to the same group', () => { + const props = getDefaultProps(); + expect( + getDropProps({ + ...props, + source: { + ...mockedDndOperations.metric, + columnId: 'col1', + layerId: 'first', + groupId: 'c', + }, + target: { + ...props.target, + columnId: 'newId', + groupId: 'c', + layerId: 'second', + }, + }) + ).toEqual({ + dropTypes: ['move_compatible', 'duplicate_compatible'], + }); + }); + it('allows dropping to compatible groups', () => { + const props = getDefaultProps(); + expect( + getDropProps({ + ...props, + source: { + ...mockedDndOperations.metric, + columnId: 'col1', + layerId: 'first', + groupId: 'a', + }, + target: { + ...props.target, + columnId: 'newId', + groupId: 'c', + layerId: 'second', + }, + }) + ).toEqual({ + dropTypes: ['move_compatible', 'duplicate_compatible'], + }); + }); + it('allows incompatible drop', () => { + const props = getDefaultProps(); + expect( + getDropProps({ + ...props, + source: { + ...mockedDndOperations.metric, + columnId: 'col1', + layerId: 'first', + groupId: 'c', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + target: { + ...props.target, + columnId: 'newId', + groupId: 'c', + layerId: 'second', + filterOperations: (op: OperationMetadata) => !op.isBucketed, + }, + })?.dropTypes + ).toEqual(['move_incompatible', 'duplicate_incompatible']); + }); + it('allows dropping references', () => { + const props = getDefaultProps(); + const referenceDragging = { + columnId: 'col1', + groupId: 'a', + layerId: 'first', + id: 'col1', + humanData: { label: 'Label' }, + }; + + (generateId as jest.Mock).mockReturnValue(`ref1Copy`); + props.state = { + ...props.state, + layers: { + ...props.state.layers, + first: { + indexPatternId: 'first', + columnOrder: ['col1', 'ref1'], + columns: { + col1: { + label: 'Test reference', + dataType: 'number', + isBucketed: false, + operationType: 'cumulative_sum', + references: ['ref1'], + }, + ref1: { + label: 'Count of records', + dataType: 'number', + isBucketed: false, + sourceField: '___records___', + operationType: 'count', + }, + }, + }, + }, + }; + + expect( + getDropProps({ + ...props, + source: referenceDragging, + target: { + ...props.target, + columnId: 'newColumnId', + groupId: 'c', + layerId: 'second', + filterOperations: (op: OperationMetadata) => !op.isBucketed, + }, + })?.dropTypes + ).toEqual(['move_compatible', 'duplicate_compatible']); + }); + it('doesnt allow dropping for different index patterns', () => { + const props = getDefaultProps(); + props.state.layers.second.indexPatternId = 'different index'; + expect( + getDropProps({ + ...props, + source: { + ...mockedDndOperations.metric, + columnId: 'col1', + layerId: 'first', + groupId: 'c', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + target: { + ...props.target, + columnId: 'newId', + groupId: 'c', + layerId: 'second', + filterOperations: (op: OperationMetadata) => !op.isBucketed, + }, + })?.dropTypes + ).toEqual(undefined); + }); + + it('does not allow static value to be moved when not allowed', () => { + const props = getDefaultProps(); + props.state.layers = { + first: { + indexPatternId: 'first', + columns: { + col1: mockedColumns.dateHistogram, + colMetric: mockedColumns.count, + }, + columnOrder: ['col1', 'colMetric'], + incompleteColumns: {}, + }, + second: { + indexPatternId: 'first', + columns: { + staticValue: mockedColumns.staticValue, + }, + columnOrder: ['staticValue'], + incompleteColumns: {}, + }, + }; + expect( + getDropProps({ + ...props, + source: { + columnId: 'staticValue', + groupId: 'yReferenceLineLeft', + layerId: 'second', + id: 'staticValue', + humanData: { label: 'Label' }, + }, + target: { + layerId: 'first', + columnId: 'col1', + groupId: 'x', + } as DragDropOperation, + })?.dropTypes + ).toEqual(undefined); + }); + it('allow multiple drop types from terms to terms', () => { + const props = getDefaultProps(); + props.state.layers = { + first: { + indexPatternId: 'first', + columns: { + terms: mockedColumns.terms, + metric: mockedColumns.count, + }, + columnOrder: ['terms', 'metric'], + incompleteColumns: {}, + }, + second: { + indexPatternId: 'first', + columns: { + terms2: mockedColumns.terms2, + metric2: mockedColumns.count, + }, + columnOrder: ['terms2', 'metric2'], + incompleteColumns: {}, + }, + }; + expect( + getDropProps({ + ...props, + source: { + columnId: 'terms', + groupId: 'x', + layerId: 'first', + id: 'terms', + humanData: { label: 'Label' }, + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + target: { + columnId: 'terms2', + groupId: 'x', + layerId: 'second', + filterOperations: (op: OperationMetadata) => op.isBucketed, + } as DragDropOperation, + })?.dropTypes + ).toEqual([ + 'replace_compatible', + 'replace_duplicate_compatible', + 'swap_compatible', + 'combine_compatible', + ]); + }); + it('allow multiple drop types from metric on field to terms', () => { + const props = getDefaultProps(); + props.state.layers = { + first: { + indexPatternId: 'first', + columns: { + sum: mockedColumns.sum, + metric: mockedColumns.count, + }, + columnOrder: ['sum', 'metric'], + incompleteColumns: {}, + }, + second: { + indexPatternId: 'first', + columns: { + terms2: mockedColumns.terms2, + metric2: mockedColumns.count, + }, + columnOrder: ['terms2', 'metric2'], + incompleteColumns: {}, + }, + }; + expect( + getDropProps({ + ...props, + source: { + columnId: 'sum', + groupId: 'x', + layerId: 'first', + id: 'sum', + humanData: { label: 'Label' }, + filterOperations: (op: OperationMetadata) => !op.isBucketed, + }, + target: { + columnId: 'terms2', + groupId: 'x', + layerId: 'second', + filterOperations: (op: OperationMetadata) => op.isBucketed, + } as DragDropOperation, + })?.dropTypes + ).toEqual([ + 'replace_incompatible', + 'replace_duplicate_incompatible', + 'swap_incompatible', + 'combine_incompatible', + ]); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts index 3318b8c30909e..744033a2428fa 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/get_drop_props.ts @@ -5,13 +5,7 @@ * 2.0. */ -import { - DatasourceDimensionDropProps, - isDraggedOperation, - DraggedOperation, - DropType, - VisualizationDimensionGroupConfig, -} from '../../../types'; +import { isOperation, DropType, DragDropOperation } from '../../../types'; import { getCurrentFieldsForOperation, getOperationDisplay, @@ -27,12 +21,18 @@ import { IndexPattern, IndexPatternField, DraggedField, + DataViewDragDropOperation, } from '../../types'; - -type GetDropProps = DatasourceDimensionDropProps & { - dragging?: DragContextState['dragging']; - groupId: string; -}; +import { + getDropPropsForSameGroup, + isOperationFromTheSameGroup, +} from '../../../editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils'; + +interface GetDropPropsArgs { + state: IndexPatternPrivateState; + source?: DragContextState['dragging']; + target: DragDropOperation; +} type DropProps = { dropTypes: DropType[]; nextLabel?: string } | undefined; @@ -41,7 +41,7 @@ const operationLabels = getOperationDisplay(); export function getNewOperation( field: IndexPatternField | undefined | false, filterOperations: (meta: OperationMetadata) => boolean, - targetColumn: GenericIndexPatternColumn, + targetColumn?: GenericIndexPatternColumn, prioritizedOperation?: GenericIndexPatternColumn['operationType'] ) { if (!field) { @@ -61,52 +61,50 @@ export function getNewOperation( return existsPrioritizedOperation ? prioritizedOperation : newOperations[0]; } -export function getField( - column: GenericIndexPatternColumn | undefined, - indexPattern: IndexPattern -) { +export function getField(column: GenericIndexPatternColumn | undefined, dataView: IndexPattern) { if (!column) { return; } - const field = (hasField(column) && indexPattern.getFieldByName(column.sourceField)) || undefined; + const field = (hasField(column) && dataView.getFieldByName(column.sourceField)) || undefined; return field; } -export function getDropProps(props: GetDropProps) { - const { state, columnId, layerId, dragging, groupId, filterOperations } = props; - if (!dragging) { +export function getDropProps(props: GetDropPropsArgs) { + const { state, source, target } = props; + if (!source) { return; } + const targetProps: DataViewDragDropOperation = { + ...target, + column: state.layers[target.layerId].columns[target.columnId], + dataView: state.indexPatterns[state.layers[target.layerId].indexPatternId], + }; - if (isDraggedField(dragging)) { - return getDropPropsForField({ ...props, dragging }); + if (isDraggedField(source)) { + return getDropPropsForField({ ...props, source, target: targetProps }); } - if ( - isDraggedOperation(dragging) && - dragging.layerId === layerId && - columnId !== dragging.columnId - ) { - const sourceColumn = state.layers[dragging.layerId].columns[dragging.columnId]; - const targetColumn = state.layers[layerId].columns[columnId]; - const isSameGroup = groupId === dragging.groupId; - if (isSameGroup) { - return getDropPropsForSameGroup(!targetColumn); - } - const layerIndexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; - - if (filterOperations(sourceColumn)) { - return getDropPropsForCompatibleGroup( - props.dimensionGroups, - dragging.columnId, - sourceColumn, - targetColumn, - layerIndexPattern - ); - } else if (hasTheSameField(sourceColumn, targetColumn)) { + if (isOperation(source)) { + const sourceProps: DataViewDragDropOperation = { + ...source, + column: state.layers[source.layerId]?.columns[source.columnId], + dataView: state.indexPatterns[state.layers[source.layerId]?.indexPatternId], + }; + if (!sourceProps.column) { return; - } else { - return getDropPropsFromIncompatibleGroup({ ...props, dragging }); + } + if (target.columnId !== source.columnId && targetProps.dataView === sourceProps.dataView) { + if (isOperationFromTheSameGroup(source, target)) { + return getDropPropsForSameGroup(!targetProps.column); + } + + if (targetProps.filterOperations?.(sourceProps?.column)) { + return getDropPropsForCompatibleGroup(sourceProps, targetProps); + } else if (hasTheSameField(sourceProps.column, targetProps.column)) { + return; + } else { + return getDropPropsFromIncompatibleGroup(sourceProps, targetProps); + } } } } @@ -126,14 +124,13 @@ function hasTheSameField( function getDropPropsForField({ state, - columnId, - layerId, - dragging, - filterOperations, -}: GetDropProps & { dragging: DraggedField }): DropProps { - const targetColumn = state.layers[layerId].columns[columnId]; - const isTheSameIndexPattern = state.layers[layerId].indexPatternId === dragging.indexPatternId; - const newOperation = getNewOperation(dragging.field, filterOperations, targetColumn); + source, + target, +}: GetDropPropsArgs & { source: DraggedField }): DropProps { + const targetColumn = state.layers[target.layerId].columns[target.columnId]; + const isTheSameIndexPattern = + state.layers[target.layerId].indexPatternId === source.indexPatternId; + const newOperation = getNewOperation(source.field, target.filterOperations, targetColumn); if (isTheSameIndexPattern && newOperation) { const nextLabel = operationLabels[newOperation].displayName; @@ -141,18 +138,13 @@ function getDropPropsForField({ if (!targetColumn) { return { dropTypes: ['field_add'], nextLabel }; } else if ( - (hasField(targetColumn) && targetColumn.sourceField !== dragging.field.name) || + (hasField(targetColumn) && targetColumn.sourceField !== source.field.name) || !hasField(targetColumn) ) { - const layerIndexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; + const layerDataView = state.indexPatterns[state.layers[target.layerId].indexPatternId]; return hasField(targetColumn) && - layerIndexPattern && - hasOperationSupportForMultipleFields( - layerIndexPattern, - targetColumn, - undefined, - dragging.field - ) + layerDataView && + hasOperationSupportForMultipleFields(layerDataView, targetColumn, undefined, source.field) ? { dropTypes: ['field_replace', 'field_combine'], } @@ -165,82 +157,68 @@ function getDropPropsForField({ return; } -function getDropPropsForSameGroup(isNew?: boolean): DropProps { - return !isNew ? { dropTypes: ['reorder'] } : { dropTypes: ['duplicate_compatible'] }; -} - function getDropPropsForCompatibleGroup( - dimensionGroups: VisualizationDimensionGroupConfig[], - sourceId: string, - sourceColumn?: GenericIndexPatternColumn, - targetColumn?: GenericIndexPatternColumn, - indexPattern?: IndexPattern + sourceProps: DataViewDragDropOperation, + targetProps: DataViewDragDropOperation ): DropProps { - const hasSameField = sourceColumn && hasTheSameField(sourceColumn, targetColumn); - - const canSwap = - targetColumn && - !hasSameField && - dimensionGroups - .find((group) => group.accessors.some((accessor) => accessor.columnId === sourceId)) - ?.filterOperations(targetColumn); - + if (!targetProps.column) { + return { dropTypes: ['move_compatible', 'duplicate_compatible'] }; + } + const canSwap = sourceProps.filterOperations?.(targetProps.column); const swapType: DropType[] = canSwap ? ['swap_compatible'] : []; - if (!targetColumn) { - return { dropTypes: ['move_compatible', 'duplicate_compatible', ...swapType] }; + const dropTypes: DropType[] = ['replace_compatible', 'replace_duplicate_compatible', ...swapType]; + if (!targetProps.dataView || !hasField(targetProps.column)) { + return { dropTypes }; } - if (!indexPattern || !hasField(targetColumn)) { - return { dropTypes: ['replace_compatible', 'replace_duplicate_compatible', ...swapType] }; - } - // With multi fields operations there are more combination of drops now - const dropTypes: DropType[] = []; - if (!hasSameField) { - dropTypes.push('replace_compatible', 'replace_duplicate_compatible'); - } - if (canSwap) { - dropTypes.push('swap_compatible'); - } - if (hasOperationSupportForMultipleFields(indexPattern, targetColumn, sourceColumn)) { + + if ( + hasOperationSupportForMultipleFields( + targetProps.dataView, + targetProps.column, + sourceProps.column + ) + ) { dropTypes.push('combine_compatible'); } - // return undefined if no drop action is available - if (!dropTypes.length) { - return; - } return { dropTypes, }; } -function getDropPropsFromIncompatibleGroup({ - state, - columnId, - layerId, - dragging, - filterOperations, -}: GetDropProps & { dragging: DraggedOperation }): DropProps { - const targetColumn = state.layers[layerId].columns[columnId]; - const sourceColumn = state.layers[dragging.layerId].columns[dragging.columnId]; - - const layerIndexPattern = state.indexPatterns[state.layers[layerId].indexPatternId]; - if (!layerIndexPattern) { +function getDropPropsFromIncompatibleGroup( + sourceProps: DataViewDragDropOperation, + targetProps: DataViewDragDropOperation +): DropProps { + if (!targetProps.dataView || !sourceProps.column) { return; } - const sourceField = getField(sourceColumn, layerIndexPattern); - const newOperationForSource = getNewOperation(sourceField, filterOperations, targetColumn); + const sourceField = getField(sourceProps.column, sourceProps.dataView); + const newOperationForSource = getNewOperation( + sourceField, + targetProps.filterOperations, + targetProps.column + ); if (newOperationForSource) { - const targetField = getField(targetColumn, layerIndexPattern); - const canSwap = Boolean(getNewOperation(targetField, dragging.filterOperations, sourceColumn)); + const targetField = getField(targetProps.column, targetProps.dataView); + const canSwap = Boolean( + getNewOperation(targetField, sourceProps.filterOperations, sourceProps.column) + ); const dropTypes: DropType[] = []; - if (targetColumn) { + if (targetProps.column) { dropTypes.push('replace_incompatible', 'replace_duplicate_incompatible'); if (canSwap) { dropTypes.push('swap_incompatible'); } - if (hasOperationSupportForMultipleFields(layerIndexPattern, targetColumn, sourceColumn)) { + if ( + hasOperationSupportForMultipleFields( + targetProps.dataView, + targetProps.column, + sourceProps.column + ) + ) { dropTypes.push('combine_incompatible'); } } else { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/mocks.ts new file mode 100644 index 0000000000000..40121cf99f546 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/mocks.ts @@ -0,0 +1,292 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IndexPattern, IndexPatternLayer } from '../../types'; +import { documentField } from '../../document_field'; +import { OperationMetadata } from '../../../types'; +import { + DateHistogramIndexPatternColumn, + GenericIndexPatternColumn, + StaticValueIndexPatternColumn, + TermsIndexPatternColumn, +} from '../../operations'; +import { getFieldByNameFactory } from '../../pure_helpers'; +jest.mock('../../../id_generator'); + +export const mockDataViews = (): Record => { + 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, + }, + { + name: 'src', + displayName: 'src', + type: 'string', + aggregatable: true, + searchable: true, + exists: true, + }, + { + name: 'dest', + displayName: 'dest', + type: 'string', + aggregatable: true, + searchable: true, + exists: true, + }, + documentField, + ]; + return { + first: { + id: 'first', + title: 'first', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields, + getFieldByName: getFieldByNameFactory(fields), + }, + second: { + id: 'second', + title: 'my-fake-restricted-pattern', + hasRestrictions: true, + timeFieldName: 'timestamp', + fields: [fields[0]], + getFieldByName: getFieldByNameFactory([fields[0]]), + }, + }; +}; + +export const mockedColumns: Record = { + count: { + label: 'Count of records', + dataType: 'number', + isBucketed: false, + sourceField: '___records___', + operationType: 'count', + }, + staticValue: { + label: 'Static value: 0.75', + dataType: 'number', + operationType: 'static_value', + isStaticValue: true, + isBucketed: false, + scale: 'ratio', + params: { + value: '0.75', + }, + references: [], + } as StaticValueIndexPatternColumn, + dateHistogram: { + label: 'Date histogram of timestamp', + customLabel: true, + dataType: 'date', + isBucketed: true, + + // Private + operationType: 'date_histogram', + params: { + interval: '1d', + }, + sourceField: 'timestamp', + } as DateHistogramIndexPatternColumn, + dateHistogramCopy: { + label: 'Date histogram of timestamp (1)', + customLabel: true, + dataType: 'date', + isBucketed: true, + + // Private + operationType: 'date_histogram', + params: { + interval: '1d', + }, + sourceField: 'timestamp', + } as DateHistogramIndexPatternColumn, + terms: { + label: 'Top 10 values of src', + dataType: 'string', + isBucketed: true, + // Private + operationType: 'terms', + params: { + orderBy: { type: 'alphabetical' }, + orderDirection: 'desc', + size: 10, + }, + sourceField: 'src', + } as TermsIndexPatternColumn, + terms2: { + label: 'Top 10 values of dest', + dataType: 'string', + isBucketed: true, + + // Private + operationType: 'terms', + params: { + orderBy: { type: 'alphabetical' }, + orderDirection: 'desc', + size: 10, + }, + sourceField: 'dest', + } as TermsIndexPatternColumn, + sum: { + label: 'Sum of bytes', + dataType: 'number', + isBucketed: false, + operationType: 'sum', + sourceField: 'bytes', + } as GenericIndexPatternColumn, + median: { + label: 'Median of bytes', + dataType: 'number', + isBucketed: false, + + // Private + operationType: 'median', + sourceField: 'bytes', + } as GenericIndexPatternColumn, + uniqueCount: { + label: 'Unique count of bytes', + dataType: 'number', + isBucketed: false, + sourceField: 'bytes', + operationType: 'unique_count', + } as GenericIndexPatternColumn, +}; + +export const mockedLayers: Record IndexPatternLayer> = { + singleColumnLayer: (id = 'col1') => ({ + indexPatternId: 'first', + columnOrder: [id], + columns: { + [id]: mockedColumns.dateHistogram, + }, + incompleteColumns: {}, + }), + doubleColumnLayer: (id1 = 'col1', id2 = 'col2') => ({ + indexPatternId: 'first', + columnOrder: [id1, id2], + columns: { + [id1]: mockedColumns.dateHistogram, + [id2]: mockedColumns.terms, + }, + incompleteColumns: {}, + }), + multipleColumnsLayer: (id1 = 'col1', id2 = 'col2', id3 = 'col3', id4 = 'col4') => ({ + indexPatternId: 'first', + columnOrder: [id1, id2, id3, id4], + columns: { + [id1]: mockedColumns.dateHistogram, + [id2]: mockedColumns.terms, + [id3]: mockedColumns.terms2, + [id4]: mockedColumns.median, + }, + }), + emptyLayer: () => ({ + indexPatternId: 'first', + columnOrder: [], + columns: {}, + }), +}; + +export const mockedDraggedField = { + field: { type: 'number', name: 'bytes', aggregatable: true }, + indexPatternId: 'first', + id: 'bar', + humanData: { label: 'Label' }, +}; + +export const mockedDndOperations = { + notFiltering: { + layerId: 'first', + groupId: 'a', + filterOperations: () => true, + columnId: 'col1', + id: 'col1', + humanData: { label: 'Column 1' }, + }, + metric: { + layerId: 'first', + groupId: 'a', + columnId: 'col1', + filterOperations: (op: OperationMetadata) => !op.isBucketed, + id: 'col1', + humanData: { label: 'Column 1' }, + }, + numericalOnly: { + layerId: 'first', + groupId: 'a', + columnId: 'col1', + filterOperations: (op: OperationMetadata) => op.dataType === 'number', + id: 'col1', + humanData: { label: 'Column 1' }, + }, + bucket: { + columnId: 'col2', + groupId: 'b', + layerId: 'first', + id: 'col2', + humanData: { label: 'Column 2' }, + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + staticValue: { + columnId: 'col1', + groupId: 'b', + layerId: 'first', + id: 'col1', + humanData: { label: 'Column 2' }, + filterOperations: (op: OperationMetadata) => !!op.isStaticValue, + }, + bucket2: { + columnId: 'col3', + groupId: 'b', + layerId: 'first', + id: 'col3', + humanData: { + label: '', + }, + }, + metricC: { + columnId: 'col4', + groupId: 'c', + layerId: 'first', + id: 'col4', + humanData: { + label: '', + }, + filterOperations: (op: OperationMetadata) => !op.isBucketed, + }, +}; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.test.ts new file mode 100644 index 0000000000000..12acf46c58380 --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.test.ts @@ -0,0 +1,2259 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { onDrop } from './on_drop_handler'; +import { IndexPatternPrivateState } from '../../types'; +import { OperationMetadata, DropType, DatasourceDimensionDropHandlerProps } from '../../../types'; +import { FormulaIndexPatternColumn, MedianIndexPatternColumn } from '../../operations'; +import { generateId } from '../../../id_generator'; +import { + mockDataViews, + mockedLayers, + mockedDraggedField, + mockedDndOperations, + mockedColumns, +} from './mocks'; + +jest.mock('../../../id_generator'); + +const dimensionGroups = [ + { + accessors: [], + groupId: 'a', + supportsMoreColumns: true, + hideGrouping: true, + groupLabel: '', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + { + accessors: [{ columnId: 'col1' }, { columnId: 'col2' }, { columnId: 'col3' }], + groupId: 'b', + supportsMoreColumns: true, + hideGrouping: true, + groupLabel: '', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + { + accessors: [{ columnId: 'col4' }], + groupId: 'c', + supportsMoreColumns: true, + hideGrouping: true, + groupLabel: '', + filterOperations: (op: OperationMetadata) => op.isBucketed === false, + }, +]; + +function getStateWithMultiFieldColumn(state: IndexPatternPrivateState) { + return { + ...state, + layers: { + ...state.layers, + first: { + ...state.layers.first, + columns: { + col1: mockedColumns.terms2, + }, + }, + }, + }; +} + +describe('IndexPatternDimensionEditorPanel: onDrop', () => { + let state: IndexPatternPrivateState; + let setState: jest.Mock; + let defaultProps: DatasourceDimensionDropHandlerProps; + + beforeEach(() => { + state = { + indexPatternRefs: [], + indexPatterns: mockDataViews(), + currentIndexPatternId: 'first', + isFirstExistenceFetch: false, + existingFields: { + first: { + timestamp: true, + bytes: true, + memory: true, + source: true, + }, + }, + layers: { + first: mockedLayers.singleColumnLayer(), + second: mockedLayers.emptyLayer(), + }, + }; + + setState = jest.fn(); + + defaultProps = { + dropType: 'reorder', + source: { name: 'bar', id: 'bar', humanData: { label: 'Label' } }, + target: mockedDndOperations.notFiltering, + state, + setState, + dimensionGroups: [], + }; + + jest.clearAllMocks(); + }); + + describe('dropping a field', () => { + it('updates a column when a field is dropped', () => { + onDrop({ + ...defaultProps, + source: mockedDraggedField, + dropType: 'field_replace', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: expect.objectContaining({ + columns: expect.objectContaining({ + col1: expect.objectContaining({ + dataType: 'number', + sourceField: mockedDraggedField.field.name, + }), + }), + }), + }, + }); + }); + it('selects the specific operation that was valid on drop', () => { + onDrop({ + ...defaultProps, + source: mockedDraggedField, + dropType: 'field_replace', + target: { + ...defaultProps.target, + filterOperations: (op: OperationMetadata) => op.isBucketed, + columnId: 'col2', + }, + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: { + ...state.layers.first, + columnOrder: ['col1', 'col2'], + columns: { + ...state.layers.first.columns, + col2: expect.objectContaining({ + dataType: 'number', + sourceField: mockedDraggedField.field.name, + }), + }, + }, + }, + }); + }); + it('keeps the operation when dropping a different compatible field', () => { + onDrop({ + ...defaultProps, + source: { + humanData: { label: 'Label1' }, + field: { name: 'memory', type: 'number', aggregatable: true }, + indexPatternId: 'first', + id: '1', + }, + state: { + ...state, + layers: { + ...state.layers, + first: { + indexPatternId: 'first', + columnOrder: ['col1'], + columns: { + col1: mockedColumns.sum, + }, + }, + }, + }, + dropType: 'field_replace', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: expect.objectContaining({ + columns: expect.objectContaining({ + col1: expect.objectContaining({ + operationType: 'sum', + dataType: 'number', + sourceField: 'memory', + }), + }), + }), + }, + }); + }); + it('appends the dropped column when a field is dropped', () => { + onDrop({ + ...defaultProps, + source: mockedDraggedField, + dropType: 'field_replace', + target: { + ...defaultProps.target, + columnId: 'col2', + filterOperations: (op: OperationMetadata) => op.dataType === 'number', + }, + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: { + ...state.layers.first, + columnOrder: ['col1', 'col2'], + columns: { + ...state.layers.first.columns, + col2: expect.objectContaining({ + dataType: 'number', + sourceField: mockedDraggedField.field.name, + }), + }, + }, + }, + }); + }); + it('dimensionGroups are defined - appends the dropped column in the right place when a field is dropped', () => { + const testState = { ...state }; + testState.layers.first = { ...mockedLayers.multipleColumnsLayer() }; + // config: + // a: + // b: col1, col2, col3 + // c: col4 + // dragging field into newCol in group a + + onDrop({ + ...defaultProps, + source: mockedDraggedField, + dimensionGroups, + dropType: 'field_add', + target: { + ...defaultProps.target, + filterOperations: (op: OperationMetadata) => op.dataType === 'number', + groupId: 'a', + columnId: 'newCol', + }, + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['newCol', 'col1', 'col2', 'col3', 'col4'], + columns: { + newCol: expect.objectContaining({ + dataType: 'number', + sourceField: mockedDraggedField.field.name, + }), + col1: testState.layers.first.columns.col1, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + incompleteColumns: {}, + }, + }, + }); + }); + + it('appends the new field to the column that supports multiple fields when a field is dropped', () => { + state = getStateWithMultiFieldColumn(state); + onDrop({ + ...defaultProps, + state, + source: mockedDraggedField, + dropType: 'field_combine', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: expect.objectContaining({ + columns: expect.objectContaining({ + col1: expect.objectContaining({ + dataType: 'string', + sourceField: 'dest', + params: expect.objectContaining({ + secondaryFields: [mockedDraggedField.field.name], + }), + }), + }), + }), + }, + }); + }); + }); + + describe('dropping a dimension', () => { + it('sets correct order in group for metric and bucket columns when duplicating a column in group', () => { + const testState: IndexPatternPrivateState = { + ...state, + layers: { + ...state.layers, + first: { + indexPatternId: 'first', + columnOrder: ['col1', 'col2', 'col3'], + columns: { + col1: mockedColumns.dateHistogram, + col2: mockedColumns.terms, + col3: mockedColumns.sum, + }, + }, + }, + }; + + const referenceDragging = { + columnId: 'col3', + groupId: 'a', + layerId: 'first', + id: 'col3', + humanData: { label: 'Label' }, + }; + + onDrop({ + ...defaultProps, + source: referenceDragging, + state: testState, + dropType: 'duplicate_compatible', + target: { + ...defaultProps.target, + columnId: 'newCol', + }, + }); + // metric is appended + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'col2', 'col3', 'newCol'], + columns: { + col1: testState.layers.first.columns.col1, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + newCol: testState.layers.first.columns.col3, + }, + }, + }, + }); + + const bucketDragging = { + columnId: 'col2', + groupId: 'a', + layerId: 'first', + id: 'col2', + humanData: { label: 'Label' }, + }; + + onDrop({ + ...defaultProps, + state: testState, + dropType: 'duplicate_compatible', + source: bucketDragging, + target: { + ...defaultProps.target, + columnId: 'newCol', + }, + }); + + // bucket is placed after the last existing bucket + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'col2', 'newCol', 'col3'], + columns: { + col1: testState.layers.first.columns.col1, + col2: testState.layers.first.columns.col2, + newCol: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + }, + }, + }, + }); + }); + + it('when duplicating fullReference column, the referenced columns get duplicated too', () => { + (generateId as jest.Mock).mockReturnValue(`ref1Copy`); + const testState: IndexPatternPrivateState = { + ...state, + layers: { + ...state.layers, + first: { + indexPatternId: '1', + columnOrder: ['col1', 'ref1'], + columns: { + col1: { + label: 'Test reference', + dataType: 'number', + isBucketed: false, + operationType: 'cumulative_sum', + references: ['ref1'], + }, + ref1: mockedColumns.count, + }, + }, + }, + }; + const referenceDragging = { + columnId: 'col1', + groupId: 'a', + layerId: 'first', + id: 'col1', + humanData: { label: 'Label' }, + }; + onDrop({ + ...defaultProps, + source: referenceDragging, + state: testState, + dropType: 'duplicate_compatible', + target: { + ...defaultProps.target, + columnId: 'col1Copy', + }, + }); + + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'ref1', 'ref1Copy', 'col1Copy'], + columns: { + ref1: testState.layers.first.columns.ref1, + col1: testState.layers.first.columns.col1, + ref1Copy: { ...testState.layers.first.columns.ref1 }, + col1Copy: { + ...testState.layers.first.columns.col1, + references: ['ref1Copy'], + }, + }, + }, + }, + }); + }); + + it('when duplicating fullReference column, the multiple referenced columns get duplicated too', () => { + (generateId as jest.Mock).mockReturnValueOnce(`ref1Copy`); + (generateId as jest.Mock).mockReturnValueOnce(`ref2Copy`); + const testState: IndexPatternPrivateState = { + ...state, + layers: { + ...state.layers, + first: { + indexPatternId: '1', + columnOrder: ['col1', 'ref1'], + columns: { + col1: { + label: 'Test reference', + dataType: 'number', + isBucketed: false, + operationType: 'cumulative_sum', + references: ['ref1', 'ref2'], + }, + ref1: mockedColumns.count, + ref2: mockedColumns.uniqueCount, + }, + }, + }, + }; + const metricDragging = { + columnId: 'col1', + groupId: 'a', + layerId: 'first', + id: 'col1', + humanData: { label: 'Label' }, + }; + onDrop({ + ...defaultProps, + source: metricDragging, + state: testState, + dropType: 'duplicate_compatible', + target: { + ...defaultProps.target, + columnId: 'col1Copy', + }, + }); + + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'ref1', 'ref2', 'ref1Copy', 'ref2Copy', 'col1Copy'], + columns: { + ref1: testState.layers.first.columns.ref1, + ref2: testState.layers.first.columns.ref2, + col1: testState.layers.first.columns.col1, + ref2Copy: { ...testState.layers.first.columns.ref2 }, + ref1Copy: { ...testState.layers.first.columns.ref1 }, + col1Copy: { + ...testState.layers.first.columns.col1, + references: ['ref1Copy', 'ref2Copy'], + }, + }, + }, + }, + }); + }); + + it('when duplicating fullReference column, the referenced columns get duplicated', () => { + (generateId as jest.Mock).mockReturnValueOnce(`ref1Copy`); + (generateId as jest.Mock).mockReturnValueOnce(`ref2Copy`); + const testState: IndexPatternPrivateState = { + ...state, + layers: { + ...state.layers, + first: { + indexPatternId: '1', + columnOrder: ['ref2', 'ref1', 'col1'], + columns: { + col1: { + label: 'Test reference', + dataType: 'number', + isBucketed: false, + operationType: 'cumulative_sum', + references: ['ref1', 'ref2'], + }, + ref1: mockedColumns.count, + ref2: { + label: 'Unique count of bytes', + dataType: 'number', + isBucketed: false, + sourceField: 'bytes', + operationType: 'unique_count', + }, + }, + }, + }, + }; + const refDragging = { + columnId: 'col1', + groupId: 'a', + layerId: 'first', + id: 'col1', + humanData: { label: 'Label' }, + }; + onDrop({ + ...defaultProps, + source: refDragging, + state: testState, + dropType: 'duplicate_compatible', + target: { + ...defaultProps.target, + columnId: 'col1Copy', + }, + }); + + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['ref2', 'ref1', 'col1', 'ref1Copy', 'ref2Copy', 'col1Copy'], + columns: { + ref1: testState.layers.first.columns.ref1, + ref2: testState.layers.first.columns.ref2, + col1: testState.layers.first.columns.col1, + ref2Copy: { ...testState.layers.first.columns.ref2 }, + ref1Copy: { + ...testState.layers.first.columns.ref1, + }, + col1Copy: { + ...testState.layers.first.columns.col1, + references: ['ref1Copy', 'ref2Copy'], + }, + }, + }, + }, + }); + }); + + it('sets correct order in group when reordering a column in group', () => { + const testState = { + ...state, + layers: { + ...state.layers, + first: { + indexPatternId: 'first', + columnOrder: ['col1', 'col2', 'col3'], + columns: { + col1: mockedColumns.dateHistogram, + col2: mockedColumns.terms, + col3: mockedColumns.terms2, + }, + }, + }, + }; + + const defaultReorderDropParams = { + ...defaultProps, + target: { + ...defaultProps.target, + filterOperations: (op: OperationMetadata) => op.dataType === 'number', + }, + source: mockedDndOperations.metric, + state: testState, + dropType: 'reorder' as DropType, + }; + + const stateWithColumnOrder = (columnOrder: string[]) => { + return { + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder, + columns: { + ...testState.layers.first.columns, + }, + }, + }, + }; + }; + + // first element to last + onDrop({ + ...defaultReorderDropParams, + target: { + ...defaultReorderDropParams.target, + columnId: 'col3', + }, + }); + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col2', 'col3', 'col1'])); + + // last element to first + onDrop({ + ...defaultReorderDropParams, + target: { + ...defaultReorderDropParams.target, + columnId: 'col1', + }, + source: { + humanData: { label: 'Label1' }, + columnId: 'col3', + groupId: 'a', + layerId: 'first', + id: 'col3', + }, + }); + expect(setState).toBeCalledTimes(2); + expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col3', 'col1', 'col2'])); + + // middle column to first + onDrop({ + ...defaultReorderDropParams, + target: { + ...defaultReorderDropParams.target, + columnId: 'col1', + }, + source: { + humanData: { label: 'Label1' }, + columnId: 'col2', + groupId: 'a', + layerId: 'first', + id: 'col2', + }, + }); + expect(setState).toBeCalledTimes(3); + expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col2', 'col1', 'col3'])); + + // middle column to last + onDrop({ + ...defaultReorderDropParams, + target: { + ...defaultReorderDropParams.target, + columnId: 'col3', + }, + source: { + humanData: { label: 'Label1' }, + columnId: 'col2', + groupId: 'a', + layerId: 'first', + id: 'col2', + }, + }); + expect(setState).toBeCalledTimes(4); + expect(setState).toHaveBeenCalledWith(stateWithColumnOrder(['col1', 'col3', 'col2'])); + }); + + it('updates the column id when moving an operation to an empty dimension', () => { + onDrop({ + ...defaultProps, + source: mockedDndOperations.metric, + target: { + ...defaultProps.target, + columnId: 'col2', + }, + dropType: 'move_compatible', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: { + ...state.layers.first, + columnOrder: ['col2'], + columns: { + col2: state.layers.first.columns.col1, + }, + }, + }, + }); + }); + + it('replaces an operation when moving to a populated dimension', () => { + const testState = { ...state }; + testState.layers.first = { + indexPatternId: 'first', + columnOrder: ['col1', 'col2', 'col3'], + columns: { + col1: testState.layers.first.columns.col1, + col2: mockedColumns.terms, + col3: mockedColumns.count, + }, + }; + + onDrop({ + ...defaultProps, + source: mockedDndOperations.bucket, + state: testState, + dropType: 'replace_compatible', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + incompleteColumns: {}, + columnOrder: ['col1', 'col3'], + columns: { + col1: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + }, + }, + }, + }); + }); + + it('when combine compatible columns should append dropped column fields into the target one', () => { + state = getStateWithMultiFieldColumn(state); + state.layers.first.columns = { + ...state.layers.first.columns, + col2: mockedColumns.terms, + }; + onDrop({ + ...defaultProps, + state, + source: { + columnId: 'col2', + groupId: 'a', + layerId: 'first', + id: 'col2', + humanData: { label: 'Label' }, + }, + dropType: 'combine_compatible', + target: { + ...defaultProps.target, + columnId: 'col1', + groupId: 'a', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: expect.objectContaining({ + columns: expect.objectContaining({ + col1: expect.objectContaining({ + dataType: 'string', + sourceField: 'dest', + params: expect.objectContaining({ secondaryFields: ['src'] }), + }), + }), + }), + }, + }); + }); + + describe('dimension group aware ordering and copying', () => { + let testState: IndexPatternPrivateState; + beforeEach(() => { + testState = { ...state }; + testState.layers.first = { ...mockedLayers.multipleColumnsLayer() }; + }); + + it('respects groups on moving operations between compatible groups', () => { + // config: + // a: + // b: col1, col2, col3 + // c: col4 + // dragging col2 into newCol in group a + onDrop({ + ...defaultProps, + target: { + ...defaultProps.target, + columnId: 'newCol', + groupId: 'a', + }, + source: mockedDndOperations.bucket, + state: testState, + dimensionGroups, + dropType: 'move_compatible', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + incompleteColumns: {}, + columnOrder: ['newCol', 'col1', 'col3', 'col4'], + columns: { + newCol: testState.layers.first.columns.col2, + col1: testState.layers.first.columns.col1, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + }, + }, + }); + }); + + it('respects groups on duplicating operations between compatible groups', () => { + // config: + // a: + // b: col1, col2, col3 + // c: col4 + // dragging col2 into newCol in group a + onDrop({ + ...defaultProps, + target: { + ...defaultProps.target, + columnId: 'newCol', + groupId: 'a', + }, + source: mockedDndOperations.bucket, + state: testState, + dimensionGroups, + dropType: 'duplicate_compatible', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['newCol', 'col1', 'col2', 'col3', 'col4'], + columns: { + newCol: testState.layers.first.columns.col2, + col1: testState.layers.first.columns.col1, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + }, + }, + }); + }); + + it('respects groups on moving operations between compatible groups with overwrite', () => { + // config: + // a: col1, + // b: col2, col3 + // c: col4 + // dragging col3 onto col1 in group a + onDrop({ + ...defaultProps, + target: { + ...defaultProps.target, + columnId: 'col1', + groupId: 'a', + }, + source: mockedDndOperations.bucket2, + state: testState, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + dropType: 'move_compatible', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + incompleteColumns: {}, + columnOrder: ['col1', 'col2', 'col4'], + columns: { + col1: testState.layers.first.columns.col3, + col2: testState.layers.first.columns.col2, + col4: testState.layers.first.columns.col4, + }, + }, + }, + }); + }); + + it('respects groups on moving operations if some columns are not listed in groups', () => { + // config: + // a: col1, + // b: col2, col3 + // c: col4 + // col5, col6 not in visualization groups + // dragging col3 onto col1 in group a + onDrop({ + ...defaultProps, + source: mockedDndOperations.bucket2, + target: { + ...defaultProps.target, + columnId: 'col1', + groupId: 'a', + }, + state: { + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'col2', 'col3', 'col4', 'col5', 'col6'], + columns: { + ...testState.layers.first.columns, + col5: { + dataType: 'number', + operationType: 'count', + label: '', + isBucketed: false, + sourceField: '___records___', + customLabel: true, + }, + col6: { + dataType: 'number', + operationType: 'count', + label: '', + isBucketed: false, + sourceField: '___records___', + customLabel: true, + }, + }, + }, + }, + }, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + dropType: 'move_compatible', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + incompleteColumns: {}, + columnOrder: ['col1', 'col2', 'col4', 'col5', 'col6'], + columns: { + col1: testState.layers.first.columns.col3, + col2: testState.layers.first.columns.col2, + col4: testState.layers.first.columns.col4, + col5: expect.objectContaining({ + dataType: 'number', + operationType: 'count', + label: '', + isBucketed: false, + sourceField: '___records___', + }), + col6: expect.objectContaining({ + dataType: 'number', + operationType: 'count', + label: '', + isBucketed: false, + sourceField: '___records___', + }), + }, + }, + }, + }); + }); + + it('respects groups on duplicating operations between compatible groups with overwrite', () => { + // config: + // a: col1, + // b: col2, col3 + // c: col4 + // dragging col3 onto col1 in group a + + onDrop({ + ...defaultProps, + source: mockedDndOperations.bucket2, + state: testState, + target: { + ...defaultProps.target, + columnId: 'col1', + groupId: 'a', + }, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + dropType: 'duplicate_compatible', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'col2', 'col3', 'col4'], + columns: { + col1: testState.layers.first.columns.col3, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + }, + }, + }); + }); + + it('moves newly created dimension to the bottom of the current group', () => { + // config: + // a: col1 + // b: col2, col3 + // c: col4 + // dragging col1 into newCol in group b + onDrop({ + ...defaultProps, + dropType: 'move_compatible', + source: mockedDndOperations.metric, + state: testState, + target: { + ...defaultProps.target, + columnId: 'newCol', + groupId: 'b', + }, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + incompleteColumns: {}, + columnOrder: ['col2', 'col3', 'newCol', 'col4'], + columns: { + newCol: testState.layers.first.columns.col1, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + }, + }, + }); + }); + + it('copies column to the bottom of the current group', () => { + // config: + // a: col1 + // b: col2, col3 + // c: col4 + // copying col1 within group a + onDrop({ + ...defaultProps, + dropType: 'duplicate_compatible', + target: { + ...defaultProps.target, + columnId: 'newCol', + groupId: 'a', + }, + source: mockedDndOperations.metric, + state: testState, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'newCol', 'col2', 'col3', 'col4'], + columns: { + col1: testState.layers.first.columns.col1, + newCol: testState.layers.first.columns.col1, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + }, + }, + }); + }); + + it('appends the dropped column in the right place respecting custom nestingOrder', () => { + // config: + // a: + // b: col1, col2, col3 + // c: col4 + // dragging field into newCol in group a + + onDrop({ + ...defaultProps, + source: mockedDraggedField, + target: { + ...defaultProps.target, + columnId: 'newCol', + groupId: 'a', + filterOperations: (op: OperationMetadata) => op.dataType === 'number', + }, + dimensionGroups: [ + // a and b are ordered in reverse visually, but nesting order keeps them in place for column order + { ...dimensionGroups[1], nestingOrder: 1 }, + { ...dimensionGroups[0], nestingOrder: 0 }, + { ...dimensionGroups[2] }, + ], + dropType: 'field_add', + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...state, + layers: { + ...state.layers, + first: { + ...testState.layers.first, + columnOrder: ['newCol', 'col1', 'col2', 'col3', 'col4'], + columns: { + newCol: expect.objectContaining({ + dataType: 'number', + sourceField: mockedDraggedField.field.name, + }), + col1: testState.layers.first.columns.col1, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + incompleteColumns: {}, + }, + }, + }); + }); + + it('moves incompatible column to the bottom of the target group', () => { + // config: + // a: col1 + // b: col2, col3 + // c: col4 + // dragging col4 into newCol in group a + + onDrop({ + ...defaultProps, + dropType: 'move_incompatible', + source: mockedDndOperations.metricC, + state: testState, + target: { + ...defaultProps.target, + columnId: 'newCol', + groupId: 'a', + }, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'newCol', 'col2', 'col3'], + columns: { + col1: testState.layers.first.columns.col1, + newCol: expect.objectContaining({ + sourceField: (testState.layers.first.columns.col4 as MedianIndexPatternColumn) + .sourceField, + }), + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + }, + incompleteColumns: {}, + }, + }, + }); + }); + + it('copies incompatible column to the bottom of the target group', () => { + // config: + // a: col1 + // b: col2, col3 + // c: col4 + // dragging col4 into newCol in group a + + onDrop({ + ...defaultProps, + dropType: 'duplicate_incompatible', + source: mockedDndOperations.metricC, + state: testState, + target: { + ...defaultProps.target, + columnId: 'newCol', + groupId: 'a', + }, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'newCol', 'col2', 'col3', 'col4'], + columns: { + col1: testState.layers.first.columns.col1, + newCol: expect.objectContaining({ + sourceField: (testState.layers.first.columns.col4 as MedianIndexPatternColumn) + .sourceField, + }), + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col4, + }, + incompleteColumns: {}, + }, + }, + }); + }); + + it('moves incompatible column with overwrite keeping order of target column', () => { + // config: + // a: col1 + // b: col2, col3 + // c: col4 + // dragging col4 into col2 in group b + + onDrop({ + ...defaultProps, + dropType: 'move_incompatible', + source: mockedDndOperations.metricC, + state: testState, + target: { + ...defaultProps.target, + columnId: 'col2', + groupId: 'b', + }, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'col2', 'col3'], + columns: { + col1: testState.layers.first.columns.col1, + col2: { + isBucketed: true, + label: 'Top 10 values of bytes', + operationType: 'terms', + sourceField: 'bytes', + dataType: 'number', + params: { + orderBy: { + type: 'alphabetical', + }, + orderDirection: 'desc', + size: 10, + parentFormat: { id: 'terms' }, + }, + }, + col3: testState.layers.first.columns.col3, + }, + incompleteColumns: {}, + }, + }, + }); + }); + + it('when swapping compatibly, columns carry order', () => { + // config: + // a: col1 + // b: col2, col3 + // c: col4 + // dragging col4 into col1 + + onDrop({ + ...defaultProps, + target: { + ...defaultProps.target, + columnId: 'col1', + groupId: 'a', + }, + source: mockedDndOperations.metricC, + dropType: 'swap_compatible', + state: testState, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'col2', 'col3', 'col4'], + columns: { + col1: testState.layers.first.columns.col4, + col2: testState.layers.first.columns.col2, + col3: testState.layers.first.columns.col3, + col4: testState.layers.first.columns.col1, + }, + }, + }, + }); + }); + + it('when swapping incompatibly, newly created columns take order from the columns they replace', () => { + // config: + // a: col1 + // b: col2, col3 + // c: col4 + // dragging col4 into col2 + + onDrop({ + ...defaultProps, + target: { + ...defaultProps.target, + columnId: 'col2', + groupId: 'b', + }, + dropType: 'swap_incompatible', + source: mockedDndOperations.metricC, + state: testState, + dimensionGroups: [ + { ...dimensionGroups[0], accessors: [{ columnId: 'col1' }] }, + { ...dimensionGroups[1], accessors: [{ columnId: 'col2' }, { columnId: 'col3' }] }, + { ...dimensionGroups[2] }, + ], + }); + + expect(setState).toBeCalledTimes(1); + expect(setState).toHaveBeenCalledWith({ + ...testState, + layers: { + ...testState.layers, + first: { + ...testState.layers.first, + columnOrder: ['col1', 'col2', 'col3', 'col4'], + columns: { + col1: testState.layers.first.columns.col1, + col2: { + isBucketed: true, + label: 'Top 10 values of bytes', + operationType: 'terms', + sourceField: 'bytes', + dataType: 'number', + params: { + orderBy: { + type: 'alphabetical', + }, + orderDirection: 'desc', + parentFormat: { id: 'terms' }, + size: 10, + }, + }, + col3: testState.layers.first.columns.col3, + col4: { + isBucketed: false, + label: 'Unique count of src', + filter: undefined, + operationType: 'unique_count', + sourceField: 'src', + timeShift: undefined, + dataType: 'number', + params: { + emptyAsNull: true, + }, + scale: 'ratio', + }, + }, + incompleteColumns: {}, + }, + }, + }); + }); + }); + + describe('onDrop between layers', () => { + const defaultDimensionGroups = [ + { + groupId: 'x', + groupLabel: 'Horizontal axis', + accessors: [], + supportsMoreColumns: true, + dataTestSubj: 'lnsXY_xDimensionPanel', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + { + groupId: 'y', + groupLabel: 'Vertical axis', + accessors: [], + supportsMoreColumns: true, + required: true, + dataTestSubj: 'lnsXY_yDimensionPanel', + enableDimensionEditor: true, + filterOperations: (op: OperationMetadata) => !op.isBucketed, + }, + { + groupId: 'breakdown', + groupLabel: 'Break down by', + accessors: [], + supportsMoreColumns: true, + dataTestSubj: 'lnsXY_splitDimensionPanel', + required: false, + enableDimensionEditor: true, + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + ]; + describe('simple operations', () => { + let props: DatasourceDimensionDropHandlerProps; + beforeEach(() => { + setState = jest.fn(); + + props = { + state: { + indexPatternRefs: [], + indexPatterns: mockDataViews(), + currentIndexPatternId: 'first', + isFirstExistenceFetch: false, + existingFields: { + first: { + timestamp: true, + bytes: true, + memory: true, + source: true, + }, + }, + layers: { + first: mockedLayers.singleColumnLayer(), + second: mockedLayers.multipleColumnsLayer('col2', 'col3', 'col4', 'col5'), + }, + }, + setState: jest.fn(), + source: { + id: 'col1', + humanData: { label: '2' }, + columnId: 'col1', + groupId: 'x', + layerId: 'first', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + target: { + filterOperations: (op: OperationMetadata) => op.isBucketed, + columnId: 'newCol', + groupId: 'x', + layerId: 'second', + }, + dimensionGroups: defaultDimensionGroups, + dropType: 'move_compatible', + }; + jest.clearAllMocks(); + }); + it('doesnt allow dropping for different data views', () => { + props.state.layers.second.indexPatternId = 'second'; + expect(onDrop(props)).toEqual(false); + expect(props.setState).not.toHaveBeenCalled(); + }); + it('move_compatible; allows dropping to the compatible group in different layer to empty column', () => { + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...mockedLayers.emptyLayer(), + incompleteColumns: {}, + }, + second: { + columnOrder: ['col2', 'col3', 'col4', 'newCol', 'col5'], + columns: { + ...props.state.layers.second.columns, + newCol: mockedColumns.dateHistogram, + }, + indexPatternId: 'first', + }, + }, + }); + }); + it('duplicate_compatible: allows dropping to the compatible group in different layer to empty column', () => { + expect(onDrop({ ...props, dropType: 'duplicate_compatible' })).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + second: { + columnOrder: ['col2', 'col3', 'col4', 'newCol', 'col5'], + columns: { + ...props.state.layers.second.columns, + newCol: mockedColumns.dateHistogram, + }, + indexPatternId: 'first', + }, + }, + }); + }); + it('swap_compatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + + target: { + ...props.target, + columnId: 'col4', + groupId: 'breakdown', + layerId: 'second', + }, + dropType: 'swap_compatible', + }; + + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...props.state.layers.first, + columns: { + col1: props.state.layers.second.columns.col4, + }, + }, + second: { + ...props.state.layers.second, + columns: { + ...props.state.layers.second.columns, + col4: props.state.layers.first.columns.col1, + }, + }, + }, + }); + }); + it('replace_compatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + target: { + ...props.target, + columnId: 'col4', + groupId: 'breakdown', + layerId: 'second', + }, + dropType: 'replace_compatible', + }; + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...mockedLayers.emptyLayer(), + incompleteColumns: {}, + }, + second: { + columnOrder: ['col2', 'col3', 'col4', 'col5'], + columns: { + ...props.state.layers.second.columns, + col4: mockedColumns.dateHistogram, + }, + indexPatternId: 'first', + }, + }, + }); + }); + it('replace_duplicate_compatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + target: { + ...props.target, + columnId: 'col4', + groupId: 'breakdown', + layerId: 'second', + }, + dropType: 'replace_duplicate_compatible', + }; + + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + second: { + columnOrder: ['col2', 'col3', 'col4', 'col5'], + columns: { + ...props.state.layers.second.columns, + col4: mockedColumns.dateHistogram, + }, + indexPatternId: 'first', + }, + }, + }); + }); + it('replace_duplicate_incompatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + target: { + ...props.target, + columnId: 'col5', + groupId: 'y', + layerId: 'second', + filterOperations: (op) => !op.isBucketed, + }, + dropType: 'replace_duplicate_incompatible', + }; + + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + second: { + columnOrder: ['col2', 'col3', 'col4', 'col5'], + columns: { + ...props.state.layers.second.columns, + col5: { + dataType: 'date', + isBucketed: false, + label: 'Minimum of timestampLabel', + operationType: 'min', + params: { + emptyAsNull: true, + }, + scale: 'ratio', + sourceField: 'timestamp', + }, + }, + incompleteColumns: {}, + indexPatternId: 'first', + }, + }, + }); + }); + it('replace_incompatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + target: { + ...props.target, + columnId: 'col5', + groupId: 'y', + layerId: 'second', + filterOperations: (op) => !op.isBucketed, + }, + dropType: 'replace_incompatible', + }; + + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...mockedLayers.emptyLayer(), + incompleteColumns: {}, + }, + second: { + columnOrder: ['col2', 'col3', 'col4', 'col5'], + columns: { + ...props.state.layers.second.columns, + col5: { + dataType: 'date', + isBucketed: false, + label: 'Minimum of timestampLabel', + operationType: 'min', + params: { + emptyAsNull: true, + }, + scale: 'ratio', + sourceField: 'timestamp', + }, + }, + incompleteColumns: {}, + indexPatternId: 'first', + }, + }, + }); + }); + it('move_incompatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + target: { + ...props.target, + columnId: 'newCol', + groupId: 'y', + layerId: 'second', + filterOperations: (op) => !op.isBucketed, + }, + dropType: 'move_incompatible', + }; + + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...mockedLayers.emptyLayer(), + incompleteColumns: {}, + }, + second: { + columnOrder: ['col2', 'col3', 'col4', 'col5', 'newCol'], + columns: { + ...props.state.layers.second.columns, + newCol: { + dataType: 'date', + isBucketed: false, + label: 'Minimum of timestampLabel', + operationType: 'min', + params: { + emptyAsNull: true, + }, + scale: 'ratio', + sourceField: 'timestamp', + }, + }, + incompleteColumns: {}, + indexPatternId: 'first', + }, + }, + }); + }); + it('duplicate_incompatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + target: { + ...props.target, + columnId: 'newCol', + groupId: 'y', + layerId: 'second', + filterOperations: (op) => !op.isBucketed, + }, + dropType: 'duplicate_incompatible', + }; + + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + second: { + columnOrder: ['col2', 'col3', 'col4', 'col5', 'newCol'], + columns: { + ...props.state.layers.second.columns, + newCol: { + dataType: 'date', + isBucketed: false, + label: 'Minimum of timestampLabel', + operationType: 'min', + params: { + emptyAsNull: true, + }, + scale: 'ratio', + sourceField: 'timestamp', + }, + }, + incompleteColumns: {}, + indexPatternId: 'first', + }, + }, + }); + }); + it('swap_incompatible: allows dropping to compatible group to replace an existing column', () => { + props = { + ...props, + target: { + ...props.target, + columnId: 'col5', + groupId: 'y', + layerId: 'second', + filterOperations: (op) => !op.isBucketed, + }, + dropType: 'swap_incompatible', + }; + + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...props.state.layers.first, + columns: { + ...props.state.layers.first.columns, + col1: { + dataType: 'number', + isBucketed: true, + label: 'bytes', + operationType: 'range', + params: { + includeEmptyRows: true, + maxBars: 'auto', + ranges: [ + { + from: 0, + label: '', + to: 1000, + }, + ], + type: 'histogram', + }, + scale: 'interval', + sourceField: 'bytes', + }, + }, + }, + second: { + columnOrder: ['col2', 'col3', 'col4', 'col5'], + columns: { + ...props.state.layers.second.columns, + col5: { + dataType: 'date', + isBucketed: false, + label: 'Minimum of timestampLabel', + operationType: 'min', + params: { + emptyAsNull: true, + }, + scale: 'ratio', + sourceField: 'timestamp', + }, + }, + incompleteColumns: {}, + indexPatternId: 'first', + }, + }, + }); + }); + it('combine_compatible: allows dropping to combine to multiterms', () => { + onDrop({ + ...props, + state: { + ...props.state, + layers: { + ...props.state.layers, + first: { + ...props.state.layers.first, + columns: { + terms1: mockedColumns.terms, + }, + }, + }, + }, + source: { + columnId: 'terms1', + groupId: 'a', + layerId: 'first', + id: 'terms1', + humanData: { label: 'Label' }, + }, + dropType: 'combine_compatible', + target: { + ...props.target, + columnId: 'col4', + groupId: 'a', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + }); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { ...mockedLayers.emptyLayer(), incompleteColumns: {} }, + second: { + ...props.state.layers.second, + incompleteColumns: {}, + columns: { + ...props.state.layers.second.columns, + col4: { + dataType: 'string', + isBucketed: true, + label: 'Top values of dest + 1 other', + operationType: 'terms', + params: { + orderBy: { + type: 'alphabetical', + }, + orderDirection: 'desc', + parentFormat: { + id: 'multi_terms', + }, + secondaryFields: ['src'], + size: 10, + }, + sourceField: 'dest', + }, + }, + }, + }, + }); + }); + it('combine_incompatible: allows dropping to combine to multiterms', () => { + onDrop({ + ...props, + state: { + ...props.state, + layers: { + ...props.state.layers, + first: { + ...props.state.layers.first, + columns: { + median: mockedColumns.median, + }, + }, + }, + }, + source: { + columnId: 'median', + groupId: 'x', + layerId: 'first', + id: 'median', + humanData: { label: 'Label' }, + filterOperations: (op: OperationMetadata) => !op.isBucketed, + }, + dropType: 'combine_incompatible', + target: { + ...props.target, + columnId: 'col4', + groupId: 'breakdown', + filterOperations: (op: OperationMetadata) => op.isBucketed, + }, + }); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { ...mockedLayers.emptyLayer(), incompleteColumns: {} }, + second: { + ...props.state.layers.second, + incompleteColumns: {}, + columns: { + ...props.state.layers.second.columns, + col4: { + dataType: 'string', + isBucketed: true, + label: 'Top values of dest + 1 other', + operationType: 'terms', + params: { + orderBy: { + type: 'alphabetical', + }, + orderDirection: 'desc', + parentFormat: { + id: 'multi_terms', + }, + secondaryFields: ['bytes'], + size: 10, + }, + sourceField: 'dest', + }, + }, + }, + }, + }); + }); + }); + describe('references', () => { + let props: DatasourceDimensionDropHandlerProps; + beforeEach(() => { + props = { + dimensionGroups: defaultDimensionGroups, + setState: jest.fn(), + dropType: 'move_compatible', + + state: { + layers: { + first: { + indexPatternId: 'first', + columns: { + firstColumnX0: { + label: 'Part of count()', + dataType: 'number', + operationType: 'count', + isBucketed: false, + scale: 'ratio', + sourceField: '___records___', + customLabel: true, + }, + firstColumn: { + label: 'count()', + dataType: 'number', + operationType: 'formula', + isBucketed: false, + scale: 'ratio', + params: { formula: 'count()' }, + references: ['firstColumnX0'], + } as FormulaIndexPatternColumn, + }, + columnOrder: ['firstColumn', 'firstColumnX0'], + incompleteColumns: {}, + }, + second: { + indexPatternId: 'first', + columns: { + secondX0: { + label: 'Part of count()', + dataType: 'number', + operationType: 'count', + isBucketed: false, + scale: 'ratio', + sourceField: '___records___', + customLabel: true, + }, + second: { + label: 'count()', + dataType: 'number', + operationType: 'formula', + isBucketed: false, + scale: 'ratio', + params: { formula: 'count()' }, + references: ['secondX0'], + } as FormulaIndexPatternColumn, + }, + columnOrder: ['second', 'secondX0'], + }, + }, + indexPatternRefs: [], + indexPatterns: mockDataViews(), + currentIndexPatternId: 'first', + isFirstExistenceFetch: false, + existingFields: { + first: { + timestamp: true, + bytes: true, + memory: true, + source: true, + }, + }, + }, + source: { + columnId: 'firstColumn', + groupId: 'y', + layerId: 'first', + id: 'firstColumn', + humanData: { + label: 'count()', + }, + }, + target: { + columnId: 'newColumn', + groupId: 'y', + layerId: 'second', + filterOperations: (op) => !op.isBucketed, + }, + }; + + jest.clearAllMocks(); + }); + + it('move_compatible; allows dropping to the compatible group in different layer to empty column', () => { + expect(onDrop(props)).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...mockedLayers.emptyLayer(), + incompleteColumns: {}, + }, + second: { + columnOrder: ['second', 'secondX0', 'newColumnX0', 'newColumn'], + columns: { + ...props.state.layers.second.columns, + newColumn: { + dataType: 'number', + isBucketed: false, + label: 'count()', + operationType: 'formula', + params: { + formula: 'count()', + isFormulaBroken: false, + }, + references: ['newColumnX0'], + scale: 'ratio', + }, + newColumnX0: { + customLabel: true, + dataType: 'number', + filter: undefined, + isBucketed: false, + label: 'Part of count()', + operationType: 'count', + params: { + emptyAsNull: false, + }, + scale: 'ratio', + sourceField: '___records___', + timeScale: undefined, + timeShift: undefined, + }, + }, + indexPatternId: 'first', + }, + }, + }); + }); + it('replace_compatible: allows dropping to compatible group to replace an existing column', () => { + expect( + onDrop({ + ...props, + target: { + columnId: 'second', + groupId: 'y', + layerId: 'second', + filterOperations: (op) => !op.isBucketed, + }, + }) + ).toEqual(true); + expect(props.setState).toBeCalledTimes(1); + expect(props.setState).toHaveBeenCalledWith({ + ...props.state, + layers: { + ...props.state.layers, + first: { + ...mockedLayers.emptyLayer(), + incompleteColumns: {}, + }, + second: { + columnOrder: ['second', 'secondX0'], + columns: { + ...props.state.layers.second.columns, + second: { + dataType: 'number', + isBucketed: false, + label: 'count()', + operationType: 'formula', + params: { + formula: 'count()', + isFormulaBroken: false, + }, + references: ['secondX0'], + scale: 'ratio', + }, + secondX0: { + customLabel: true, + dataType: 'number', + filter: undefined, + isBucketed: false, + label: 'Part of count()', + operationType: 'count', + params: { + emptyAsNull: false, + }, + scale: 'ratio', + sourceField: '___records___', + timeScale: undefined, + timeShift: undefined, + }, + }, + indexPatternId: 'first', + }, + }, + }); + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts index c9e806050caad..3d57e21e73387 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/droppable/on_drop_handler.ts @@ -4,7 +4,14 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { DatasourceDimensionDropHandlerProps, DraggedOperation } from '../../../types'; +import { + DatasourceDimensionDropHandlerProps, + DragDropOperation, + DropType, + isOperation, + StateSetter, + VisualizationDimensionGroupConfig, +} from '../../../types'; import { insertOrReplaceColumn, deleteColumn, @@ -14,160 +21,125 @@ import { hasOperationSupportForMultipleFields, getOperationHelperForMultipleFields, replaceColumn, + deleteColumnInLayers, } from '../../operations'; -import { mergeLayer } from '../../state_helpers'; +import { mergeLayer, mergeLayers } from '../../state_helpers'; import { isDraggedField } from '../../pure_utils'; import { getNewOperation, getField } from './get_drop_props'; -import { IndexPatternPrivateState, DraggedField } from '../../types'; +import { IndexPatternPrivateState, DraggedField, DataViewDragDropOperation } from '../../types'; import { trackUiEvent } from '../../../lens_ui_telemetry'; -type DropHandlerProps = DatasourceDimensionDropHandlerProps & { - droppedItem: T; -}; +interface DropHandlerProps { + state: IndexPatternPrivateState; + setState: StateSetter< + IndexPatternPrivateState, + { + isDimensionComplete?: boolean; + forceRender?: boolean; + } + >; + dimensionGroups: VisualizationDimensionGroupConfig[]; + dropType?: DropType; + source: T; + target: DataViewDragDropOperation; +} export function onDrop(props: DatasourceDimensionDropHandlerProps) { - const { droppedItem, dropType } = props; - - if (dropType === 'field_add' || dropType === 'field_replace' || dropType === 'field_combine') { - return operationOnDropMap[dropType]({ - ...props, - droppedItem: droppedItem as DraggedField, - }); + const { target, source, dropType, state } = props; + + if (isDraggedField(source) && isFieldDropType(dropType)) { + return onFieldDrop( + { + ...props, + target: { + ...target, + dataView: state.indexPatterns[state.layers[target.layerId].indexPatternId], + }, + source, + }, + dropType === 'field_combine' + ); } - return operationOnDropMap[dropType]({ - ...props, - droppedItem: droppedItem as DraggedOperation, - }); -} - -const operationOnDropMap = { - field_add: onFieldDrop, - field_replace: onFieldDrop, - field_combine: (props: DropHandlerProps) => onFieldDrop(props, true), - - reorder: onReorder, - - move_compatible: (props: DropHandlerProps) => onMoveCompatible(props, true), - replace_compatible: (props: DropHandlerProps) => onMoveCompatible(props, true), - duplicate_compatible: onMoveCompatible, - replace_duplicate_compatible: onMoveCompatible, - move_incompatible: (props: DropHandlerProps) => onMoveIncompatible(props, true), - replace_incompatible: (props: DropHandlerProps) => - onMoveIncompatible(props, true), - duplicate_incompatible: onMoveIncompatible, - replace_duplicate_incompatible: onMoveIncompatible, - - swap_compatible: onSwapCompatible, - swap_incompatible: onSwapIncompatible, - combine_compatible: onCombineCompatible, - combine_incompatible: onCombineCompatible, -}; - -function onCombineCompatible({ - columnId, - setState, - state, - layerId, - droppedItem, - dimensionGroups, - groupId, -}: DropHandlerProps) { - const layer = state.layers[layerId]; - const sourceId = droppedItem.columnId; - const targetId = columnId; - const indexPattern = state.indexPatterns[layer.indexPatternId]; - const sourceColumn = layer.columns[sourceId]; - const targetColumn = layer.columns[targetId]; - - // extract the field from the source column - const sourceField = getField(sourceColumn, indexPattern); - const targetField = getField(targetColumn, indexPattern); - if (!sourceField || !targetField) { + if (!isOperation(source)) { + return false; + } + const sourceDataView = state.indexPatterns[state.layers[source.layerId].indexPatternId]; + const targetDataView = state.indexPatterns[state.layers[target.layerId].indexPatternId]; + if (sourceDataView !== targetDataView) { return false; } - // pass it to the target column and delete the source column - const initialParams = { - params: - getOperationHelperForMultipleFields(targetColumn.operationType)?.({ - targetColumn, - sourceColumn, - indexPattern, - }) ?? {}, - }; - - const modifiedLayer = replaceColumn({ - layer, - columnId, - indexPattern, - op: targetColumn.operationType, - field: targetField, - visualizationGroups: dimensionGroups, - targetGroup: groupId, - initialParams, - shouldCombineField: true, - }); - const newLayer = deleteColumn({ - layer: modifiedLayer, - columnId: sourceId, - indexPattern, - }); - // Time to replace - setState( - mergeLayer({ - state, - layerId, - newLayer, - }) - ); + const operationProps = { + ...props, + target: { + ...target, + dataView: targetDataView, + }, + source: { + ...source, + dataView: sourceDataView, + }, + }; + if (dropType === 'reorder') { + return onReorder(operationProps); + } - return { deleted: sourceId }; + if (['move_compatible', 'replace_compatible'].includes(dropType)) { + return onMoveCompatible(operationProps, true); + } + if (['duplicate_compatible', 'replace_duplicate_compatible'].includes(dropType)) { + return onMoveCompatible(operationProps); + } + if (['move_incompatible', 'replace_incompatible'].includes(dropType)) { + return onMoveIncompatible(operationProps, true); + } + if (['duplicate_incompatible', 'replace_duplicate_incompatible'].includes(dropType)) { + return onMoveIncompatible(operationProps); + } + if (dropType === 'swap_compatible') { + return onSwapCompatible(operationProps); + } + if (dropType === 'swap_incompatible') { + return onSwapIncompatible(operationProps); + } + if (['combine_incompatible', 'combine_compatible'].includes(dropType)) { + return onCombine(operationProps); + } } +const isFieldDropType = (dropType: DropType) => + ['field_add', 'field_replace', 'field_combine'].includes(dropType); + function onFieldDrop(props: DropHandlerProps, shouldAddField?: boolean) { - const { - columnId, - setState, - state, - layerId, - droppedItem, - filterOperations, - groupId, - dimensionGroups, - } = props; + const { setState, state, source, target, dimensionGroups } = props; const prioritizedOperation = dimensionGroups.find( - (g) => g.groupId === groupId + (g) => g.groupId === target.groupId )?.prioritizedOperation; - const layer = state.layers[layerId]; + const layer = state.layers[target.layerId]; const indexPattern = state.indexPatterns[layer.indexPatternId]; - const targetColumn = layer.columns[columnId]; + const targetColumn = layer.columns[target.columnId]; const newOperation = shouldAddField ? targetColumn.operationType - : getNewOperation(droppedItem.field, filterOperations, targetColumn, prioritizedOperation); + : getNewOperation(source.field, target.filterOperations, targetColumn, prioritizedOperation); if ( - !isDraggedField(droppedItem) || + !isDraggedField(source) || !newOperation || (shouldAddField && - !hasOperationSupportForMultipleFields( - indexPattern, - targetColumn, - undefined, - droppedItem.field - )) + !hasOperationSupportForMultipleFields(indexPattern, targetColumn, undefined, source.field)) ) { return false; } - const field = shouldAddField ? getField(targetColumn, indexPattern) : droppedItem.field; + const field = shouldAddField ? getField(targetColumn, indexPattern) : source.field; const initialParams = shouldAddField ? { params: getOperationHelperForMultipleFields(targetColumn.operationType)?.({ targetColumn, - field: droppedItem.field, + field: source.field, indexPattern, }) || {}, } @@ -175,12 +147,12 @@ function onFieldDrop(props: DropHandlerProps, shouldAddField?: boo const newLayer = insertOrReplaceColumn({ layer, - columnId, + columnId: target.columnId, indexPattern, op: newOperation, field, visualizationGroups: dimensionGroups, - targetGroup: groupId, + targetGroup: target.groupId, shouldCombineField: shouldAddField, initialParams, }); @@ -188,82 +160,76 @@ function onFieldDrop(props: DropHandlerProps, shouldAddField?: boo trackUiEvent('drop_onto_dimension'); const hasData = Object.values(state.layers).some(({ columns }) => columns.length); trackUiEvent(hasData ? 'drop_non_empty' : 'drop_empty'); - setState(mergeLayer({ state, layerId, newLayer })); + setState(mergeLayer({ state, layerId: target.layerId, newLayer })); return true; } function onMoveCompatible( - { - columnId, - setState, - state, - layerId, - droppedItem, - dimensionGroups, - groupId, - }: DropHandlerProps, + { setState, state, source, target, dimensionGroups }: DropHandlerProps, shouldDeleteSource?: boolean ) { - const layer = state.layers[layerId]; - const sourceColumn = layer.columns[droppedItem.columnId]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; - - const modifiedLayer = copyColumn({ - layer, - targetId: columnId, - sourceColumnId: droppedItem.columnId, - sourceColumn, + const modifiedLayers = copyColumn({ + layers: state.layers, + target, + source, shouldDeleteSource, - indexPattern, }); - const updatedColumnOrder = reorderByGroups( - dimensionGroups, - groupId, - getColumnOrder(modifiedLayer), - columnId - ); + if (target.layerId === source.layerId) { + const updatedColumnOrder = reorderByGroups( + dimensionGroups, + getColumnOrder(modifiedLayers[target.layerId]), + target.groupId, + target.columnId + ); + + const newLayer = { + ...modifiedLayers[target.layerId], + columnOrder: updatedColumnOrder, + columns: modifiedLayers[target.layerId].columns, + }; + + // Time to replace + setState( + mergeLayer({ + state, + layerId: target.layerId, + newLayer, + }) + ); + return true; + } else { + setState(mergeLayers({ state, newLayers: modifiedLayers })); - // Time to replace - setState( - mergeLayer({ - state, - layerId, - newLayer: { - columnOrder: updatedColumnOrder, - columns: modifiedLayer.columns, - }, - }) - ); - return shouldDeleteSource ? { deleted: droppedItem.columnId } : true; + return true; + } } function onReorder({ - columnId, setState, state, - layerId, - droppedItem, -}: DropHandlerProps) { - function reorderElements(items: string[], dest: string, src: string) { - const result = items.filter((c) => c !== src); - const targetIndex = items.findIndex((c) => c === src); - const sourceIndex = items.findIndex((c) => c === dest); - - const targetPosition = result.indexOf(dest); - result.splice(targetIndex < sourceIndex ? targetPosition + 1 : targetPosition, 0, src); + source, + target, +}: DropHandlerProps) { + function reorderElements(items: string[], targetId: string, sourceId: string) { + const result = items.filter((c) => c !== sourceId); + const targetIndex = items.findIndex((c) => c === sourceId); + const sourceIndex = items.findIndex((c) => c === targetId); + + const targetPosition = result.indexOf(targetId); + result.splice(targetIndex < sourceIndex ? targetPosition + 1 : targetPosition, 0, sourceId); return result; } setState( mergeLayer({ state, - layerId, + layerId: target.layerId, newLayer: { columnOrder: reorderElements( - state.layers[layerId].columnOrder, - columnId, - droppedItem.columnId + state.layers[target.layerId].columnOrder, + target.columnId, + source.columnId ), }, }) @@ -272,124 +238,158 @@ function onReorder({ } function onMoveIncompatible( - { - columnId, - setState, - state, - layerId, - droppedItem, - filterOperations, - dimensionGroups, - groupId, - }: DropHandlerProps, + { setState, state, source, dimensionGroups, target }: DropHandlerProps, shouldDeleteSource?: boolean ) { - const layer = state.layers[layerId]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; - const sourceColumn = layer.columns[droppedItem.columnId]; - const targetColumn = layer.columns[columnId] || null; - + const targetLayer = state.layers[target.layerId]; + const targetColumn = targetLayer.columns[target.columnId] || null; + const sourceLayer = state.layers[source.layerId]; + const indexPattern = state.indexPatterns[sourceLayer.indexPatternId]; + const sourceColumn = sourceLayer.columns[source.columnId]; const sourceField = getField(sourceColumn, indexPattern); - const newOperation = getNewOperation(sourceField, filterOperations, targetColumn); + const newOperation = getNewOperation(sourceField, target.filterOperations, targetColumn); if (!newOperation) { return false; } - const modifiedLayer = shouldDeleteSource + const outputSourceLayer = shouldDeleteSource ? deleteColumn({ - layer, - columnId: droppedItem.columnId, + layer: sourceLayer, + columnId: source.columnId, indexPattern, }) - : layer; + : sourceLayer; - const newLayer = insertOrReplaceColumn({ - layer: modifiedLayer, - columnId, - indexPattern, - op: newOperation, - field: sourceField, - visualizationGroups: dimensionGroups, - targetGroup: groupId, - shouldResetLabel: true, - }); + if (target.layerId === source.layerId) { + const newLayer = insertOrReplaceColumn({ + layer: outputSourceLayer, + columnId: target.columnId, + indexPattern, + op: newOperation, + field: sourceField, + visualizationGroups: dimensionGroups, + targetGroup: target.groupId, + shouldResetLabel: true, + }); - trackUiEvent('drop_onto_dimension'); - setState( - mergeLayer({ - state, - layerId, - newLayer, - }) - ); - return shouldDeleteSource ? { deleted: droppedItem.columnId } : true; + trackUiEvent('drop_onto_dimension'); + setState( + mergeLayer({ + state, + layerId: target.layerId, + newLayer, + }) + ); + return true; + } else { + const outputTargetLayer = insertOrReplaceColumn({ + layer: targetLayer, + columnId: target.columnId, + indexPattern, + op: newOperation, + field: sourceField, + visualizationGroups: dimensionGroups, + targetGroup: target.groupId, + shouldResetLabel: true, + }); + + trackUiEvent('drop_onto_dimension'); + setState( + mergeLayers({ + state, + newLayers: { + [source.layerId]: outputSourceLayer, + [target.layerId]: outputTargetLayer, + }, + }) + ); + return true; + } } function onSwapIncompatible({ - columnId, setState, state, - layerId, - droppedItem, - filterOperations, + source, dimensionGroups, - groupId, -}: DropHandlerProps) { - const layer = state.layers[layerId]; - const indexPattern = state.indexPatterns[layer.indexPatternId]; - const sourceColumn = layer.columns[droppedItem.columnId]; - const targetColumn = layer.columns[columnId]; + target, +}: DropHandlerProps) { + const targetLayer = state.layers[target.layerId]; + const sourceLayer = state.layers[source.layerId]; + const indexPattern = state.indexPatterns[targetLayer.indexPatternId]; + const sourceColumn = sourceLayer.columns[source.columnId]; + const targetColumn = targetLayer.columns[target.columnId]; const sourceField = getField(sourceColumn, indexPattern); const targetField = getField(targetColumn, indexPattern); - const newOperationForSource = getNewOperation(sourceField, filterOperations, targetColumn); - const newOperationForTarget = getNewOperation( - targetField, - droppedItem.filterOperations, - sourceColumn - ); + const newOperationForSource = getNewOperation(sourceField, target.filterOperations, targetColumn); + const newOperationForTarget = getNewOperation(targetField, source.filterOperations, sourceColumn); if (!newOperationForSource || !newOperationForTarget) { return false; } - const newLayer = insertOrReplaceColumn({ - layer: insertOrReplaceColumn({ - layer, - columnId, - targetGroup: groupId, - indexPattern, - op: newOperationForSource, - field: sourceField, - visualizationGroups: dimensionGroups, - shouldResetLabel: true, - }), - columnId: droppedItem.columnId, + const outputTargetLayer = insertOrReplaceColumn({ + layer: targetLayer, + columnId: target.columnId, + targetGroup: target.groupId, indexPattern, - op: newOperationForTarget, - field: targetField, + op: newOperationForSource, + field: sourceField, visualizationGroups: dimensionGroups, - targetGroup: droppedItem.groupId, shouldResetLabel: true, }); - trackUiEvent('drop_onto_dimension'); - setState( - mergeLayer({ - state, - layerId, - newLayer, - }) - ); - return true; + if (source.layerId === target.layerId) { + const newLayer = insertOrReplaceColumn({ + layer: outputTargetLayer, + columnId: source.columnId, + indexPattern, + op: newOperationForTarget, + field: targetField, + visualizationGroups: dimensionGroups, + targetGroup: source.groupId, + shouldResetLabel: true, + }); + + trackUiEvent('drop_onto_dimension'); + setState( + mergeLayer({ + state, + layerId: target.layerId, + newLayer, + }) + ); + return true; + } else { + const outputSourceLayer = insertOrReplaceColumn({ + layer: sourceLayer, + columnId: source.columnId, + indexPattern, + op: newOperationForTarget, + field: targetField, + visualizationGroups: dimensionGroups, + targetGroup: source.groupId, + shouldResetLabel: true, + }); + + trackUiEvent('drop_onto_dimension'); + setState( + mergeLayers({ + state, + newLayers: { [source.layerId]: outputSourceLayer, [target.layerId]: outputTargetLayer }, + }) + ); + return true; + } } const swapColumnOrder = (columnOrder: string[], sourceId: string, targetId: string) => { - const newColumnOrder = [...columnOrder]; - const sourceIndex = newColumnOrder.findIndex((c) => c === sourceId); - const targetIndex = newColumnOrder.findIndex((c) => c === targetId); + const sourceIndex = columnOrder.findIndex((c) => c === sourceId); + const targetIndex = columnOrder.findIndex((c) => c === targetId); + const newColumnOrder = [...columnOrder]; newColumnOrder[sourceIndex] = targetId; newColumnOrder[targetIndex] = sourceId; @@ -397,38 +397,114 @@ const swapColumnOrder = (columnOrder: string[], sourceId: string, targetId: stri }; function onSwapCompatible({ - columnId, setState, state, - layerId, - droppedItem, + source, dimensionGroups, - groupId, -}: DropHandlerProps) { - const layer = state.layers[layerId]; - const sourceId = droppedItem.columnId; - const targetId = columnId; - - const sourceColumn = { ...layer.columns[sourceId] }; - const targetColumn = { ...layer.columns[targetId] }; - const newColumns = { ...layer.columns }; - newColumns[targetId] = sourceColumn; - newColumns[sourceId] = targetColumn; - - let updatedColumnOrder = swapColumnOrder(layer.columnOrder, sourceId, targetId); - updatedColumnOrder = reorderByGroups(dimensionGroups, groupId, updatedColumnOrder, columnId); - - // Time to replace - setState( - mergeLayer({ - state, - layerId, - newLayer: { - columnOrder: updatedColumnOrder, - columns: newColumns, - }, - }) - ); + target, +}: DropHandlerProps) { + if (target.layerId === source.layerId) { + const layer = state.layers[target.layerId]; + const newColumns = { + ...layer.columns, + [target.columnId]: { ...layer.columns[source.columnId] }, + [source.columnId]: { ...layer.columns[target.columnId] }, + }; + + let updatedColumnOrder = swapColumnOrder(layer.columnOrder, source.columnId, target.columnId); + updatedColumnOrder = reorderByGroups( + dimensionGroups, + updatedColumnOrder, + target.groupId, + target.columnId + ); + + setState( + mergeLayer({ + state, + layerId: target.layerId, + newLayer: { + columnOrder: updatedColumnOrder, + columns: newColumns, + }, + }) + ); + + return true; + } else { + const newTargetLayer = copyColumn({ + layers: state.layers, + target, + source, + shouldDeleteSource: true, + })[target.layerId]; + + const newSourceLayer = copyColumn({ + layers: state.layers, + target: source, + source: target, + shouldDeleteSource: true, + })[source.layerId]; + + setState( + mergeLayers({ + state, + newLayers: { + [source.layerId]: newSourceLayer, + [target.layerId]: newTargetLayer, + }, + }) + ); + + return true; + } +} + +function onCombine({ + state, + setState, + source, + target, + dimensionGroups, +}: DropHandlerProps) { + const targetLayer = state.layers[target.layerId]; + const targetColumn = targetLayer.columns[target.columnId]; + const targetField = getField(targetColumn, target.dataView); + const indexPattern = state.indexPatterns[targetLayer.indexPatternId]; + + const sourceLayer = state.layers[source.layerId]; + const sourceColumn = sourceLayer.columns[source.columnId]; + const sourceField = getField(sourceColumn, indexPattern); + // extract the field from the source column + if (!sourceField || !targetField) { + return false; + } + // pass it to the target column and delete the source column + const initialParams = { + params: + getOperationHelperForMultipleFields(targetColumn.operationType)?.({ + targetColumn, + sourceColumn, + indexPattern, + }) ?? {}, + }; + const outputTargetLayer = replaceColumn({ + layer: targetLayer, + columnId: target.columnId, + indexPattern, + op: targetColumn.operationType, + field: targetField, + visualizationGroups: dimensionGroups, + targetGroup: target.groupId, + initialParams, + shouldCombineField: true, + }); + + const newLayers = deleteColumnInLayers({ + layers: { ...state.layers, [target.layerId]: outputTargetLayer }, + source, + }); + setState(mergeLayers({ state, newLayers })); return true; } 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 7a7297e77bcf2..2f703547219ec 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 @@ -18,9 +18,9 @@ export interface OperationSupportMatrix { } type Props = Pick< - DatasourceDimensionDropProps, - 'layerId' | 'columnId' | 'state' | 'filterOperations' ->; + DatasourceDimensionDropProps['target'], + 'layerId' | 'columnId' | 'filterOperations' +> & { state: IndexPatternPrivateState }; function computeOperationMatrix( operationsByMetadata: Array<{ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx index 437ee4bf8b22d..104b85651a876 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx @@ -150,12 +150,8 @@ export const countOperation: OperationDefinition - adjustTimeScaleOnOtherColumnChange( - layer, - thisColumnId, - changedColumnId - ), + onOtherColumnChanged: (layer, thisColumnId) => + adjustTimeScaleOnOtherColumnChange(layer, thisColumnId), toEsAggsFn: (column, columnId) => { return buildExpressionFunction('aggCount', { id: columnId, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx index 1d08873a160e9..72aace21479ac 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/formula.tsx @@ -174,13 +174,23 @@ export const formulaOperation: OperationDefinition { return true; }, - createCopy(layer, sourceId, targetId, indexPattern, operationDefinitionMap) { - const currentColumn = layer.columns[sourceId] as FormulaIndexPatternColumn; - - return insertOrReplaceFormulaColumn(targetId, currentColumn, layer, { - indexPattern, - operations: operationDefinitionMap, - }).layer; + createCopy(layers, source, target, operationDefinitionMap) { + const currentColumn = layers[source.layerId].columns[ + source.columnId + ] as FormulaIndexPatternColumn; + const modifiedLayer = insertOrReplaceFormulaColumn( + target.columnId, + currentColumn, + layers[target.layerId], + { + indexPattern: target.dataView, + operations: operationDefinitionMap, + } + ); + return { + ...layers, + [target.layerId]: modifiedLayer.layer, + }; }, timeScalingMode: 'optional', paramEditor: WrappedFormulaEditor, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx index 85c2ea707b123..d7f25275f63a2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/math.tsx @@ -67,8 +67,8 @@ export const mathOperation: OperationDefinition { - return { ...layer }; + createCopy: (layers) => { + return { ...layers }; }, }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts index 74d635cac02dc..cdf2b0249529e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts @@ -54,7 +54,12 @@ import type { GenericIndexPatternColumn, ReferenceBasedIndexPatternColumn, } from './column_types'; -import { IndexPattern, IndexPatternField, IndexPatternLayer } from '../../types'; +import { + DataViewDragDropOperation, + IndexPattern, + IndexPatternField, + IndexPatternLayer, +} from '../../types'; import { DateRange, LayerType } from '../../../../common'; import { rangeOperation } from './ranges'; import { IndexPatternDimensionEditorProps, OperationSupportMatrix } from '../../dimension_panel'; @@ -249,11 +254,7 @@ interface BaseOperationDefinitionProps * Based on the current column and the other updated columns, this function has to * return an updated column. If not implemented, the `id` function is used instead. */ - onOtherColumnChanged?: ( - layer: IndexPatternLayer, - thisColumnId: string, - changedColumnId: string - ) => C; + onOtherColumnChanged?: (layer: IndexPatternLayer, thisColumnId: string) => C; /** * React component for operation specific settings shown in the flyout editor */ @@ -623,12 +624,11 @@ interface ManagedReferenceOperationDefinition * root level */ createCopy: ( - layer: IndexPatternLayer, - sourceColumnId: string, - targetColumnId: string, - indexPattern: IndexPattern, + layers: Record, + source: DataViewDragDropOperation, + target: DataViewDragDropOperation, operationDefinitionMap: Record - ) => IndexPatternLayer; + ) => Record; } interface OperationDefinitionMap { 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 55df2b8e0ff1a..10c4310e820b2 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 @@ -108,9 +108,9 @@ function buildMetricOperation>({ (!newField.aggregationRestrictions || newField.aggregationRestrictions![type]) ); }, - onOtherColumnChanged: (layer, thisColumnId, changedColumnId) => + onOtherColumnChanged: (layer, thisColumnId) => optionalTimeScaling - ? (adjustTimeScaleOnOtherColumnChange(layer, thisColumnId, changedColumnId) as T) + ? (adjustTimeScaleOnOtherColumnChange(layer, thisColumnId) as T) : (layer.columns[thisColumnId] as T), getDefaultLabel: (column, indexPattern, columns) => labelLookup(getSafeName(column.sourceField, indexPattern), column), diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx index 555360a2f7f6c..5642c06c6b642 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/static_value.tsx @@ -16,6 +16,7 @@ import { import type { IndexPattern } from '../../types'; import { useDebouncedValue } from '../../../shared_components'; import { getFormatFromPreviousColumn, isValidNumber } from './helpers'; +import { getColumnOrder } from '../layer_helpers'; const defaultLabel = i18n.translate('xpack.lens.indexPattern.staticValueLabelDefault', { defaultMessage: 'Static value', @@ -132,13 +133,21 @@ export const staticValueOperation: OperationDefinition< isTransferable: (column) => { return true; }, - createCopy(layer, sourceId, targetId, indexPattern, operationDefinitionMap) { - const currentColumn = layer.columns[sourceId] as StaticValueIndexPatternColumn; + createCopy(layers, source, target) { + const currentColumn = layers[source.layerId].columns[ + source.columnId + ] as StaticValueIndexPatternColumn; + const targetLayer = layers[target.layerId]; + const columns = { + ...targetLayer.columns, + [target.columnId]: { ...currentColumn }, + }; return { - ...layer, - columns: { - ...layer.columns, - [targetId]: { ...currentColumn }, + ...layers, + [target.layerId]: { + ...targetLayer, + columns, + columnOrder: getColumnOrder({ ...targetLayer, columns }), }, }; }, 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 419e087411810..62aed475df42a 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 @@ -325,7 +325,7 @@ export const termsOperation: OperationDefinition { + onOtherColumnChanged: (layer, thisColumnId) => { const columns = layer.columns; const currentColumn = columns[thisColumnId] as TermsIndexPatternColumn; if ( 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 1cce6c5b06cd6..99c20bbd8bca6 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 @@ -755,8 +755,7 @@ describe('terms', () => { }, }, }, - 'col2', - 'col1' + 'col2' ); expect(updatedColumn).toBe(initialColumn); @@ -796,8 +795,7 @@ describe('terms', () => { columnOrder: [], indexPatternId: '', }, - 'col2', - 'col1' + 'col2' ); expect(updatedColumn.params).toEqual( expect.objectContaining({ @@ -843,8 +841,7 @@ describe('terms', () => { columnOrder: [], indexPatternId: '', }, - 'col2', - 'col1' + 'col2' ); expect(updatedColumn.params).toEqual( expect.objectContaining({ @@ -875,8 +872,7 @@ describe('terms', () => { columnOrder: [], indexPatternId: '', }, - 'col2', - 'col1' + 'col2' ); expect(termsColumn.params).toEqual( expect.objectContaining({ @@ -919,8 +915,7 @@ describe('terms', () => { columnOrder: [], indexPatternId: '', }, - 'col2', - 'col1' + 'col2' ); expect(termsColumn.params).toEqual( expect.objectContaining({ @@ -951,8 +946,7 @@ describe('terms', () => { columnOrder: [], indexPatternId: '', }, - 'col2', - 'col1' + 'col2' ); expect(termsColumn.params).toEqual( expect.objectContaining({ @@ -991,8 +985,7 @@ describe('terms', () => { }, }, }, - 'col2', - 'col1' + 'col2' ); expect(updatedColumn.params).toEqual( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts index 4fdd82439fc22..ab9319957afca 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.test.ts @@ -159,24 +159,38 @@ describe('state_helpers', () => { params: { window: 5 }, references: ['formulaX0'], }; + expect( copyColumn({ - layer: { - indexPatternId: '', - columnOrder: [], - columns: { - source, - formulaX0: sum, - formulaX1: movingAvg, - formulaX2: math, + layers: { + layer: { + indexPatternId: '', + columnOrder: [], + columns: { + source, + formulaX0: sum, + formulaX1: movingAvg, + formulaX2: math, + }, }, }, - targetId: 'copy', - sourceColumn: source, + source: { + column: source, + groupId: 'one', + columnId: 'source', + layerId: 'layer', + dataView: indexPattern, + filterOperations: () => true, + }, + target: { + columnId: 'copy', + groupId: 'one', + dataView: indexPattern, + layerId: 'layer', + filterOperations: () => true, + }, shouldDeleteSource: false, - indexPattern, - sourceColumnId: 'source', - }) + }).layer ).toEqual({ indexPatternId: '', columnOrder: [ @@ -1355,8 +1369,7 @@ describe('state_helpers', () => { }, incompleteColumns: {}, }, - 'col1', - 'col2' + 'col1' ); }); @@ -1422,8 +1435,7 @@ describe('state_helpers', () => { }, incompleteColumns: {}, }), - 'col1', - 'willBeReference' + 'col1' ); }); @@ -2374,8 +2386,7 @@ describe('state_helpers', () => { expect(operationDefinitionMap.terms.onOtherColumnChanged).toHaveBeenCalledWith( { indexPatternId: '1', columnOrder: ['col1', 'col2'], columns: { col1: termsColumn } }, - 'col1', - 'col2' + 'col1' ); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts index 8376a57ddc19d..434370943fbc1 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts @@ -26,6 +26,7 @@ import { TermsIndexPatternColumn, } from './definitions'; import type { + DataViewDragDropOperation, IndexPattern, IndexPatternField, IndexPatternLayer, @@ -68,96 +69,84 @@ interface ColumnChange { } interface ColumnCopy { - layer: IndexPatternLayer; - targetId: string; - sourceColumn: GenericIndexPatternColumn; - sourceColumnId: string; - indexPattern: IndexPattern; + layers: Record; + target: DataViewDragDropOperation; + source: DataViewDragDropOperation; shouldDeleteSource?: boolean; } +export const deleteColumnInLayers = ({ + layers, + source, +}: { + layers: Record; + source: DataViewDragDropOperation; +}) => ({ + ...layers, + [source.layerId]: deleteColumn({ + layer: layers[source.layerId], + columnId: source.columnId, + indexPattern: source.dataView, + }), +}); + export function copyColumn({ - layer, - targetId, - sourceColumn, + layers, + source, + target, shouldDeleteSource, - indexPattern, - sourceColumnId, -}: ColumnCopy): IndexPatternLayer { - let modifiedLayer = copyReferencesRecursively( - layer, - sourceColumn, - sourceColumnId, - targetId, - indexPattern - ); - - if (shouldDeleteSource) { - modifiedLayer = deleteColumn({ - layer: modifiedLayer, - columnId: sourceColumnId, - indexPattern, - }); - } - - return modifiedLayer; +}: ColumnCopy): Record { + const outputLayers = createCopiedColumn(layers, target, source); + return shouldDeleteSource + ? deleteColumnInLayers({ + layers: outputLayers, + source, + }) + : outputLayers; } -function copyReferencesRecursively( - layer: IndexPatternLayer, - sourceColumn: GenericIndexPatternColumn, - sourceId: string, - targetId: string, - indexPattern: IndexPattern -): IndexPatternLayer { - let columns = { ...layer.columns }; +function createCopiedColumn( + layers: Record, + target: DataViewDragDropOperation, + source: DataViewDragDropOperation +): Record { + const sourceLayer = layers[source.layerId]; + const sourceColumn = sourceLayer.columns[source.columnId]; + const targetLayer = layers[target.layerId]; + let columns = { ...targetLayer.columns }; if ('references' in sourceColumn) { - if (columns[targetId]) { - return layer; - } - const def = operationDefinitionMap[sourceColumn.operationType]; if ('createCopy' in def) { - // Allow managed references to recursively insert new columns - return def.createCopy(layer, sourceId, targetId, indexPattern, operationDefinitionMap); + return def.createCopy(layers, source, target, operationDefinitionMap); // Allow managed references to recursively insert new columns } + const referenceColumns = sourceColumn.references.reduce((refs, sourceRef) => { + const newRefId = generateId(); + return { ...refs, [newRefId]: { ...sourceLayer.columns[sourceRef] } }; + }, {}); - sourceColumn?.references.forEach((ref, index) => { - const newId = generateId(); - const refColumn = { ...columns[ref] }; - - // TODO: For fullReference types, now all references are hidden columns, - // but in the future we will have references to visible columns - // and visible columns shouldn't be copied - const refColumnWithInnerRefs = - 'references' in refColumn - ? copyReferencesRecursively(layer, refColumn, sourceId, newId, indexPattern).columns // if a column has references, copy them too - : { [newId]: refColumn }; - - const newColumn = columns[targetId]; - let references = [newId]; - if (newColumn && 'references' in newColumn) { - references = newColumn.references; - references[index] = newId; - } - - columns = { - ...columns, - ...refColumnWithInnerRefs, - [targetId]: { - ...sourceColumn, - references, - }, - }; - }); + columns = { + ...columns, + ...referenceColumns, + [target.columnId]: { + ...sourceColumn, + references: Object.keys(referenceColumns), + }, + }; } else { columns = { ...columns, - [targetId]: sourceColumn, + [target.columnId]: { ...sourceColumn }, }; } - return { ...layer, columns, columnOrder: getColumnOrder({ ...layer, columns }) }; + return { + ...layers, + [target.layerId]: adjustColumnReferences({ + ...targetLayer, + columns, + columnOrder: getColumnOrder({ ...targetLayer, columns }), + }), + }; } export function insertOrReplaceColumn(args: ColumnChange): IndexPatternLayer { @@ -1046,8 +1035,8 @@ function addBucket( } updatedColumnOrder = reorderByGroups( visualizationGroups, - targetGroup, updatedColumnOrder, + targetGroup, addedColumnId ); const tempLayer = { @@ -1064,8 +1053,8 @@ function addBucket( export function reorderByGroups( visualizationGroups: VisualizationDimensionGroupConfig[], - targetGroup: string | undefined, updatedColumnOrder: string[], + targetGroup: string | undefined, addedColumnId: string ) { const hidesColumnGrouping = @@ -1184,6 +1173,26 @@ export function updateColumnParam({ }; } +export function adjustColumnReferences(layer: IndexPatternLayer) { + const newColumns = { ...layer.columns }; + Object.keys(newColumns).forEach((currentColumnId) => { + const currentColumn = newColumns[currentColumnId]; + if (currentColumn?.operationType) { + const operationDefinition = operationDefinitionMap[currentColumn.operationType]; + newColumns[currentColumnId] = operationDefinition.onOtherColumnChanged + ? operationDefinition.onOtherColumnChanged( + { ...layer, columns: newColumns }, + currentColumnId + ) + : currentColumn; + } + }); + return { + ...layer, + columns: newColumns, + }; +} + export function adjustColumnReferencesForChangedColumn( layer: IndexPatternLayer, changedColumnId: string @@ -1196,8 +1205,7 @@ export function adjustColumnReferencesForChangedColumn( newColumns[currentColumnId] = operationDefinition.onOtherColumnChanged ? operationDefinition.onOtherColumnChanged( { ...layer, columns: newColumns }, - currentColumnId, - changedColumnId + currentColumnId ) : currentColumn; } @@ -1561,6 +1569,9 @@ export function isColumnValidAsReference({ if (!column) return false; const operationType = column.operationType; const operationDefinition = operationDefinitionMap[operationType]; + if (!operationDefinition) { + throw new Error('No suitable operation definition found for ' + operationType); + } return ( validation.input.includes(operationDefinition.input) && maybeValidateOperations({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.test.ts index 1eb02fa82ceef..fd8952ad9e077 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.test.ts @@ -113,11 +113,7 @@ describe('time scale utils', () => { it('should keep column if there is no time scale', () => { const column = { ...baseColumn, timeScale: undefined }; expect( - adjustTimeScaleOnOtherColumnChange( - { ...baseLayer, columns: { col1: column } }, - 'col1', - 'col2' - ) + adjustTimeScaleOnOtherColumnChange({ ...baseLayer, columns: { col1: column } }, 'col1') ).toBe(column); }); @@ -138,14 +134,13 @@ describe('time scale utils', () => { } as DateHistogramIndexPatternColumn, }, }, - 'col1', - 'col2' + 'col1' ) ).toBe(baseColumn); }); it('should remove time scale if there is no date histogram', () => { - expect(adjustTimeScaleOnOtherColumnChange(baseLayer, 'col1', 'col2')).toHaveProperty( + expect(adjustTimeScaleOnOtherColumnChange(baseLayer, 'col1')).toHaveProperty( 'timeScale', undefined ); @@ -153,22 +148,14 @@ describe('time scale utils', () => { it('should remove suffix from label', () => { expect( - adjustTimeScaleOnOtherColumnChange( - { ...baseLayer, columns: { col1: baseColumn } }, - 'col1', - 'col2' - ) + adjustTimeScaleOnOtherColumnChange({ ...baseLayer, columns: { col1: baseColumn } }, 'col1') ).toHaveProperty('label', 'Count of records'); }); it('should keep custom label', () => { const column = { ...baseColumn, label: 'abc', customLabel: true }; expect( - adjustTimeScaleOnOtherColumnChange( - { ...baseLayer, columns: { col1: column } }, - 'col1', - 'col2' - ) + adjustTimeScaleOnOtherColumnChange({ ...baseLayer, columns: { col1: column } }, 'col1') ).toHaveProperty('label', 'abc'); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.ts index a8e71c0fd86e5..c6cd343504253 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/time_scale_utils.ts @@ -46,8 +46,7 @@ export function adjustTimeScaleLabelSuffix( export function adjustTimeScaleOnOtherColumnChange( layer: IndexPatternLayer, - thisColumnId: string, - changedColumnId: string + thisColumnId: string ): T { const columns = layer.columns; const column = columns[thisColumnId] as T; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.ts index 5d48922a66d8a..6e16ebe5e8d53 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/state_helpers.ts @@ -24,3 +24,19 @@ export function mergeLayer({ }, }; } + +export function mergeLayers({ + state, + newLayers, +}: { + state: IndexPatternPrivateState; + newLayers: Record; +}) { + return { + ...state, + layers: { + ...state.layers, + ...newLayers, + }, + }; +} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts index 7e25509c3b2dd..cbf02bddb8814 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts @@ -10,6 +10,7 @@ import type { FieldSpec } from '@kbn/data-plugin/common'; import type { FieldFormatParams } from '@kbn/field-formats-plugin/common'; import type { DragDropIdentifier } from '../drag_drop/providers'; import type { IncompleteColumn, GenericIndexPatternColumn } from './operations'; +import { DragDropOperation } from '../types'; export type { GenericIndexPatternColumn, @@ -109,3 +110,8 @@ export interface IndexPatternRef { title: string; name?: string; } + +export interface DataViewDragDropOperation extends DragDropOperation { + dataView: IndexPattern; + column?: GenericIndexPatternColumn; +} diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 873159562dc8f..770f4bee7eecd 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -199,11 +199,18 @@ interface ChartSettings { }; } -export type GetDropProps = DatasourceDimensionDropProps & { - groupId: string; - dragging: DragContextState['dragging']; - prioritizedOperation?: string; -}; +export interface GetDropPropsArgs { + state: T; + source?: DraggingIdentifier; + target: { + layerId: string; + groupId: string; + columnId: string; + filterOperations: (meta: OperationMetadata) => boolean; + prioritizedOperation?: string; + isNewColumn?: boolean; + }; +} /** * Interface for the datasource registry @@ -257,9 +264,9 @@ export interface Datasource { props: DatasourceLayerPanelProps ) => ((cleanupElement: Element) => void) | void; getDropProps: ( - props: GetDropProps + props: GetDropPropsArgs ) => { dropTypes: DropType[]; nextLabel?: string } | undefined; - onDrop: (props: DatasourceDimensionDropHandlerProps) => false | true | { deleted: string }; + onDrop: (props: DatasourceDimensionDropHandlerProps) => boolean | undefined; /** * The datasource is allowed to cancel a close event on the dimension editor, * mainly used for formulas @@ -454,16 +461,14 @@ export interface DatasourceLayerPanelProps { activeData?: Record; } -export interface DraggedOperation extends DraggingIdentifier { +export interface DragDropOperation { layerId: string; groupId: string; columnId: string; filterOperations: (operation: OperationMetadata) => boolean; } -export function isDraggedOperation( - operationCandidate: unknown -): operationCandidate is DraggedOperation { +export function isOperation(operationCandidate: unknown): operationCandidate is DragDropOperation { return ( typeof operationCandidate === 'object' && operationCandidate !== null && @@ -471,10 +476,8 @@ export function isDraggedOperation( ); } -export type DatasourceDimensionDropProps = SharedDimensionProps & { - layerId: string; - groupId: string; - columnId: string; +export interface DatasourceDimensionDropProps { + target: DragDropOperation; state: T; setState: StateSetter< T, @@ -484,10 +487,10 @@ export type DatasourceDimensionDropProps = SharedDimensionProps & { } >; dimensionGroups: VisualizationDimensionGroupConfig[]; -}; +} -export type DatasourceDimensionDropHandlerProps = DatasourceDimensionDropProps & { - droppedItem: unknown; +export type DatasourceDimensionDropHandlerProps = DatasourceDimensionDropProps & { + source: DragDropIdentifier; dropType: DropType; }; @@ -851,7 +854,17 @@ export interface Visualization { * look at its internal state to determine which dimension is being affected. */ removeDimension: (props: VisualizationDimensionChangeProps) => T; - + /** + * Allow defining custom behavior for the visualization when the drop action occurs. + */ + onDrop?: (props: { + prevState: T; + target: DragDropOperation; + source: DragDropIdentifier; + frame: FramePublicAPI; + dropType: DropType; + group?: VisualizationDimensionGroupConfig; + }) => T; /** * Update the configuration for the visualization. This is used to update the state */ diff --git a/x-pack/plugins/lens/public/xy_visualization/annotations/helpers.tsx b/x-pack/plugins/lens/public/xy_visualization/annotations/helpers.tsx index 35a40623b72aa..692d0f02725b2 100644 --- a/x-pack/plugins/lens/public/xy_visualization/annotations/helpers.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/annotations/helpers.tsx @@ -118,6 +118,207 @@ export const getAnnotationsSupportedLayer = ( }; }; +const getDefaultAnnotationConfig = (id: string, timestamp: string): EventAnnotationConfig => ({ + label: defaultAnnotationLabel, + key: { + type: 'point_in_time', + timestamp, + }, + icon: 'triangle', + id, +}); + +const createCopiedAnnotation = ( + newId: string, + timestamp: string, + source?: EventAnnotationConfig +): EventAnnotationConfig => { + if (!source) { + return getDefaultAnnotationConfig(newId, timestamp); + } + return { + ...source, + id: newId, + }; +}; + +export const onAnnotationDrop: Visualization['onDrop'] = ({ + prevState, + frame, + source, + target, + dropType, +}) => { + const targetLayer = prevState.layers.find((l) => l.layerId === target.layerId); + const sourceLayer = prevState.layers.find((l) => l.layerId === source.layerId); + if ( + !targetLayer || + !isAnnotationsLayer(targetLayer) || + !sourceLayer || + !isAnnotationsLayer(sourceLayer) + ) { + return prevState; + } + const targetAnnotation = targetLayer.annotations.find(({ id }) => id === target.columnId); + const sourceAnnotation = sourceLayer.annotations.find(({ id }) => id === source.columnId); + switch (dropType) { + case 'reorder': + if (!targetAnnotation || !sourceAnnotation || source.layerId !== target.layerId) { + return prevState; + } + const newAnnotations = targetLayer.annotations.filter((c) => c.id !== sourceAnnotation.id); + const targetPosition = newAnnotations.findIndex((c) => c.id === targetAnnotation.id); + const targetIndex = targetLayer.annotations.indexOf(sourceAnnotation); + const sourceIndex = targetLayer.annotations.indexOf(targetAnnotation); + newAnnotations.splice( + targetIndex < sourceIndex ? targetPosition + 1 : targetPosition, + 0, + sourceAnnotation + ); + return { + ...prevState, + layers: prevState.layers.map((l) => + l.layerId === target.layerId ? { ...targetLayer, annotations: newAnnotations } : l + ), + }; + case 'swap_compatible': + if (!targetAnnotation || !sourceAnnotation) { + return prevState; + } + return { + ...prevState, + layers: prevState.layers.map((l): XYLayerConfig => { + if (!isAnnotationsLayer(l) || !isAnnotationsLayer(targetLayer)) { + return l; + } + if (l.layerId === target.layerId) { + return { + ...targetLayer, + annotations: [ + ...targetLayer.annotations.map( + (a): EventAnnotationConfig => (a === targetAnnotation ? sourceAnnotation : a) + ), + ], + }; + } + if (l.layerId === source.layerId) { + return { + ...sourceLayer, + annotations: [ + ...sourceLayer.annotations.map( + (a): EventAnnotationConfig => (a === sourceAnnotation ? targetAnnotation : a) + ), + ], + }; + } + return l; + }), + }; + case 'replace_compatible': + if (!targetAnnotation || !sourceAnnotation) { + return prevState; + } + + return { + ...prevState, + layers: prevState.layers.map((l) => { + if (l.layerId === source.layerId) { + return { + ...sourceLayer, + annotations: sourceLayer.annotations.filter((a) => a !== sourceAnnotation), + }; + } + if (l.layerId === target.layerId) { + return { + ...targetLayer, + annotations: [ + ...targetLayer.annotations.map((a) => + a === targetAnnotation ? sourceAnnotation : a + ), + ], + }; + } + return l; + }), + }; + case 'duplicate_compatible': + if (targetAnnotation) { + return prevState; + } + return { + ...prevState, + layers: prevState.layers.map( + (l): XYLayerConfig => + l.layerId === target.layerId + ? { + ...targetLayer, + annotations: [ + ...targetLayer.annotations, + createCopiedAnnotation( + target.columnId, + getStaticDate(getDataLayers(prevState.layers), frame), + sourceAnnotation + ), + ], + } + : l + ), + }; + case 'replace_duplicate_compatible': + if (!targetAnnotation) { + return prevState; + } + return { + ...prevState, + layers: prevState.layers.map((l) => { + if (l.layerId === target.layerId) { + return { + ...targetLayer, + annotations: [ + ...targetLayer.annotations.map((a) => + a === targetAnnotation + ? createCopiedAnnotation( + target.columnId, + getStaticDate(getDataLayers(prevState.layers), frame), + sourceAnnotation + ) + : a + ), + ], + }; + } + return l; + }), + }; + case 'move_compatible': + if (targetAnnotation || !sourceAnnotation) { + return prevState; + } + + return { + ...prevState, + layers: prevState.layers.map((l): XYLayerConfig => { + if (l.layerId === source.layerId) { + return { + ...sourceLayer, + annotations: sourceLayer.annotations.filter((a) => a !== sourceAnnotation), + }; + } + if (l.layerId === target.layerId) { + return { + ...targetLayer, + annotations: [...targetLayer.annotations, sourceAnnotation], + }; + } + return l; + }), + }; + default: + return prevState; + } + return prevState; +}; + export const setAnnotationsDimension: Visualization['setDimension'] = ({ prevState, layerId, @@ -125,46 +326,30 @@ export const setAnnotationsDimension: Visualization['setDimension'] = ( previousColumn, frame, }) => { - const foundLayer = prevState.layers.find((l) => l.layerId === layerId); - if (!foundLayer || !isAnnotationsLayer(foundLayer)) { + const targetLayer = prevState.layers.find((l) => l.layerId === layerId); + if (!targetLayer || !isAnnotationsLayer(targetLayer)) { return prevState; } - const inputAnnotations = foundLayer.annotations as XYAnnotationLayerConfig['annotations']; - const currentConfig = inputAnnotations?.find(({ id }) => id === columnId); - const previousConfig = previousColumn - ? inputAnnotations?.find(({ id }) => id === previousColumn) + const sourceAnnotation = previousColumn + ? targetLayer.annotations?.find(({ id }) => id === previousColumn) : undefined; - let resultAnnotations = [...inputAnnotations] as XYAnnotationLayerConfig['annotations']; - - if (!currentConfig) { - resultAnnotations.push({ - label: defaultAnnotationLabel, - key: { - type: 'point_in_time', - timestamp: getStaticDate(getDataLayers(prevState.layers), frame), - }, - icon: 'triangle', - ...previousConfig, - id: columnId, - }); - } else if (currentConfig && previousConfig) { - // TODO: reordering should not live in setDimension, to be refactored - resultAnnotations = inputAnnotations.filter((c) => c.id !== previousConfig.id); - const targetPosition = resultAnnotations.findIndex((c) => c.id === currentConfig.id); - const targetIndex = inputAnnotations.indexOf(previousConfig); - const sourceIndex = inputAnnotations.indexOf(currentConfig); - resultAnnotations.splice( - targetIndex < sourceIndex ? targetPosition + 1 : targetPosition, - 0, - previousConfig - ); - } - return { ...prevState, layers: prevState.layers.map((l) => - l.layerId === layerId ? { ...foundLayer, annotations: resultAnnotations } : l + l.layerId === layerId + ? { + ...targetLayer, + annotations: [ + ...targetLayer.annotations, + createCopiedAnnotation( + columnId, + getStaticDate(getDataLayers(prevState.layers), frame), + sourceAnnotation + ), + ], + } + : l ), }; }; @@ -224,7 +409,6 @@ export const getAnnotationsConfiguration = ({ defaultMessage: 'Annotations require a time based chart to work. Add a date histogram.', }), required: false, - requiresPreviousColumnOnDuplicate: true, supportsMoreColumns: true, supportFieldFormat: false, enableDimensionEditor: true, diff --git a/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx index 3f0e8816cf6b1..ece9a6d28893e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/reference_line_helpers.tsx @@ -18,6 +18,7 @@ import { checkScaleOperation, getAxisName, getDataLayers, + getReferenceLayers, isNumericMetric, isReferenceLayer, } from './visualization_helpers'; @@ -342,7 +343,10 @@ export const setReferenceDimension: Visualization['setDimension'] = ({ newLayer.accessors = [...newLayer.accessors.filter((a) => a !== columnId), columnId]; const hasYConfig = newLayer.yConfig?.some(({ forAccessor }) => forAccessor === columnId); const previousYConfig = previousColumn - ? newLayer.yConfig?.find(({ forAccessor }) => forAccessor === previousColumn) + ? getReferenceLayers(prevState.layers) + .map(({ yConfig }) => yConfig) + .flat() + ?.find((yConfig) => yConfig?.forAccessor === previousColumn) : false; if (!hasYConfig) { const axisMode: YAxisMode = diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index 1cc3df6b5ca96..0092bb78a6d71 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -476,7 +476,7 @@ describe('xy_visualization', () => { }); it('should copy previous column if passed and assign a new id', () => { expect( - xyVisualization.setDimension({ + xyVisualization.onDrop!({ frame, prevState: { ...exampleState(), @@ -488,10 +488,20 @@ describe('xy_visualization', () => { }, ], }, - layerId: 'annotation', - groupId: 'xAnnotation', - previousColumn: 'an2', - columnId: 'newColId', + dropType: 'duplicate_compatible', + source: { + layerId: 'annotation', + groupId: 'xAnnotation', + columnId: 'an2', + id: 'an2', + humanData: { label: 'an2' }, + }, + target: { + layerId: 'annotation', + groupId: 'xAnnotation', + columnId: 'newColId', + filterOperations: Boolean, + }, }).layers[0] ).toEqual({ layerId: 'annotation', @@ -501,7 +511,7 @@ describe('xy_visualization', () => { }); it('should reorder a dimension to a annotation layer', () => { expect( - xyVisualization.setDimension({ + xyVisualization.onDrop!({ frame, prevState: { ...exampleState(), @@ -513,10 +523,21 @@ describe('xy_visualization', () => { }, ], }, - layerId: 'annotation', - groupId: 'xAnnotation', - previousColumn: 'an2', - columnId: 'an1', + source: { + layerId: 'annotation', + groupId: 'xAnnotation', + columnId: 'an2', + id: 'an2', + humanData: { label: 'label' }, + filterOperations: () => true, + }, + target: { + layerId: 'annotation', + groupId: 'xAnnotation', + columnId: 'an1', + filterOperations: () => true, + }, + dropType: 'reorder', }).layers[0] ).toEqual({ layerId: 'annotation', @@ -524,6 +545,199 @@ describe('xy_visualization', () => { annotations: [exampleAnnotation2, exampleAnnotation], }); }); + + it('should duplicate the annotations and replace the target in another annotation layer', () => { + expect( + xyVisualization.onDrop!({ + frame, + prevState: { + ...exampleState(), + layers: [ + { + layerId: 'first', + layerType: 'annotations', + annotations: [exampleAnnotation], + }, + { + layerId: 'second', + layerType: 'annotations', + annotations: [exampleAnnotation2], + }, + ], + }, + source: { + layerId: 'first', + groupId: 'xAnnotation', + columnId: 'an1', + id: 'an1', + humanData: { label: 'label' }, + filterOperations: () => true, + }, + target: { + layerId: 'second', + groupId: 'xAnnotation', + columnId: 'an2', + filterOperations: () => true, + }, + dropType: 'replace_duplicate_compatible', + }).layers + ).toEqual([ + { + layerId: 'first', + layerType: layerTypes.ANNOTATIONS, + annotations: [exampleAnnotation], + }, + { + layerId: 'second', + layerType: layerTypes.ANNOTATIONS, + annotations: [{ ...exampleAnnotation, id: 'an2' }], + }, + ]); + }); + it('should swap the annotations between layers', () => { + expect( + xyVisualization.onDrop!({ + frame, + prevState: { + ...exampleState(), + layers: [ + { + layerId: 'first', + layerType: 'annotations', + annotations: [exampleAnnotation], + }, + { + layerId: 'second', + layerType: 'annotations', + annotations: [exampleAnnotation2], + }, + ], + }, + source: { + layerId: 'first', + groupId: 'xAnnotation', + columnId: 'an1', + id: 'an1', + humanData: { label: 'label' }, + filterOperations: () => true, + }, + target: { + layerId: 'second', + groupId: 'xAnnotation', + columnId: 'an2', + filterOperations: () => true, + }, + dropType: 'swap_compatible', + }).layers + ).toEqual([ + { + layerId: 'first', + layerType: layerTypes.ANNOTATIONS, + annotations: [exampleAnnotation2], + }, + { + layerId: 'second', + layerType: layerTypes.ANNOTATIONS, + annotations: [exampleAnnotation], + }, + ]); + }); + it('should replace the target in another annotation layer', () => { + expect( + xyVisualization.onDrop!({ + frame, + prevState: { + ...exampleState(), + layers: [ + { + layerId: 'first', + layerType: 'annotations', + annotations: [exampleAnnotation], + }, + { + layerId: 'second', + layerType: 'annotations', + annotations: [exampleAnnotation2], + }, + ], + }, + source: { + layerId: 'first', + groupId: 'xAnnotation', + columnId: 'an1', + id: 'an1', + humanData: { label: 'label' }, + filterOperations: () => true, + }, + target: { + layerId: 'second', + groupId: 'xAnnotation', + columnId: 'an2', + filterOperations: () => true, + }, + dropType: 'replace_compatible', + }).layers + ).toEqual([ + { + layerId: 'first', + layerType: layerTypes.ANNOTATIONS, + annotations: [], + }, + { + layerId: 'second', + layerType: layerTypes.ANNOTATIONS, + annotations: [exampleAnnotation], + }, + ]); + }); + it('should move compatible to another annotation layer', () => { + expect( + xyVisualization.onDrop!({ + frame, + prevState: { + ...exampleState(), + layers: [ + { + layerId: 'first', + layerType: 'annotations', + annotations: [exampleAnnotation], + }, + { + layerId: 'second', + layerType: 'annotations', + annotations: [], + }, + ], + }, + source: { + layerId: 'first', + groupId: 'xAnnotation', + columnId: 'an1', + id: 'an1', + humanData: { label: 'label' }, + filterOperations: () => true, + }, + target: { + layerId: 'second', + groupId: 'xAnnotation', + columnId: 'an2', + filterOperations: () => true, + }, + dropType: 'move_compatible', + }).layers + ).toEqual([ + { + layerId: 'first', + layerType: layerTypes.ANNOTATIONS, + annotations: [], + }, + { + layerId: 'second', + layerType: layerTypes.ANNOTATIONS, + annotations: [exampleAnnotation], + }, + ]); + }); }); }); diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 4f89ba1fdcedf..dcf3ab3e42a47 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -27,7 +27,7 @@ import { getSuggestions } from './xy_suggestions'; import { XyToolbar } from './xy_config_panel'; import { DimensionEditor } from './xy_config_panel/dimension_editor'; import { LayerHeader } from './xy_config_panel/layer_header'; -import type { Visualization, AccessorConfig, FramePublicAPI } from '../types'; +import { Visualization, AccessorConfig, FramePublicAPI } from '../types'; import { State, visualizationTypes, XYSuggestion, XYLayerConfig, XYDataLayerConfig } from './types'; import { layerTypes } from '../../common'; import { isHorizontalChart } from './state_helpers'; @@ -45,6 +45,7 @@ import { getAnnotationsSupportedLayer, setAnnotationsDimension, getUniqueLabels, + onAnnotationDrop, } from './annotations/helpers'; import { checkXAccessorCompatibility, @@ -71,6 +72,7 @@ import { ReferenceLinePanel } from './xy_config_panel/reference_line_config_pane import { AnnotationsPanel } from './xy_config_panel/annotations_config_panel'; import { DimensionTrigger } from '../shared_components/dimension_trigger'; import { defaultAnnotationLabel } from './annotations/helpers'; +import { onDropForVisualization } from '../editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils'; export const getXyVisualization = ({ datatableUtilities, @@ -303,6 +305,20 @@ export const getXyVisualization = ({ return getFirstDataLayer(state.layers)?.palette; }, + onDrop(props) { + const targetLayer: XYLayerConfig | undefined = props.prevState.layers.find( + (l) => l.layerId === props.target.layerId + ); + if (!targetLayer) { + throw new Error('target layer should exist'); + } + + if (isAnnotationsLayer(targetLayer)) { + return onAnnotationDrop?.(props) || props.prevState; + } + return onDropForVisualization(props, this); + }, + setDimension(props) { const { prevState, layerId, columnId, groupId } = props; diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization_helpers.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization_helpers.tsx index d390d081258a5..9b4ed872f1dc2 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization_helpers.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization_helpers.tsx @@ -334,6 +334,7 @@ export function validateLayersForDimension( export const isNumericMetric = (op: OperationMetadata) => !op.isBucketed && op.dataType === 'number'; + export const isNumericDynamicMetric = (op: OperationMetadata) => isNumericMetric(op) && !op.isStaticValue; export const isBucketed = (op: OperationMetadata) => op.isBucketed; diff --git a/x-pack/plugins/ml/common/index.ts b/x-pack/plugins/ml/common/index.ts index cfed678a804a1..8d419f120a564 100644 --- a/x-pack/plugins/ml/common/index.ts +++ b/x-pack/plugins/ml/common/index.ts @@ -14,7 +14,6 @@ export { SEVERITY_COLORS, } from './constants/anomalies'; export { getSeverityColor, getSeverityType } from './util/anomaly_utils'; -export { isPopulatedObject } from './util/object_utils'; export { composeValidators, patternValidator } from './util/validators'; export { isRuntimeMappings, isRuntimeField } from './util/runtime_field_utils'; export { extractErrorMessage } from './util/errors'; diff --git a/x-pack/plugins/ml/common/types/es_client.ts b/x-pack/plugins/ml/common/types/es_client.ts index 44425619af39d..9d8f5f3dbed9f 100644 --- a/x-pack/plugins/ml/common/types/es_client.ts +++ b/x-pack/plugins/ml/common/types/es_client.ts @@ -6,7 +6,7 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { isPopulatedObject } from '../util/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export function isMultiBucketAggregate( arg: unknown diff --git a/x-pack/plugins/ml/common/types/feature_importance.ts b/x-pack/plugins/ml/common/types/feature_importance.ts index 111c8432dd439..3333f11ecd2e6 100644 --- a/x-pack/plugins/ml/common/types/feature_importance.ts +++ b/x-pack/plugins/ml/common/types/feature_importance.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { isPopulatedObject } from '../util/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export type FeatureImportanceClassName = string | number | boolean; diff --git a/x-pack/plugins/ml/common/util/errors/process_errors.ts b/x-pack/plugins/ml/common/util/errors/process_errors.ts index e5c6ed38161ab..0da2650fa5fd6 100644 --- a/x-pack/plugins/ml/common/util/errors/process_errors.ts +++ b/x-pack/plugins/ml/common/util/errors/process_errors.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { ErrorType, MLErrorObject, @@ -14,7 +15,6 @@ import { isEsErrorBody, isMLResponseError, } from './types'; -import { isPopulatedObject } from '../object_utils'; export const extractErrorProperties = (error: ErrorType): MLErrorObject => { // extract properties of the error object from within the response error diff --git a/x-pack/plugins/ml/common/util/group_color_utils.ts b/x-pack/plugins/ml/common/util/group_color_utils.ts index b9709671475be..3c2398a18684f 100644 --- a/x-pack/plugins/ml/common/util/group_color_utils.ts +++ b/x-pack/plugins/ml/common/util/group_color_utils.ts @@ -7,7 +7,7 @@ import { euiDarkVars as euiVars } from '@kbn/ui-theme'; -import { stringHash } from './string_utils'; +import { stringHash } from '@kbn/ml-string-hash'; const COLORS = [ euiVars.euiColorVis0, diff --git a/x-pack/plugins/ml/common/util/job_utils.ts b/x-pack/plugins/ml/common/util/job_utils.ts index f1991118d4e36..d7faf732a7c84 100644 --- a/x-pack/plugins/ml/common/util/job_utils.ts +++ b/x-pack/plugins/ml/common/util/job_utils.ts @@ -9,9 +9,9 @@ import { each, isEmpty, isEqual, pick } from 'lodash'; import semverGte from 'semver/functions/gte'; import moment, { Duration } from 'moment'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -// @ts-ignore import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { ALLOWED_DATA_UNITS, JOB_ID_MAX_LENGTH } from '../constants/validation'; import { parseInterval } from './parse_interval'; import { maxLengthValidator } from './validators'; @@ -24,7 +24,7 @@ import { ES_AGGREGATION, ML_JOB_AGGREGATION } from '../constants/aggregation_typ import { MLCATEGORY } from '../constants/field_types'; import { getAggregations, getDatafeedAggregations } from './datafeed_utils'; import { findAggField } from './validation_utils'; -import { getFirstKeyInObject, isPopulatedObject } from './object_utils'; +import { getFirstKeyInObject } from './object_utils'; import { isDefined } from '../types/guards'; export interface ValidationResults { diff --git a/x-pack/plugins/ml/common/util/object_utils.test.ts b/x-pack/plugins/ml/common/util/object_utils.test.ts index d6d500cdb82c6..e6a0617c6335e 100644 --- a/x-pack/plugins/ml/common/util/object_utils.test.ts +++ b/x-pack/plugins/ml/common/util/object_utils.test.ts @@ -5,49 +5,9 @@ * 2.0. */ -import { getFirstKeyInObject, isPopulatedObject } from './object_utils'; +import { getFirstKeyInObject } from './object_utils'; describe('object_utils', () => { - describe('isPopulatedObject()', () => { - it('does not allow numbers', () => { - expect(isPopulatedObject(0)).toBe(false); - }); - it('does not allow strings', () => { - expect(isPopulatedObject('')).toBe(false); - }); - it('does not allow null', () => { - expect(isPopulatedObject(null)).toBe(false); - }); - it('does not allow an empty object', () => { - expect(isPopulatedObject({})).toBe(false); - }); - it('allows an object with an attribute', () => { - expect(isPopulatedObject({ attribute: 'value' })).toBe(true); - }); - it('does not allow an object with a non-existing required attribute', () => { - expect(isPopulatedObject({ attribute: 'value' }, ['otherAttribute'])).toBe(false); - }); - it('allows an object with an existing required attribute', () => { - expect(isPopulatedObject({ attribute: 'value' }, ['attribute'])).toBe(true); - }); - it('allows an object with two existing required attributes', () => { - expect( - isPopulatedObject({ attribute1: 'value1', attribute2: 'value2' }, [ - 'attribute1', - 'attribute2', - ]) - ).toBe(true); - }); - it('does not allow an object with two required attributes where one does not exist', () => { - expect( - isPopulatedObject({ attribute1: 'value1', attribute2: 'value2' }, [ - 'attribute1', - 'otherAttribute', - ]) - ).toBe(false); - }); - }); - describe('getFirstKeyInObject()', () => { it('gets the first key in object', () => { expect(getFirstKeyInObject({ attribute1: 'value', attribute2: 'value2' })).toBe('attribute1'); diff --git a/x-pack/plugins/ml/common/util/object_utils.ts b/x-pack/plugins/ml/common/util/object_utils.ts index cd62ca006725e..2bf2e301f9473 100644 --- a/x-pack/plugins/ml/common/util/object_utils.ts +++ b/x-pack/plugins/ml/common/util/object_utils.ts @@ -5,35 +5,7 @@ * 2.0. */ -/* - * A type guard to check record like object structures. - * - * Examples: - * - `isPopulatedObject({...})` - * Limits type to Record - * - * - `isPopulatedObject({...}, ['attribute'])` - * Limits type to Record<'attribute', unknown> - * - * - `isPopulatedObject({...})` - * Limits type to a record with keys of the given interface. - * Note that you might want to add keys from the interface to the - * array of requiredAttributes to satisfy runtime requirements. - * Otherwise you'd just satisfy TS requirements but might still - * run into runtime issues. - */ -export const isPopulatedObject = ( - arg: unknown, - requiredAttributes: U[] = [] -): arg is Record => { - return ( - typeof arg === 'object' && - arg !== null && - Object.keys(arg).length > 0 && - (requiredAttributes.length === 0 || - requiredAttributes.every((d) => ({}.hasOwnProperty.call(arg, d)))) - ); -}; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; /** * Get the first key in the object diff --git a/x-pack/plugins/ml/common/util/query_utils.ts b/x-pack/plugins/ml/common/util/query_utils.ts index 22c0f45f2f239..5ceda44fa44b3 100644 --- a/x-pack/plugins/ml/common/util/query_utils.ts +++ b/x-pack/plugins/ml/common/util/query_utils.ts @@ -7,7 +7,7 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { cloneDeep } from 'lodash'; -import { isPopulatedObject } from './object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export const addExcludeFrozenToQuery = (originalQuery: QueryDslQueryContainer | undefined) => { const FROZEN_TIER_TERM = { diff --git a/x-pack/plugins/ml/common/util/runtime_field_utils.ts b/x-pack/plugins/ml/common/util/runtime_field_utils.ts index 6b2cb78d73274..10179d5e51732 100644 --- a/x-pack/plugins/ml/common/util/runtime_field_utils.ts +++ b/x-pack/plugins/ml/common/util/runtime_field_utils.ts @@ -6,7 +6,7 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { RUNTIME_FIELD_TYPES } from '@kbn/data-plugin/common'; -import { isPopulatedObject } from './object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; type RuntimeType = typeof RUNTIME_FIELD_TYPES[number]; diff --git a/x-pack/plugins/ml/common/util/string_utils.test.ts b/x-pack/plugins/ml/common/util/string_utils.test.ts index 52a3c10da8b5a..43acc80110001 100644 --- a/x-pack/plugins/ml/common/util/string_utils.test.ts +++ b/x-pack/plugins/ml/common/util/string_utils.test.ts @@ -5,12 +5,7 @@ * 2.0. */ -import { - renderTemplate, - getMedianStringLength, - stringHash, - getGroupQueryText, -} from './string_utils'; +import { renderTemplate, getMedianStringLength, getGroupQueryText } from './string_utils'; const strings: string[] = [ 'foo', @@ -53,14 +48,6 @@ describe('ML - string utils', () => { }); }); - describe('stringHash', () => { - test('should return a unique number based off a string', () => { - const hash1 = stringHash('the-string-1'); - const hash2 = stringHash('the-string-2'); - expect(hash1).not.toBe(hash2); - }); - }); - describe('getGroupQueryText', () => { const groupIdOne = 'test_group_id_1'; const groupIdTwo = 'test_group_id_2'; diff --git a/x-pack/plugins/ml/common/util/string_utils.ts b/x-pack/plugins/ml/common/util/string_utils.ts index 044b34d166a87..d55d007ceb225 100644 --- a/x-pack/plugins/ml/common/util/string_utils.ts +++ b/x-pack/plugins/ml/common/util/string_utils.ts @@ -24,23 +24,6 @@ export function getMedianStringLength(strings: string[]) { return sortedStringLengths[Math.floor(sortedStringLengths.length / 2)] || 0; } -/** - * Creates a deterministic number based hash out of a string. - */ -export function stringHash(str: string): number { - let hash = 0; - let chr = 0; - if (str.length === 0) { - return hash; - } - for (let i = 0; i < str.length; i++) { - chr = str.charCodeAt(i); - hash = (hash << 5) - hash + chr; // eslint-disable-line no-bitwise - hash |= 0; // eslint-disable-line no-bitwise - } - return hash < 0 ? hash * -2 : hash; -} - export function getGroupQueryText(groupIds: string[]): string { return `groups:(${groupIds.join(' or ')})`; } diff --git a/x-pack/plugins/ml/common/util/validators.ts b/x-pack/plugins/ml/common/util/validators.ts index 0936efbcb00fc..b28e120b1f196 100644 --- a/x-pack/plugins/ml/common/util/validators.ts +++ b/x-pack/plugins/ml/common/util/validators.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { ALLOWED_DATA_UNITS } from '../constants/validation'; import { parseInterval } from './parse_interval'; -import { isPopulatedObject } from './object_utils'; /** * Provides a validator function for maximum allowed input length. diff --git a/x-pack/plugins/ml/public/alerting/jobs_health_rule/anomaly_detection_jobs_health_rule_trigger.tsx b/x-pack/plugins/ml/public/alerting/jobs_health_rule/anomaly_detection_jobs_health_rule_trigger.tsx index dcbf580461e0f..1b88b38788554 100644 --- a/x-pack/plugins/ml/public/alerting/jobs_health_rule/anomaly_detection_jobs_health_rule_trigger.tsx +++ b/x-pack/plugins/ml/public/alerting/jobs_health_rule/anomaly_detection_jobs_health_rule_trigger.tsx @@ -11,13 +11,13 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import useDebounce from 'react-use/lib/useDebounce'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { MlAnomalyDetectionJobsHealthRuleParams } from '../../../common/types/alerts'; import { JobSelectorControl } from '../job_selector'; import { jobsApiProvider } from '../../application/services/ml_api_service/jobs'; import { HttpService } from '../../application/services/http_service'; import { useMlKibana } from '../../application/contexts/kibana'; import { TestsSelectionControl } from './tests_selection_control'; -import { isPopulatedObject } from '../../../common'; import { ALL_JOBS_SELECTION } from '../../../common/constants/alerts'; import { BetaBadge } from '../beta_badge'; import { isDefined } from '../../../common/types/guards'; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx b/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx index 82ae725038387..3edc757c11846 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx +++ b/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx @@ -27,6 +27,7 @@ import { } from '@elastic/eui'; import { CoreSetup } from '@kbn/core/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { DEFAULT_SAMPLER_SHARD_SIZE } from '../../../../common/constants/field_histograms'; import { ANALYSIS_CONFIG_TYPE, INDEX_STATUS } from '../../data_frame_analytics/common'; @@ -44,7 +45,6 @@ import { FeatureImportance, TopClasses, } from '../../../../common/types/feature_importance'; -import { isPopulatedObject } from '../../../../common/util/object_utils'; import { DEFAULT_RESULTS_FIELD } from '../../../../common/constants/data_frame_analytics'; import { DataFrameAnalysisConfigType } from '../../../../common/types/data_frame_analytics'; diff --git a/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts b/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts index c83836164221d..edaa2c30662b1 100644 --- a/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts +++ b/x-pack/plugins/ml/public/application/components/full_time_range_selector/full_time_range_selector_service.ts @@ -11,9 +11,9 @@ import { i18n } from '@kbn/i18n'; import dateMath from '@kbn/datemath'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import type { DataView } from '@kbn/data-views-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { getTimefilter, getToastNotifications } from '../../util/dependency_cache'; import { ml, GetTimeFieldRangeResponse } from '../../services/ml_api_service'; -import { isPopulatedObject } from '../../../../common/util/object_utils'; import type { RuntimeMappings } from '../../../../common/types/fields'; import { addExcludeFrozenToQuery } from '../../../../common/util/query_utils'; diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx index b93ba79830f98..e11de5fea47d3 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx @@ -25,9 +25,9 @@ import { import { i18n } from '@kbn/i18n'; import { DataView } from '@kbn/data-views-plugin/public'; +import { stringHash } from '@kbn/ml-string-hash'; import { extractErrorMessage } from '../../../../common'; import { isRuntimeMappings } from '../../../../common/util/runtime_field_utils'; -import { stringHash } from '../../../../common/util/string_utils'; import { RuntimeMappings } from '../../../../common/types/fields'; import type { ResultsSearchQuery } from '../../data_frame_analytics/common/analytics'; import { getCombinedRuntimeMappings } from '../data_grid'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/runtime_mappings/runtime_mappings.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/runtime_mappings/runtime_mappings.tsx index 9de32fdd5bd3e..962a06410ca50 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/runtime_mappings/runtime_mappings.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/runtime_mappings/runtime_mappings.tsx @@ -21,10 +21,10 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { XJsonMode } from '@kbn/ace'; import { XJson } from '@kbn/es-ui-shared-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { useMlContext } from '../../../../../contexts/ml'; import { CreateAnalyticsFormProps } from '../../../analytics_management/hooks/use_create_analytics_form'; import { getCombinedRuntimeMappings } from '../../../../../components/data_grid/common'; -import { isPopulatedObject } from '../../../../../../../common/util/object_utils'; import { RuntimeMappingsEditor } from './runtime_mappings_editor'; import { isRuntimeMappings } from '../../../../../../../common'; import { SwitchModal } from './switch_modal'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/hooks/use_exploration_url_state.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/hooks/use_exploration_url_state.ts index dac1a85211c20..1a26cce465d85 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/hooks/use_exploration_url_state.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/hooks/use_exploration_url_state.ts @@ -5,11 +5,11 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { usePageUrlState } from '../../../../util/url_state'; import { ML_PAGES } from '../../../../../../common/constants/locator'; import { ExplorationPageUrlState } from '../../../../../../common/types/locator'; import { SEARCH_QUERY_LANGUAGE } from '../../../../../../common/constants/search'; -import { isPopulatedObject } from '../../../../../../common/util/object_utils'; export function getDefaultExplorationPageUrlState( overrides?: Partial diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js index d6926950dce7d..364cdd1be55db 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/utils.js @@ -21,7 +21,7 @@ import { JOB_STATE, DATAFEED_STATE } from '../../../../../common/constants/state import { JOB_ACTION } from '../../../../../common/constants/job_actions'; import { parseInterval } from '../../../../../common/util/parse_interval'; import { mlCalendarService } from '../../../services/calendar_service'; -import { isPopulatedObject } from '../../../../../common/util/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export function loadFullJob(jobId) { return new Promise((resolve, reject) => { diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_utils.ts b/x-pack/plugins/ml/public/application/jobs/jobs_utils.ts index 103f079b88ff3..79952312723fa 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_utils.ts +++ b/x-pack/plugins/ml/public/application/jobs/jobs_utils.ts @@ -6,7 +6,7 @@ */ import { MlJob } from '@elastic/elasticsearch/lib/api/types'; -import { isPopulatedObject } from '../../../common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { MlSummaryJob } from '../../../common/types/anomaly_detection_jobs'; export const isManagedJob = (job: MlSummaryJob | MlJob) => { diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/filter_runtime_mappings.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/filter_runtime_mappings.ts index 9f6f301891741..2f081369ca686 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/filter_runtime_mappings.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/filter_runtime_mappings.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { RuntimeMappings } from '../../../../../../../common/types/fields'; import type { Datafeed, Job } from '../../../../../../../common/types/anomaly_detection_jobs'; -import { isPopulatedObject } from '../../../../../../../common/util/object_utils'; interface Response { runtime_mappings: RuntimeMappings; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx index c370778b178c8..59176d06d92c0 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/recognize/page.tsx @@ -19,6 +19,7 @@ import { } from '@elastic/eui'; import { merge } from 'lodash'; import moment from 'moment'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { useMlKibana, useMlLocator } from '../../../contexts/kibana'; import { ml } from '../../../services/ml_api_service'; import { useMlContext } from '../../../contexts/ml'; @@ -40,7 +41,6 @@ import { JobId } from '../../../../../common/types/anomaly_detection_jobs'; import { ML_PAGES } from '../../../../../common/constants/locator'; import { TIME_FORMAT } from '../../../../../common/constants/time_format'; import { JobsAwaitingNodeWarning } from '../../../components/jobs_awaiting_node_warning'; -import { isPopulatedObject } from '../../../../../common/util/object_utils'; import { RuntimeMappings } from '../../../../../common/types/fields'; import { addExcludeFrozenToQuery } from '../../../../../common/util/query_utils'; import { MlPageHeader } from '../../../components/page_header'; diff --git a/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.ts b/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.ts index 0ed3b511b669e..d1e42dd72ddaf 100644 --- a/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.ts +++ b/x-pack/plugins/ml/public/application/services/anomaly_explorer_charts_service.ts @@ -9,12 +9,12 @@ import { Observable, of } from 'rxjs'; import { map as mapObservable } from 'rxjs/operators'; import type { TimeRange } from '@kbn/es-query'; import type { TimefilterContract } from '@kbn/data-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { RecordForInfluencer } from './results_service/results_service'; import type { EntityField } from '../../../common/util/anomaly_utils'; import type { CombinedJob } from '../../../common/types/anomaly_detection_jobs'; import type { MlApiServices } from './ml_api_service'; import type { MlResultsService } from './results_service'; -import { isPopulatedObject } from '../../../common/util/object_utils'; import { ExplorerChartsData } from '../explorer/explorer_charts/explorer_charts_container_service'; import type { TimeRangeBounds } from '../util/time_buckets'; import { isDefined } from '../../../common/types/guards'; diff --git a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts index cbe4017a02835..38bf80be1ffed 100644 --- a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts +++ b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts @@ -8,6 +8,7 @@ import { IUiSettingsClient } from '@kbn/core/public'; import type { TimeRange } from '@kbn/es-query'; import { TimefilterContract, UI_SETTINGS } from '@kbn/data-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { getBoundsRoundedToInterval, TimeBuckets, @@ -24,7 +25,6 @@ import { OVERALL_LABEL, VIEW_BY_JOB_LABEL } from '../explorer/explorer_constants import { MlResultsService } from './results_service'; import { EntityField } from '../../../common/util/anomaly_utils'; import { InfluencersFilterQuery } from '../../../common/types/es_client'; -import { isPopulatedObject } from '../../../common'; /** * Service for retrieving anomaly swim lanes data. diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts index d15c500ddb9c4..201ed34e42654 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/trained_models.ts @@ -48,7 +48,7 @@ export interface InferenceStatsResponse { } export interface MlInferTrainedModelDeploymentResponse { - inference_results: estypes.MlInferTrainedModelDeploymentResponse[]; + inference_results: estypes.MlInferenceResponseResult[]; } /** diff --git a/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts b/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts index 54dece80f22cf..d5da658755943 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts +++ b/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts @@ -15,6 +15,7 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { each, get } from 'lodash'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { Dictionary } from '../../../../common/types/common'; import { ML_MEDIAN_PERCENTS } from '../../../../common/util/job_utils'; import { Datafeed, JobId } from '../../../../common/types/anomaly_detection_jobs'; @@ -24,7 +25,6 @@ import { findAggField } from '../../../../common/util/validation_utils'; import { getDatafeedAggregations } from '../../../../common/util/datafeed_utils'; import { aggregationTypeTransform, EntityField } from '../../../../common/util/anomaly_utils'; import { ES_AGGREGATION } from '../../../../common/constants/aggregation_types'; -import { isPopulatedObject } from '../../../../common/util/object_utils'; import { InfluencersFilterQuery } from '../../../../common/types/es_client'; import { RecordForInfluencer } from './results_service'; import { isRuntimeMappings } from '../../../../common'; diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.js b/x-pack/plugins/ml/public/application/services/results_service/results_service.js index bb6f6b5969ac4..b26e52f5f32f2 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/results_service.js +++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.js @@ -7,6 +7,8 @@ import { each, get } from 'lodash'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + import { ML_MEDIAN_PERCENTS } from '../../../../common/util/job_utils'; import { escapeForElasticsearchQuery } from '../../util/string_utils'; import { @@ -14,7 +16,6 @@ import { SWIM_LANE_DEFAULT_PAGE_SIZE, } from '../../explorer/explorer_constants'; import { aggregationTypeTransform } from '../../../../common/util/anomaly_utils'; -import { isPopulatedObject } from '../../../../common/util/object_utils'; /** * Service for carrying out Elasticsearch queries to obtain data for the Ml Results dashboards. diff --git a/x-pack/plugins/ml/public/application/trained_models/models_management/expanded_row.tsx b/x-pack/plugins/ml/public/application/trained_models/models_management/expanded_row.tsx index 8b868a088499d..6ab9261213d56 100644 --- a/x-pack/plugins/ml/public/application/trained_models/models_management/expanded_row.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/expanded_row.tsx @@ -23,9 +23,9 @@ import { import type { EuiDescriptionListProps } from '@elastic/eui/src/components/description_list/description_list'; import { FormattedMessage } from '@kbn/i18n-react'; import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { ModelItemFull } from './models_list'; import { isDefined } from '../../../../common/types/guards'; -import { isPopulatedObject } from '../../../../common'; import { ModelPipelines } from './pipelines'; import { AllocatedModels } from '../nodes_overview/allocated_models'; import type { AllocatedModel } from '../../../../common/types/trained_models'; diff --git a/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx b/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx index 4f3cef2eeda12..07b1e876d4120 100644 --- a/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/models_list.tsx @@ -26,6 +26,7 @@ import { EuiBasicTableColumn } from '@elastic/eui/src/components/basic_table/bas import { EuiTableSelectionType } from '@elastic/eui/src/components/basic_table/table_types'; import { Action } from '@elastic/eui/src/components/basic_table/action_types'; import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { getAnalysisType } from '../../data_frame_analytics/common'; import { ModelsTableToConfigMapping } from '.'; import { ModelsBarStats, StatsBar } from '../../components/stats_bar'; @@ -44,7 +45,6 @@ import { ML_PAGES } from '../../../../common/constants/locator'; import { ListingPageUrlState } from '../../../../common/types/common'; import { usePageUrlState } from '../../util/url_state'; import { ExpandedRow } from './expanded_row'; -import { isPopulatedObject } from '../../../../common'; import { useTableSettings } from '../../data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings'; import { useToastNotificationService } from '../../services/toast_notification_service'; import { useFieldFormatter } from '../../contexts/kibana/use_field_formatter'; diff --git a/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/inference_base.ts b/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/inference_base.ts index e3b502a10f6ce..ed1d8fdacbca4 100644 --- a/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/inference_base.ts +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/inference_base.ts @@ -74,17 +74,17 @@ export abstract class InferenceBase { protected abstract infer(): Promise; - protected getInferenceConfig(): estypes.AggregationsClassificationInferenceOptions | undefined { + protected getInferenceConfig(): estypes.MlInferenceConfigCreateContainer[keyof estypes.MlInferenceConfigCreateContainer] { return this.model.inference_config[ - this.inferenceType as keyof estypes.AggregationsInferenceConfigContainer + this.inferenceType as keyof estypes.MlInferenceConfigCreateContainer ]; } protected getNumTopClassesConfig(defaultOverride = 5) { - const options: estypes.AggregationsClassificationInferenceOptions | undefined = + const options: estypes.MlInferenceConfigCreateContainer[keyof estypes.MlInferenceConfigCreateContainer] = this.getInferenceConfig(); - if (options?.num_top_classes !== undefined && options?.num_top_classes > 0) { + if (options && 'num_top_classes' in options && (options?.num_top_classes ?? 0 > 0)) { return {}; } diff --git a/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/text_classification/common.ts b/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/text_classification/common.ts index ab136900c7d1e..6592e44800d14 100644 --- a/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/text_classification/common.ts +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/models/text_classification/common.ts @@ -39,9 +39,7 @@ export function processResponse( const { inference_results: [inferenceResults], } = resp; - const labels: string[] = - // @ts-expect-error inference config is wrong - model.inference_config.text_classification?.classification_labels ?? []; + const labels: string[] = model.inference_config.text_classification?.classification_labels ?? []; let formattedResponse = [ { diff --git a/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/utils.ts b/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/utils.ts index 3ac6ec77f576a..e340170ce46ce 100644 --- a/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/utils.ts +++ b/x-pack/plugins/ml/public/application/trained_models/models_management/test_models/utils.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { TRAINED_MODEL_TYPE, DEPLOYMENT_STATE, @@ -13,8 +14,6 @@ import { import type { SupportedPytorchTasksType } from '../../../../../common/constants/trained_models'; import type { ModelItem } from '../models_list'; -import { isPopulatedObject } from '../../../../../common'; - const PYTORCH_TYPES = Object.values(SUPPORTED_PYTORCH_TASKS); export function isTestable(modelItem: ModelItem) { diff --git a/x-pack/plugins/ml/public/application/util/url_state.tsx b/x-pack/plugins/ml/public/application/util/url_state.tsx index 42d5c012b9c14..a31b574681827 100644 --- a/x-pack/plugins/ml/public/application/util/url_state.tsx +++ b/x-pack/plugins/ml/public/application/util/url_state.tsx @@ -21,11 +21,11 @@ import { useHistory, useLocation } from 'react-router-dom'; import { BehaviorSubject, Observable } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { Dictionary } from '../../../common/types/common'; import { getNestedProperty } from './object_utils'; import { MlPages } from '../../../common/constants/locator'; -import { isPopulatedObject } from '../../../common'; type Accessor = '_a' | '_g'; export type SetUrlState = ( diff --git a/x-pack/plugins/ml/public/embeddables/types.ts b/x-pack/plugins/ml/public/embeddables/types.ts index 2ba4af15f7466..6a990db33398a 100644 --- a/x-pack/plugins/ml/public/embeddables/types.ts +++ b/x-pack/plugins/ml/public/embeddables/types.ts @@ -10,6 +10,7 @@ import type { Filter, Query, TimeRange } from '@kbn/es-query'; import type { RefreshInterval } from '@kbn/data-plugin/common'; import type { EmbeddableInput, EmbeddableOutput, IEmbeddable } from '@kbn/embeddable-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { JobId } from '../../common/types/anomaly_detection_jobs'; import type { SwimlaneType } from '../application/explorer/explorer_constants'; import type { AnomalyDetectorService } from '../application/services/anomaly_detector_service'; @@ -18,7 +19,6 @@ import type { MlDependencies } from '../application/app'; import type { AppStateSelectedCells } from '../application/explorer/explorer_utils'; import { AnomalyExplorerChartsService } from '../application/services/anomaly_explorer_charts_service'; import { EntityField } from '../../common/util/anomaly_utils'; -import { isPopulatedObject } from '../../common/util/object_utils'; import { ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, diff --git a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts index 808c77d4d6ea5..a54bad9d886fe 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts @@ -494,7 +494,7 @@ export function getMlClient( await modelIdsCheck(p); return mlClient.stopTrainedModelDeployment(...p); }, - async inferTrainedModelDeployment(...p: Parameters) { + async inferTrainedModel(...p: Parameters) { await modelIdsCheck(p); // Temporary workaround for the incorrect inferTrainedModelDeployment function in the esclient if ( diff --git a/x-pack/plugins/ml/server/lib/query_utils.test.ts b/x-pack/plugins/ml/server/lib/query_utils.test.ts index a83265ed1262f..c505a8a9b1fa8 100644 --- a/x-pack/plugins/ml/server/lib/query_utils.test.ts +++ b/x-pack/plugins/ml/server/lib/query_utils.test.ts @@ -5,11 +5,7 @@ * 2.0. */ -import { - buildBaseFilterCriteria, - buildSamplerAggregation, - getSamplerAggregationsResponsePath, -} from './query_utils'; +import { buildBaseFilterCriteria } from './query_utils'; describe('ML - query utils', () => { describe('buildBaseFilterCriteria', () => { @@ -52,37 +48,4 @@ describe('ML - query utils', () => { ]); }); }); - - describe('buildSamplerAggregation', () => { - const testAggs = { - bytes_stats: { - stats: { field: 'bytes' }, - }, - }; - - test('returns wrapped sampler aggregation for sampler shard size of 1000', () => { - expect(buildSamplerAggregation(testAggs, 1000)).toEqual({ - sample: { - sampler: { - shard_size: 1000, - }, - aggs: testAggs, - }, - }); - }); - - test('returns un-sampled aggregation as-is for sampler shard size of 0', () => { - expect(buildSamplerAggregation(testAggs, 0)).toEqual(testAggs); - }); - }); - - describe('getSamplerAggregationsResponsePath', () => { - test('returns correct path for sampler shard size of 1000', () => { - expect(getSamplerAggregationsResponsePath(1000)).toEqual(['sample']); - }); - - test('returns correct path for sampler shard size of 0', () => { - expect(getSamplerAggregationsResponsePath(0)).toEqual([]); - }); - }); }); diff --git a/x-pack/plugins/ml/server/lib/query_utils.ts b/x-pack/plugins/ml/server/lib/query_utils.ts index cfaa5abaf7f23..a60622583781b 100644 --- a/x-pack/plugins/ml/server/lib/query_utils.ts +++ b/x-pack/plugins/ml/server/lib/query_utils.ts @@ -5,7 +5,6 @@ * 2.0. */ -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; /* * Contains utility functions for building and processing queries. */ @@ -37,32 +36,3 @@ export function buildBaseFilterCriteria( return filterCriteria; } - -// Wraps the supplied aggregations in a sampler aggregation. -// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation) -// of less than 1 indicates no sampling, and the aggs are returned as-is. -export function buildSamplerAggregation( - aggs: any, - samplerShardSize: number -): Record { - if (samplerShardSize < 1) { - return aggs; - } - - return { - sample: { - sampler: { - shard_size: samplerShardSize, - }, - aggs, - }, - }; -} - -// Returns the path of aggregations in the elasticsearch response, as an array, -// depending on whether sampling is being used. -// A supplied samplerShardSize (the shard_size parameter of the sampler aggregation) -// of less than 1 indicates no sampling, and an empty array is returned. -export function getSamplerAggregationsResponsePath(samplerShardSize: number): string[] { - return samplerShardSize > 0 ? ['sample'] : []; -} diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts index 4ee77f06eac1f..1f6bb64fd76f4 100644 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/models_provider.ts @@ -112,7 +112,6 @@ export function modelsProvider(client: IScopedClusterClient, mlClient: MlClient) */ async getNodesOverview(): Promise { // TODO set node_id to ml:true when elasticsearch client is updated. - // @ts-expect-error typo in type definition: MlGetMemoryStatsResponse.cluser_name const response = (await mlClient.getMemoryStats()) as MemoryStatsResponse; const { trained_model_stats: trainedModelStats } = await mlClient.getTrainedModelsStats({ diff --git a/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts b/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts index 9bf107106a056..7060d935b0fef 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts +++ b/x-pack/plugins/ml/server/models/data_recognizer/data_recognizer.ts @@ -17,6 +17,7 @@ import type { import moment from 'moment'; import { merge } from 'lodash'; import type { DataViewsService } from '@kbn/data-views-plugin/common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { AnalysisLimits } from '../../../common/types/anomaly_detection_jobs'; import { getAuthorizationHeader } from '../../lib/request_authorization'; import type { MlClient } from '../../lib/ml_client'; @@ -54,7 +55,6 @@ import type { JobExistResult, JobStat } from '../../../common/types/data_recogni import type { Datafeed } from '../../../common/types/anomaly_detection_jobs'; import type { MLSavedObjectService } from '../../saved_objects'; import { isDefined } from '../../../common/types/guards'; -import { isPopulatedObject } from '../../../common/util/object_utils'; const ML_DIR = 'ml'; const KIBANA_DIR = 'kibana'; diff --git a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts index bbfc43257caf5..6946a2fbda90f 100644 --- a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts +++ b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts @@ -5,21 +5,23 @@ * 2.0. */ -import { IScopedClusterClient } from '@kbn/core/server'; import { get, each, last, find } from 'lodash'; + +import { IScopedClusterClient } from '@kbn/core/server'; import { KBN_FIELD_TYPES } from '@kbn/data-plugin/server'; -import { ML_JOB_FIELD_TYPES } from '../../../common/constants/field_types'; -import { getSafeAggregationName } from '../../../common/util/job_utils'; -import { stringHash } from '../../../common/util/string_utils'; import { - buildBaseFilterCriteria, buildSamplerAggregation, + getAggIntervals, getSamplerAggregationsResponsePath, -} from '../../lib/query_utils'; +} from '@kbn/ml-agg-utils'; +import { stringHash } from '@kbn/ml-string-hash'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; +import { ML_JOB_FIELD_TYPES } from '../../../common/constants/field_types'; +import { getSafeAggregationName } from '../../../common/util/job_utils'; +import { buildBaseFilterCriteria } from '../../lib/query_utils'; import { AggCardinality, RuntimeMappings } from '../../../common/types/fields'; import { getDatafeedAggregations } from '../../../common/util/datafeed_utils'; import { Datafeed } from '../../../common/types/anomaly_detection_jobs'; -import { isPopulatedObject } from '../../../common/util/object_utils'; const SAMPLER_TOP_TERMS_THRESHOLD = 100000; const SAMPLER_TOP_TERMS_SHARD_SIZE = 5000; @@ -112,13 +114,6 @@ interface FieldExamples { examples: any[]; } -interface NumericColumnStats { - interval: number; - min: number; - max: number; -} -type NumericColumnStatsMap = Record; - interface AggHistogram { histogram: { field: string; @@ -178,67 +173,6 @@ type BatchStats = | DocumentCountStats | FieldExamples; -const getAggIntervals = async ( - { asCurrentUser }: IScopedClusterClient, - indexPattern: string, - query: any, - fields: HistogramField[], - samplerShardSize: number, - runtimeMappings?: RuntimeMappings -): Promise => { - const numericColumns = fields.filter((field) => { - return field.type === KBN_FIELD_TYPES.NUMBER || field.type === KBN_FIELD_TYPES.DATE; - }); - - if (numericColumns.length === 0) { - return {}; - } - - const minMaxAggs = numericColumns.reduce((aggs, c) => { - const id = stringHash(c.fieldName); - aggs[id] = { - stats: { - field: c.fieldName, - }, - }; - return aggs; - }, {} as Record); - - const body = await asCurrentUser.search( - { - index: indexPattern, - size: 0, - body: { - query, - aggs: buildSamplerAggregation(minMaxAggs, samplerShardSize), - size: 0, - ...(isPopulatedObject(runtimeMappings) ? { runtime_mappings: runtimeMappings } : {}), - }, - }, - { maxRetries: 0 } - ); - - const aggsPath = getSamplerAggregationsResponsePath(samplerShardSize); - const aggregations = aggsPath.length > 0 ? get(body.aggregations, aggsPath) : body.aggregations; - - return Object.keys(aggregations).reduce((p, aggName) => { - const stats = [aggregations[aggName].min, aggregations[aggName].max]; - if (!stats.includes(null)) { - const delta = aggregations[aggName].max - aggregations[aggName].min; - - let aggInterval = 1; - - if (delta > MAX_CHART_COLUMNS || delta <= 1) { - aggInterval = delta / (MAX_CHART_COLUMNS - 1); - } - - p[aggName] = { interval: aggInterval, min: stats[0], max: stats[1] }; - } - - return p; - }, {} as NumericColumnStatsMap); -}; - // export for re-use by transforms plugin export const getHistogramsForFields = async ( client: IScopedClusterClient, @@ -250,7 +184,7 @@ export const getHistogramsForFields = async ( ) => { const { asCurrentUser } = client; const aggIntervals = await getAggIntervals( - client, + client.asCurrentUser, indexPattern, query, fields, diff --git a/x-pack/plugins/ml/server/models/fields_service/fields_service.ts b/x-pack/plugins/ml/server/models/fields_service/fields_service.ts index 64348a0656009..fd661063bde5f 100644 --- a/x-pack/plugins/ml/server/models/fields_service/fields_service.ts +++ b/x-pack/plugins/ml/server/models/fields_service/fields_service.ts @@ -8,6 +8,7 @@ import Boom from '@hapi/boom'; import { IScopedClusterClient } from '@kbn/core/server'; import { duration } from 'moment'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { parseInterval } from '../../../common/util/parse_interval'; import { initCardinalityFieldsCache } from './fields_aggs_cache'; import { AggCardinality } from '../../../common/types/fields'; @@ -15,7 +16,6 @@ import { isValidAggregationField } from '../../../common/util/validation_utils'; import { getDatafeedAggregations } from '../../../common/util/datafeed_utils'; import { Datafeed, IndicesOptions } from '../../../common/types/anomaly_detection_jobs'; import { RuntimeMappings } from '../../../common/types/fields'; -import { isPopulatedObject } from '../../../common/util/object_utils'; /** * Service for carrying out queries to obtain data diff --git a/x-pack/plugins/ml/server/models/job_service/jobs.ts b/x-pack/plugins/ml/server/models/job_service/jobs.ts index 1ffa9687fca95..f3cb4c584f27f 100644 --- a/x-pack/plugins/ml/server/models/job_service/jobs.ts +++ b/x-pack/plugins/ml/server/models/job_service/jobs.ts @@ -9,6 +9,7 @@ import { uniq } from 'lodash'; import Boom from '@hapi/boom'; import { IScopedClusterClient } from '@kbn/core/server'; import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { getSingleMetricViewerJobErrorMessage, parseTimeIntervalForJob, @@ -47,7 +48,6 @@ import { } from '../../../common/util/job_utils'; import { groupsProvider } from './groups'; import type { MlClient } from '../../lib/ml_client'; -import { isPopulatedObject } from '../../../common/util/object_utils'; import { ML_ALERT_TYPES } from '../../../common/constants/alerts'; import { MlAnomalyDetectionAlertParams } from '../../routes/schemas/alerting_schema'; import type { AuthorizationHeader } from '../../lib/request_authorization'; diff --git a/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts b/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts index dd7e2b3373e89..9456e529eb039 100644 --- a/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts +++ b/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts @@ -10,8 +10,9 @@ import { i18n } from '@kbn/i18n'; import { each, find, get, keyBy, map, reduce, sortBy } from 'lodash'; import type * as estypes from '@elastic/elasticsearch/lib/api/types'; import { extent, max, min } from 'd3'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { MlClient } from '../../lib/ml_client'; -import { isPopulatedObject, isRuntimeMappings } from '../../../common'; +import { isRuntimeMappings } from '../../../common'; import type { MetricData, ModelPlotOutput, diff --git a/x-pack/plugins/ml/server/routes/trained_models.ts b/x-pack/plugins/ml/server/routes/trained_models.ts index 849d3b04d8cef..1fcfe4e1fa05e 100644 --- a/x-pack/plugins/ml/server/routes/trained_models.ts +++ b/x-pack/plugins/ml/server/routes/trained_models.ts @@ -377,7 +377,7 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) routeGuard.fullLicenseAPIGuard(async ({ mlClient, request, response }) => { try { const { modelId } = request.params; - const body = await mlClient.inferTrainedModelDeployment({ + const body = await mlClient.inferTrainedModel({ model_id: modelId, body: { docs: request.body.docs, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts b/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts index 825cabc723294..5baf6e11c4082 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts @@ -56,11 +56,37 @@ export const monitoredClustersQuery = ({ timeRange, timeout }: QueryOptions) => }; /** - * some metricset documents use a stable ID to maintain a single occurence of + * some metricset documents use a stable ID to maintain a single occurrence of * the documents in the index. we query those metricsets separately without * a time range filter */ export const persistentMetricsetsQuery = ({ timeout }: QueryOptions) => { + const shardMatches = [ + { + term: { + type: 'shards', + }, + }, + { + term: { + 'metricset.name': 'shard', + }, + }, + ]; + + const logstashStateMatches = [ + { + term: { + type: 'logstash_state', + }, + }, + { + term: { + 'metricset.name': 'node', + }, + }, + ]; + const metricsetsAggregations = { elasticsearch: { terms: { @@ -71,18 +97,7 @@ export const persistentMetricsetsQuery = ({ timeout }: QueryOptions) => { shard: lastSeenByIndex({ filter: { bool: { - should: [ - { - term: { - type: 'shards', - }, - }, - { - term: { - 'metricset.name': 'shard', - }, - }, - ], + should: shardMatches, }, }, }), @@ -98,18 +113,7 @@ export const persistentMetricsetsQuery = ({ timeout }: QueryOptions) => { node: lastSeenByIndex({ filter: { bool: { - should: [ - { - term: { - type: 'logstash_state', - }, - }, - { - term: { - 'metricset.name': 'node', - }, - }, - ], + should: logstashStateMatches, }, }, }), @@ -117,8 +121,20 @@ export const persistentMetricsetsQuery = ({ timeout }: QueryOptions) => { }, }; + // Outer query on expected types to avoid catching kibana internal collection documents containing source_node.uuid return { timeout: `${timeout}s`, + query: { + bool: { + filter: [ + { + bool: { + should: shardMatches.concat(logstashStateMatches), + }, + }, + ], + }, + }, aggs: { clusters: { terms: clusterUuidTerm, diff --git a/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx b/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx index 2ecaca0eb3e81..c3f02684ab879 100644 --- a/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx +++ b/x-pack/plugins/observability/public/config/register_alerts_table_configuration.tsx @@ -6,7 +6,6 @@ */ import type { - AlertsTableConfigurationRegistryContract, AlertTableFlyoutComponent, GetRenderCellValue, } from '@kbn/triggers-actions-ui-plugin/public'; @@ -27,20 +26,15 @@ const AlertsFlyoutFooterLazy = lazy( () => import('../pages/alerts/components/alerts_flyout/alerts_flyout_footer') ); -const registerAlertsTableConfiguration = (registry: AlertsTableConfigurationRegistryContract) => { - if (registry.has(observabilityFeatureId)) { - return; - } - registry.register({ - id: observabilityFeatureId, - columns: alertO11yColumns.map(addDisplayNames), - externalFlyout: { - header: AlertsPageFlyoutHeaderLazy as AlertTableFlyoutComponent, - body: AlertsPageFlyoutBodyLazy as AlertTableFlyoutComponent, - footer: AlertsFlyoutFooterLazy as AlertTableFlyoutComponent, - }, - getRenderCellValue: getRenderCellValue as GetRenderCellValue, - }); -}; +const getO11yAlertsTableConfiguration = () => ({ + id: observabilityFeatureId, + columns: alertO11yColumns.map(addDisplayNames), + externalFlyout: { + header: AlertsPageFlyoutHeaderLazy as AlertTableFlyoutComponent, + body: AlertsPageFlyoutBodyLazy as AlertTableFlyoutComponent, + footer: AlertsFlyoutFooterLazy as AlertTableFlyoutComponent, + }, + getRenderCellValue: getRenderCellValue as GetRenderCellValue, +}); -export { registerAlertsTableConfiguration }; +export { getO11yAlertsTableConfiguration }; diff --git a/x-pack/plugins/observability/public/hooks/use_es_search.ts b/x-pack/plugins/observability/public/hooks/use_es_search.ts index 2215d31c838fb..493260a3bbb6e 100644 --- a/x-pack/plugins/observability/public/hooks/use_es_search.ts +++ b/x-pack/plugins/observability/public/hooks/use_es_search.ts @@ -9,7 +9,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { ESSearchResponse } from '@kbn/core/types/elasticsearch'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { IInspectorInfo, isCompleteResponse } from '@kbn/data-plugin/common'; +import { IInspectorInfo, isCompleteResponse, isErrorResponse } from '@kbn/data-plugin/common'; import { FETCH_STATUS, useFetcher } from './use_fetcher'; import { useInspectorContext } from '../context/inspector/use_inspector_context'; import { getInspectResponse } from '../../common/utils/get_inspect_response'; @@ -69,6 +69,34 @@ export const useEsSearch = { + if (isErrorResponse(err)) { + console.error(err); + if (addInspectorRequest) { + addInspectorRequest({ + data: { + _inspect: [ + getInspectResponse({ + startTime, + esRequestParams: params, + esResponse: null, + esError: { originalError: err, name: err.name, message: err.message }, + esRequestStatus: 2, + operationName: name, + kibanaRequest: { + route: { + path: '/internal/bsearch', + method: 'POST', + }, + } as any, + }), + ], + }, + status: FETCH_STATUS.SUCCESS, + }); + } + } + }, }); }); } diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index d0c7cf3dbad45..20d87b1da4b32 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -144,12 +144,6 @@ export class Plugin // Get start services const [coreStart, pluginsStart, { navigation }] = await coreSetup.getStartServices(); - // Register alerts metadata - const { registerAlertsTableConfiguration } = await import( - './config/register_alerts_table_configuration' - ); - const { alertsTableConfigurationRegistry } = pluginsStart.triggersActionsUi; - registerAlertsTableConfiguration(alertsTableConfigurationRegistry); // The `/api/features` endpoint requires the "Global All" Kibana privilege. Users with a // subset of this privilege are not authorized to access this endpoint and will receive a 404 // error that causes the Alerting view to fail to load. @@ -288,6 +282,18 @@ export class Plugin getSharedUXContext: pluginsStart.sharedUX.getContextServices, }); + const getAsyncO11yAlertsTableConfiguration = async () => { + const { getO11yAlertsTableConfiguration } = await import( + './config/register_alerts_table_configuration' + ); + return getO11yAlertsTableConfiguration(); + }; + + const { alertsTableConfigurationRegistry } = pluginsStart.triggersActionsUi; + getAsyncO11yAlertsTableConfiguration().then((config) => { + alertsTableConfigurationRegistry.register(config); + }); + return { navigation: { PageTemplate, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx index ffe5417616dd9..f3b63bf32b5ff 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiAccordion } from '@elastic/eui'; +import { EuiAccordion, EuiIconTip } from '@elastic/eui'; import React from 'react'; import type { KibanaFeature, SubFeatureConfig } from '@kbn/features-plugin/public'; @@ -33,11 +33,14 @@ interface TestConfig { calculateDisplayedPrivileges: boolean; canCustomizeSubFeaturePrivileges: boolean; } + const setup = (config: TestConfig) => { const kibanaPrivileges = createKibanaPrivileges(config.features, { allowSubFeaturePrivileges: config.canCustomizeSubFeaturePrivileges, }); + const calculator = new PrivilegeFormCalculator(kibanaPrivileges, config.role); + const onChange = jest.fn(); const onChangeAll = jest.fn(); const wrapper = mountWithIntl( @@ -120,6 +123,7 @@ describe('FeatureTable', () => { feature: {}, }, ]); + const { displayedPrivileges } = setup({ role, features: kibanaFeatures, @@ -127,6 +131,7 @@ describe('FeatureTable', () => { calculateDisplayedPrivileges: true, canCustomizeSubFeaturePrivileges, }); + expect(displayedPrivileges).toEqual({ excluded_from_base: { primaryFeaturePrivilege: 'none', @@ -271,6 +276,7 @@ describe('FeatureTable', () => { }, }, ]); + const { displayedPrivileges } = setup({ role, features: kibanaFeatures, @@ -312,6 +318,7 @@ describe('FeatureTable', () => { feature: {}, }, ]); + const { wrapper } = setup({ role, features: kibanaFeatures, @@ -325,6 +332,7 @@ describe('FeatureTable', () => { .find(EuiAccordion) .filter(`#featurePrivilegeControls_${feature.id}`) .props(); + if (!feature.subFeatures || feature.subFeatures.length === 0) { expect(arrowDisplay).toEqual('none'); } else { @@ -941,4 +949,334 @@ describe('FeatureTable', () => { `"2 / 2 features granted"` ); }); + + describe('Info Icon Tooltip for Customized Subfeature privileges', () => { + it('should render if there are custom privileges and the accordion is toggled open then toggled closed', () => { + const role = createRole([ + { + spaces: ['foo'], + base: [], + feature: { + unit_test: ['minimal_read', 'sub-toggle-1', 'sub-toggle-2'], + }, + }, + ]); + + const feature = createFeature({ + id: 'unit_test', + name: 'Unit Test Feature', + subFeatures: [ + { + name: 'Some Sub Feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'sub-toggle-1', + name: 'Sub Toggle 1', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-1'], + }, + { + id: 'sub-toggle-2', + name: 'Sub Toggle 2', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-2'], + }, + { + id: 'sub-toggle-3', + name: 'Sub Toggle 3', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-3'], + }, + ], + }, + ], + }, + ] as SubFeatureConfig[], + }); + + const { wrapper } = setup({ + role, + features: [feature], + privilegeIndex: 0, + calculateDisplayedPrivileges: false, + canCustomizeSubFeaturePrivileges: true, + }); + + const categoryExpander = findTestSubject(wrapper, 'featureCategoryButton_foo'); + categoryExpander.simulate('click'); + + const featureExpander = findTestSubject(wrapper, 'featureTableCell'); + featureExpander.simulate('click').simulate('click'); + + const { type } = wrapper.find(EuiIconTip).props(); + + expect(type).toBe('iInCircle'); + }); + + it('should render if there are custom privileges and the accordion has not been toggled (i.e. on load)', () => { + const role = createRole([ + { + spaces: ['foo'], + base: [], + feature: { + unit_test: ['minimal_read', 'sub-toggle-1', 'sub-toggle-2'], + }, + }, + ]); + + const feature = createFeature({ + id: 'unit_test', + name: 'Unit Test Feature', + subFeatures: [ + { + name: 'Some Sub Feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'sub-toggle-1', + name: 'Sub Toggle 1', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-1'], + }, + { + id: 'sub-toggle-2', + name: 'Sub Toggle 2', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-2'], + }, + { + id: 'sub-toggle-3', + name: 'Sub Toggle 3', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-3'], + }, + ], + }, + ], + }, + ] as SubFeatureConfig[], + }); + + const { wrapper } = setup({ + role, + features: [feature], + privilegeIndex: 0, + calculateDisplayedPrivileges: false, + canCustomizeSubFeaturePrivileges: true, + }); + + const { type } = wrapper.find(EuiIconTip).props(); + + expect(type).toBe('iInCircle'); + }); + + it('should not render if there are custom privileges and the accordion is open', () => { + const role = createRole([ + { + spaces: ['foo'], + base: [], + feature: { + unit_test: ['minimal_read', 'sub-toggle-1', 'sub-toggle-2'], + }, + }, + ]); + + const feature = createFeature({ + id: 'unit_test', + name: 'Unit Test Feature', + subFeatures: [ + { + name: 'Some Sub Feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'sub-toggle-1', + name: 'Sub Toggle 1', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-1'], + }, + { + id: 'sub-toggle-2', + name: 'Sub Toggle 2', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-2'], + }, + { + id: 'sub-toggle-3', + name: 'Sub Toggle 3', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-3'], + }, + ], + }, + ], + }, + ] as SubFeatureConfig[], + }); + + const { wrapper } = setup({ + role, + features: [feature], + privilegeIndex: 0, + calculateDisplayedPrivileges: false, + canCustomizeSubFeaturePrivileges: true, + }); + + const categoryExpander = findTestSubject(wrapper, 'featureCategoryButton_foo'); + categoryExpander.simulate('click'); + + const featureExpander = findTestSubject(wrapper, 'featureTableCell'); + featureExpander.simulate('click'); + + const { type } = wrapper.find(EuiIconTip).props(); + + expect(type).toBe('empty'); + }); + + it('should not render if there are NOT custom privileges and the accordion has not been toggled (i.e on load)', () => { + const role = createRole([ + { + spaces: ['foo'], + base: [], + feature: { + unit_test: ['all', 'sub-toggle-1', 'sub-toggle-2', 'sub-toggle-3'], + }, + }, + ]); + + const feature = createFeature({ + id: 'unit_test', + name: 'Unit Test Feature', + subFeatures: [ + { + name: 'Some Sub Feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'sub-toggle-1', + name: 'Sub Toggle 1', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-1'], + }, + { + id: 'sub-toggle-2', + name: 'Sub Toggle 2', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-2'], + }, + { + id: 'sub-toggle-3', + name: 'Sub Toggle 3', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-3'], + }, + ], + }, + ], + }, + ] as SubFeatureConfig[], + }); + + const { wrapper } = setup({ + role, + features: [feature], + privilegeIndex: 0, + calculateDisplayedPrivileges: false, + canCustomizeSubFeaturePrivileges: true, + }); + + const { type } = wrapper.find(EuiIconTip).props(); + + expect(type).toBe('empty'); + }); + + it('should not render if there are NOT custom privileges and the accordion has been toggled open then toggled closed', () => { + const role = createRole([ + { + spaces: ['foo'], + base: [], + feature: { + unit_test: ['all', 'sub-toggle-1', 'sub-toggle-2', 'sub-toggle-3'], + }, + }, + ]); + + const feature = createFeature({ + id: 'unit_test', + name: 'Unit Test Feature', + subFeatures: [ + { + name: 'Some Sub Feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'sub-toggle-1', + name: 'Sub Toggle 1', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-1'], + }, + { + id: 'sub-toggle-2', + name: 'Sub Toggle 2', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-2'], + }, + { + id: 'sub-toggle-3', + name: 'Sub Toggle 3', + includeIn: 'all', + savedObject: { all: [], read: [] }, + ui: ['sub-toggle-3'], + }, + ], + }, + ], + }, + ] as SubFeatureConfig[], + }); + + const { wrapper } = setup({ + role, + features: [feature], + privilegeIndex: 0, + calculateDisplayedPrivileges: false, + canCustomizeSubFeaturePrivileges: true, + }); + + const categoryExpander = findTestSubject(wrapper, 'featureCategoryButton_foo'); + categoryExpander.simulate('click'); + + const featureExpander = findTestSubject(wrapper, 'featureTableCell'); + featureExpander.simulate('click').simulate('click'); + + const { type } = wrapper.find(EuiIconTip).props(); + + expect(type).toBe('empty'); + }); + }); }); diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx index 43d23fa7a584d..a506f8675bc11 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx @@ -48,7 +48,11 @@ interface Props { disabled?: boolean; } -export class FeatureTable extends Component { +interface State { + expandedPrivilegeControls: Set; +} + +export class FeatureTable extends Component { public static defaultProps = { privilegeIndex: -1, showLocks: true, @@ -67,8 +71,11 @@ export class FeatureTable extends Component { if (!this.featureCategories.has(feature.category.id)) { this.featureCategories.set(feature.category.id, []); } + this.featureCategories.get(feature.category.id)!.push(feature); }); + + this.state = { expandedPrivilegeControls: new Set() }; } public render() { @@ -207,14 +214,14 @@ export class FeatureTable extends Component { const renderFeatureMarkup = ( buttonContent: EuiAccordionProps['buttonContent'], extraAction: EuiAccordionProps['extraAction'], - warningIcon: JSX.Element + infoIcon: JSX.Element ) => { const { canCustomizeSubFeaturePrivileges } = this.props; const hasSubFeaturePrivileges = feature.getSubFeaturePrivileges().length > 0; return ( - {warningIcon} + {infoIcon} { arrowDisplay={ canCustomizeSubFeaturePrivileges && hasSubFeaturePrivileges ? 'left' : 'none' } + onToggle={(isOpen: boolean) => { + if (isOpen) { + this.state.expandedPrivilegeControls.add(feature.id); + } else { + this.state.expandedPrivilegeControls.delete(feature.id); + } + + this.setState({ + expandedPrivilegeControls: new Set([...this.state.expandedPrivilegeControls]), + }); + }} >
{ isDisabled: this.props.disabled ?? false, }); - let warningIcon = ; + let infoIcon = ; + + const arePrivilegeControlsCollapsed = !this.state.expandedPrivilegeControls.has(feature.id); + if ( + arePrivilegeControlsCollapsed && this.props.privilegeCalculator.hasCustomizedSubFeaturePrivileges( feature.id, this.props.privilegeIndex, this.props.allSpacesSelected ) ) { - warningIcon = ( + infoIcon = ( { /> ); - return renderFeatureMarkup(buttonContent, extraAction, warningIcon); + return renderFeatureMarkup(buttonContent, extraAction, infoIcon); }; private onChange = (featureId: string) => (featurePrivilegeId: string) => { diff --git a/x-pack/plugins/security_solution/public/resolver/test_utilities/react_wrapper.ts b/x-pack/plugins/security_solution/public/resolver/test_utilities/react_wrapper.ts deleted file mode 100644 index 79205a0420505..0000000000000 --- a/x-pack/plugins/security_solution/public/resolver/test_utilities/react_wrapper.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ReactWrapper } from 'enzyme'; - -/** - * Return a collection of attribute 'entries'. - * The 'entries' are attributeName-attributeValue tuples. - */ -export function attributeEntries(wrapper: ReactWrapper): Array<[string, string]> { - return Array.prototype.slice - .call(wrapper.getDOMNode().attributes) - .map(({ name, value }) => [name, value]); -} diff --git a/x-pack/plugins/security_solution/public/resolver/view/panels/descriptive_name.test.tsx b/x-pack/plugins/security_solution/public/resolver/view/panels/descriptive_name.test.tsx index 75698bf726642..cef8aa718985f 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panels/descriptive_name.test.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panels/descriptive_name.test.tsx @@ -6,46 +6,48 @@ */ import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { I18nProvider } from '@kbn/i18n-react'; + import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data'; import { DescriptiveName } from './descriptive_name'; import { SafeResolverEvent } from '../../../../common/endpoint/types'; -import { mount, ReactWrapper } from 'enzyme'; -import { I18nProvider } from '@kbn/i18n-react'; describe('DescriptiveName', () => { - let generator: EndpointDocGenerator; - let wrapper: (event: SafeResolverEvent) => ReactWrapper; - beforeEach(() => { - generator = new EndpointDocGenerator('seed'); - wrapper = (event: SafeResolverEvent) => - mount( - - - - ); - }); + const generator = new EndpointDocGenerator('seed'); + + function renderEvent(event: SafeResolverEvent) { + render( + + + + ); + } + it('returns the right name for a registry event', () => { const extensions = { registry: { key: `HKLM/Windows/Software/abc` } }; - const event = generator.generateEvent({ eventCategory: 'registry', extensions }); - expect(wrapper(event).text()).toEqual(`HKLM/Windows/Software/abc`); + renderEvent(generator.generateEvent({ eventCategory: 'registry', extensions })); + expect(screen.queryByText('HKLM/Windows/Software/abc')).toBeInTheDocument(); }); it('returns the right name for a network event', () => { const randomIP = `${generator.randomIP()}`; const extensions = { network: { direction: 'outbound', forwarded_ip: randomIP } }; - const event = generator.generateEvent({ eventCategory: 'network', extensions }); - expect(wrapper(event).text()).toEqual(`outbound ${randomIP}`); + renderEvent(generator.generateEvent({ eventCategory: 'network', extensions })); + expect(screen.queryByText(`outbound ${randomIP}`)).toBeInTheDocument(); }); it('returns the right name for a file event', () => { const extensions = { file: { path: 'C:\\My Documents\\business\\January\\processName' } }; - const event = generator.generateEvent({ eventCategory: 'file', extensions }); - expect(wrapper(event).text()).toEqual('C:\\My Documents\\business\\January\\processName'); + renderEvent(generator.generateEvent({ eventCategory: 'file', extensions })); + expect( + screen.queryByText('C:\\My Documents\\business\\January\\processName') + ).toBeInTheDocument(); }); it('returns the right name for a dns event', () => { const extensions = { dns: { question: { name: `${generator.randomIP()}` } } }; - const event = generator.generateEvent({ eventCategory: 'dns', extensions }); - expect(wrapper(event).text()).toEqual(extensions.dns.question.name); + renderEvent(generator.generateEvent({ eventCategory: 'dns', extensions })); + expect(screen.queryByText(extensions.dns.question.name)).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/resolver/view/panels/use_formatted_date.test.tsx b/x-pack/plugins/security_solution/public/resolver/view/panels/use_formatted_date.test.tsx index 1c3f1948edc4d..b388e31444a25 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panels/use_formatted_date.test.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panels/use_formatted_date.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import { useFormattedDate } from './use_formatted_date'; @@ -16,23 +16,11 @@ import { uiSetting } from '../../mocks/ui_setting'; describe(`useFormattedDate, when the "dateFormat" UI setting is "${uiSetting( 'dateFormat' )}" and the "dateFormat:tz" setting is "${uiSetting('dateFormat:tz')}"`, () => { - let formattedDate: (date: ConstructorParameters[0] | Date | undefined) => string; - - beforeEach(async () => { - const mockCoreStart = coreMock.createStart(); - mockCoreStart.uiSettings.get.mockImplementation(uiSetting); - - function Test({ date }: { date: ConstructorParameters[0] | Date | undefined }) { - return <>{useFormattedDate(date)}; - } - - formattedDate = (date: ConstructorParameters[0] | Date | undefined): string => - mount( - - - - ).text(); - }); + function Test({ date }: { date: ConstructorParameters[0] | Date | undefined }) { + return {useFormattedDate(date)}; + } + const mockCoreStart = coreMock.createStart(); + mockCoreStart.uiSettings.get.mockImplementation(uiSetting); it.each([ ['randomString', 'an invalid string', 'Invalid Date'], @@ -51,6 +39,11 @@ describe(`useFormattedDate, when the "dateFormat" UI setting is "${uiSetting( ], [new Date(1600863932316), 'a defined Date object', 'Sep 23, 2020 @ 08:25:32.316'], ])('when the provided date is %p (%s) it should return %p', (value, _explanation, expected) => { - expect(formattedDate(value)).toBe(expected); + render( + + + + ); + expect(screen.queryByTestId('useFormattedDateTest')?.textContent).toBe(expected); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/add_note_icon_item.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/add_note_icon_item.test.tsx new file mode 100644 index 0000000000000..1f4d0e9e8d12c --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/add_note_icon_item.test.tsx @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render, screen } from '@testing-library/react'; +import React from 'react'; + +import { AddEventNoteAction } from './add_note_icon_item'; +import { useUserPrivileges } from '../../../../../common/components/user_privileges'; +import { getEndpointPrivilegesInitialStateMock } from '../../../../../common/components/user_privileges/endpoint/mocks'; +import { TestProviders } from '../../../../../common/mock'; +import { TimelineType } from '../../../../../../common/types'; + +jest.mock('../../../../../common/components/user_privileges'); +const useUserPrivilegesMock = useUserPrivileges as jest.Mock; + +describe('AddEventNoteAction', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('isDisabled', () => { + test('it disables the add note button when the user does NOT have crud privileges', () => { + useUserPrivilegesMock.mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: false, read: true }, + endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + }); + + render( + + + + ); + + expect(screen.getByTestId('timeline-notes-button-small')).toHaveClass( + 'euiButtonIcon-isDisabled' + ); + }); + + test('it enables the add note button when the user has crud privileges', () => { + useUserPrivilegesMock.mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: true, read: true }, + endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + }); + + render( + + + + ); + + expect(screen.getByTestId('timeline-notes-button-small')).not.toHaveClass( + 'euiButtonIcon-isDisabled' + ); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/add_note_icon_item.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/add_note_icon_item.tsx index 22c40ba78b0fe..784685997e5ff 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/add_note_icon_item.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/add_note_icon_item.tsx @@ -11,6 +11,7 @@ import { TimelineType } from '../../../../../../common/types/timeline'; import * as i18n from '../translations'; import { NotesButton } from '../../properties/helpers'; import { ActionIconItem } from './action_icon_item'; +import { useUserPrivileges } from '../../../../../common/components/user_privileges'; interface AddEventNoteActionProps { ariaLabel?: string; @@ -24,20 +25,25 @@ const AddEventNoteActionComponent: React.FC = ({ showNotes, timelineType, toggleShowNotes, -}) => ( - - - -); +}) => { + const { kibanaSecuritySolutionsPrivileges } = useUserPrivileges(); + + return ( + + + + ); +}; AddEventNoteActionComponent.displayName = 'AddEventNoteActionComponent'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/pin_event_action.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/pin_event_action.test.tsx new file mode 100644 index 0000000000000..e94c2ac2a38f0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/pin_event_action.test.tsx @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render, screen } from '@testing-library/react'; +import React from 'react'; + +import { PinEventAction } from './pin_event_action'; +import { useUserPrivileges } from '../../../../../common/components/user_privileges'; +import { getEndpointPrivilegesInitialStateMock } from '../../../../../common/components/user_privileges/endpoint/mocks'; +import { TestProviders } from '../../../../../common/mock'; +import { TimelineType } from '../../../../../../common/types'; + +jest.mock('../../../../../common/components/user_privileges'); +const useUserPrivilegesMock = useUserPrivileges as jest.Mock; + +describe('PinEventAction', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('isDisabled', () => { + test('it disables the pin event button when the user does NOT have crud privileges', () => { + useUserPrivilegesMock.mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: false, read: true }, + endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + }); + + render( + + + + ); + + expect(screen.getByTestId('pin')).toHaveClass('euiButtonIcon-isDisabled'); + }); + + test('it enables the pin event button when the user has crud privileges', () => { + useUserPrivilegesMock.mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: true, read: true }, + endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + }); + + render( + + + + ); + + expect(screen.getByTestId('pin')).not.toHaveClass('euiButtonIcon-isDisabled'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/pin_event_action.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/pin_event_action.tsx index 53970594c8c1c..d0294d3908590 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/pin_event_action.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/actions/pin_event_action.tsx @@ -13,6 +13,7 @@ import { EventsTdContent } from '../../styles'; import { eventHasNotes, getPinTooltip } from '../helpers'; import { Pin } from '../../pin'; import { TimelineType } from '../../../../../../common/types/timeline'; +import { useUserPrivileges } from '../../../../../common/components/user_privileges'; interface PinEventActionProps { ariaLabel?: string; @@ -31,6 +32,7 @@ const PinEventActionComponent: React.FC = ({ eventIsPinned, timelineType, }) => { + const { kibanaSecuritySolutionsPrivileges } = useUserPrivileges(); const tooltipContent = useMemo( () => getPinTooltip({ @@ -50,6 +52,7 @@ const PinEventActionComponent: React.FC = ({ ariaLabel={ariaLabel} allowUnpinning={!eventHasNotes(noteIds)} data-test-subj="pin-event" + isDisabled={kibanaSecuritySolutionsPrivileges.crud === false} isAlert={isAlert} onClick={onPinClicked} pinned={eventIsPinned} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx index 334bd464f700f..59b331d4d7f11 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx @@ -28,6 +28,17 @@ jest.mock('../../../../../common/hooks/use_selector', () => ({ useShallowEqualSelector: jest.fn(), useDeepEqualSelector: jest.fn(), })); +jest.mock('../../../../../common/components/user_privileges', () => { + return { + useUserPrivileges: () => ({ + listPrivileges: { loading: false, error: undefined, result: undefined }, + detectionEnginePrivileges: { loading: false, error: undefined, result: undefined }, + endpointPrivileges: {}, + kibanaSecuritySolutionsPrivileges: { crud: true, read: true }, + }), + }; +}); + jest.mock('../../../../../common/lib/kibana', () => ({ useKibana: () => ({ services: { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx index 200c9810d9fe6..f2045327a42f7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx @@ -36,6 +36,17 @@ import { createStore, State } from '../../../../common/store'; jest.mock('../../../../common/lib/kibana/hooks'); jest.mock('../../../../common/hooks/use_app_toasts'); +jest.mock('../../../../common/components/user_privileges', () => { + return { + useUserPrivileges: () => ({ + listPrivileges: { loading: false, error: undefined, result: undefined }, + detectionEnginePrivileges: { loading: false, error: undefined, result: undefined }, + endpointPrivileges: {}, + kibanaSecuritySolutionsPrivileges: { crud: true, read: true }, + }), + }; +}); + jest.mock('../../../../common/lib/kibana', () => { const originalModule = jest.requireActual('../../../../common/lib/kibana'); const mockCasesContract = jest.requireActual('@kbn/cases-plugin/public/mocks'); @@ -225,7 +236,7 @@ describe('Body', () => { mockDispatch.mockClear(); }); - test('Add a Note to an event', () => { + test('Add a note to an event', () => { const wrapper = mount( @@ -257,7 +268,7 @@ describe('Body', () => { ); }); - test('Add two Note to an event', () => { + test('Add two notes to an event', () => { const { storage } = createSecuritySolutionStorageMock(); const state: State = { ...mockGlobalState, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx index c2179abbb61df..7c25794a16c80 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/notes_tab_content/index.tsx @@ -39,6 +39,7 @@ import { getTimelineNoteSelector } from './selectors'; import { DetailsPanel } from '../../side_panel'; import { getScrollToTopSelector } from '../tabs_content/selectors'; import { useScrollToTop } from '../../../../common/components/scroll_to_top'; +import { useUserPrivileges } from '../../../../common/components/user_privileges'; const FullWidthFlexGroup = styled(EuiFlexGroup)` width: 100%; @@ -131,6 +132,7 @@ interface NotesTabContentProps { const NotesTabContentComponent: React.FC = ({ timelineId }) => { const dispatch = useDispatch(); + const { kibanaSecuritySolutionsPrivileges } = useUserPrivileges(); const getScrollToTop = useMemo(() => getScrollToTopSelector(), []); const scrollToTop = useShallowEqualSelector((state) => getScrollToTop(state, timelineId)); @@ -239,7 +241,7 @@ const NotesTabContentComponent: React.FC = ({ timelineId } showTimelineDescription /> - {!isImmutable && ( + {!isImmutable && kibanaSecuritySolutionsPrivileges.crud === true && ( void; pinned: boolean; @@ -45,7 +46,7 @@ export const getDefaultAriaLabel = ({ }; export const Pin = React.memo( - ({ ariaLabel, allowUnpinning, isAlert, onClick = noop, pinned, timelineType }) => { + ({ ariaLabel, allowUnpinning, isAlert, isDisabled, onClick = noop, pinned, timelineType }) => { const isTemplate = timelineType === TimelineType.template; const defaultAriaLabel = getDefaultAriaLabel({ isAlert, @@ -60,7 +61,7 @@ export const Pin = React.memo( data-test-subj="pin" iconType={getPinIcon(pinned)} onClick={onClick} - isDisabled={isTemplate || !allowUnpinning} + isDisabled={isDisabled || isTemplate || !allowUnpinning} size="s" /> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx index c59c0a15ff53d..ff0d8686bb9c3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/properties/helpers.tsx @@ -91,6 +91,7 @@ NewTimeline.displayName = 'NewTimeline'; interface NotesButtonProps { ariaLabel?: string; + isDisabled?: boolean; showNotes: boolean; toggleShowNotes: () => void; toolTip?: string; @@ -99,6 +100,7 @@ interface NotesButtonProps { interface SmallNotesButtonProps { ariaLabel?: string; + isDisabled?: boolean; toggleShowNotes: () => void; timelineType: TimelineTypeLiteral; } @@ -106,7 +108,7 @@ interface SmallNotesButtonProps { export const NOTES_BUTTON_CLASS_NAME = 'notes-button'; const SmallNotesButton = React.memo( - ({ ariaLabel = i18n.NOTES, toggleShowNotes, timelineType }) => { + ({ ariaLabel = i18n.NOTES, isDisabled, toggleShowNotes, timelineType }) => { const isTemplate = timelineType === TimelineType.template; return ( @@ -114,6 +116,7 @@ const SmallNotesButton = React.memo( aria-label={ariaLabel} className={NOTES_BUTTON_CLASS_NAME} data-test-subj="timeline-notes-button-small" + disabled={isDisabled} iconType="editorComment" onClick={toggleShowNotes} size="s" @@ -125,10 +128,11 @@ const SmallNotesButton = React.memo( SmallNotesButton.displayName = 'SmallNotesButton'; export const NotesButton = React.memo( - ({ ariaLabel, showNotes, timelineType, toggleShowNotes, toolTip }) => + ({ ariaLabel, isDisabled, showNotes, timelineType, toggleShowNotes, toolTip }) => showNotes ? ( @@ -136,6 +140,7 @@ export const NotesButton = React.memo( diff --git a/x-pack/plugins/synthetics/common/constants/client_defaults.ts b/x-pack/plugins/synthetics/common/constants/client_defaults.ts index a8860dcca4a1a..5293205a183cb 100644 --- a/x-pack/plugins/synthetics/common/constants/client_defaults.ts +++ b/x-pack/plugins/synthetics/common/constants/client_defaults.ts @@ -5,6 +5,8 @@ * 2.0. */ +import moment from 'moment'; + export const CLIENT_DEFAULTS = { ABSOLUTE_DATE_RANGE_START: 0, // 15 minutes @@ -43,3 +45,17 @@ export const CLIENT_DEFAULTS = { }; export const EXCLUDE_RUN_ONCE_FILTER = { bool: { must_not: { exists: { field: 'run_once' } } } }; +export const SUMMARY_FILTER = { + exists: { + field: 'summary', + }, +}; + +export const getTimeSpanFilter = () => ({ + range: { + 'monitor.timespan': { + lte: moment().toISOString(), + gte: moment().subtract(5, 'minutes').toISOString(), + }, + }, +}); diff --git a/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts b/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts index 10e027f249104..b265da7a3f0d6 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/data_view_permissions.ts @@ -38,7 +38,7 @@ journey('DataViewPermissions', async ({ page, params }) => { await page.goto(`${baseUrl}?${queryParams}`, { waitUntil: 'networkidle', }); - await login.loginToKibana('viewer_user', 'changeme'); + await login.loginToKibana('viewer', 'changeme'); }); step('Click explore data button', async () => { diff --git a/x-pack/plugins/synthetics/e2e/journeys/monitor_management_enablement.journey.ts b/x-pack/plugins/synthetics/e2e/journeys/monitor_management_enablement.journey.ts index b7308ece8af21..5d22fe8491579 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/monitor_management_enablement.journey.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/monitor_management_enablement.journey.ts @@ -57,7 +57,7 @@ journey( }); step('login to Kibana', async () => { - await uptime.loginToKibana('editor_user', 'changeme'); + await uptime.loginToKibana('editor', 'changeme'); const invalid = await page.locator( `text=Username or password is incorrect. Please try again.` ); diff --git a/x-pack/plugins/synthetics/e2e/journeys/read_only_user/monitor_management.ts b/x-pack/plugins/synthetics/e2e/journeys/read_only_user/monitor_management.ts index 33698961951da..677983ca9260b 100644 --- a/x-pack/plugins/synthetics/e2e/journeys/read_only_user/monitor_management.ts +++ b/x-pack/plugins/synthetics/e2e/journeys/read_only_user/monitor_management.ts @@ -23,7 +23,7 @@ journey( }); step('login to Kibana', async () => { - await uptime.loginToKibana('viewer_user', 'changeme'); + await uptime.loginToKibana('viewer', 'changeme'); }); step('Adding monitor is disabled', async () => { diff --git a/x-pack/plugins/synthetics/e2e/page_objects/login.tsx b/x-pack/plugins/synthetics/e2e/page_objects/login.tsx index ae52bb45ddb84..ee0fe0f596b98 100644 --- a/x-pack/plugins/synthetics/e2e/page_objects/login.tsx +++ b/x-pack/plugins/synthetics/e2e/page_objects/login.tsx @@ -24,7 +24,7 @@ export function loginPageProvider({ await page.waitForTimeout(5 * 1000); } }, - async loginToKibana(usernameT?: string, passwordT?: string) { + async loginToKibana(usernameT?: 'editor' | 'viewer', passwordT?: string) { if (isRemote) { await page.click('text="Log in with Elasticsearch"'); } diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/hooks/use_status_by_location.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/hooks/use_status_by_location.tsx new file mode 100644 index 0000000000000..d3da5bc1b35ee --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/hooks/use_status_by_location.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 + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEsSearch } from '@kbn/observability-plugin/public'; +import { useParams } from 'react-router-dom'; +import { useMemo } from 'react'; +import { Ping } from '../../../../../../common/runtime_types'; +import { + EXCLUDE_RUN_ONCE_FILTER, + getTimeSpanFilter, + SUMMARY_FILTER, +} from '../../../../../../common/constants/client_defaults'; +import { useSyntheticsRefreshContext } from '../../../contexts/synthetics_refresh_context'; +import { SYNTHETICS_INDEX_PATTERN, UNNAMED_LOCATION } from '../../../../../../common/constants'; + +export function useStatusByLocation() { + const { lastRefresh } = useSyntheticsRefreshContext(); + + const { monitorId } = useParams<{ monitorId: string }>(); + + const { data, loading } = useEsSearch( + { + index: SYNTHETICS_INDEX_PATTERN, + body: { + size: 0, + query: { + bool: { + filter: [ + SUMMARY_FILTER, + EXCLUDE_RUN_ONCE_FILTER, + getTimeSpanFilter(), + { + term: { + config_id: monitorId, + }, + }, + ], + }, + }, + sort: [{ '@timestamp': 'desc' }], + aggs: { + locations: { + terms: { + field: 'observer.geo.name', + missing: UNNAMED_LOCATION, + size: 1000, + }, + aggs: { + summary: { + top_hits: { + size: 1, + }, + }, + }, + }, + }, + }, + }, + [lastRefresh, monitorId], + { name: 'getMonitorStatusByLocation' } + ); + + return useMemo(() => { + const locations = (data?.aggregations?.locations.buckets ?? []).map((loc) => { + return loc.summary.hits.hits?.[0]._source as Ping; + }); + + return { locations, loading }; + }, [data, loading]); +} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary.tsx index 9ac2d67967eeb..de5871304eccf 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary.tsx @@ -5,14 +5,23 @@ * 2.0. */ -import React from 'react'; -import { useSelector } from 'react-redux'; -import { selectMonitorStatus } from '../../state/monitor_summary'; +import React, { useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { useParams } from 'react-router-dom'; +import { getSyntheticsMonitorAction, selectMonitorStatus } from '../../state/monitor_summary'; import { useMonitorListBreadcrumbs } from '../monitors_page/hooks/use_breadcrumbs'; export const MonitorSummaryPage = () => { const { data } = useSelector(selectMonitorStatus); useMonitorListBreadcrumbs([{ text: data?.monitor.name ?? '' }]); + const dispatch = useDispatch(); + + const { monitorId } = useParams<{ monitorId: string }>(); + + useEffect(() => { + dispatch(getSyntheticsMonitorAction.get(monitorId)); + }, [dispatch, monitorId]); + return <>; }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary_tabs.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary_tabs.tsx index 3469341d86ca6..725d209c8200e 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary_tabs.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/monitor_summary_tabs.tsx @@ -50,7 +50,7 @@ export const MonitorSummaryTabs = () => { return ( {}} /> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/locations_status.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/locations_status.tsx new file mode 100644 index 0000000000000..6c918c1288366 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/locations_status.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiBadge, EuiBadgeGroup, EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; +import { useStatusByLocation } from '../hooks/use_status_by_location'; + +export const LocationsStatus = () => { + const { locations, loading } = useStatusByLocation(); + + if (loading) { + return ; + } + + return ( + + {locations.map((loc) => ( + ( + 0 ? 'danger' : 'success'} /> + )} + color="hollow" + > + {loc.observer?.geo?.name} + + ))} + + ); +}; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/monitor_details_panel.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/monitor_details_panel.tsx new file mode 100644 index 0000000000000..8ed2c5dffd771 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/monitor_details_panel.tsx @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + EuiBadge, + EuiSpacer, + EuiLink, + EuiLoadingSpinner, +} from '@elastic/eui'; +import { capitalize } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { useDispatch, useSelector } from 'react-redux'; +import { useParams } from 'react-router-dom'; +import { MonitorTags } from './monitor_tags'; +import { MonitorEnabled } from '../../monitors_page/management/monitor_list_table/monitor_enabled'; +import { LocationsStatus } from './locations_status'; +import { + getSyntheticsMonitorAction, + selectMonitorStatus, + syntheticsMonitorSelector, +} from '../../../state/monitor_summary'; +import { ConfigKey } from '../../../../../../common/runtime_types'; + +export const MonitorDetailsPanel = () => { + const { data } = useSelector(selectMonitorStatus); + + const { monitorId } = useParams<{ monitorId: string }>(); + + const dispatch = useDispatch(); + + const { data: monitor, loading } = useSelector(syntheticsMonitorSelector); + + if (!data) { + return ; + } + + return ( + <> + + + {ENABLED_LABEL} + + {monitor && ( + { + dispatch(getSyntheticsMonitorAction.get(monitorId)); + }} + /> + )} + + {MONITOR_TYPE_LABEL} + + {capitalize(data.monitor.type)} + + {FREQUENCY_LABEL} + Every 10 mins + {LOCATIONS_LABEL} + + + + {URL_LABEL} + + + {data.url?.full} + + + {TAGS_LABEL} + + {monitor && } + + + + ); +}; + +const FREQUENCY_LABEL = i18n.translate('xpack.synthetics.management.monitorList.frequency', { + defaultMessage: 'Frequency', +}); +const LOCATIONS_LABEL = i18n.translate('xpack.synthetics.management.monitorList.locations', { + defaultMessage: 'Locations', +}); + +const URL_LABEL = i18n.translate('xpack.synthetics.management.monitorList.url', { + defaultMessage: 'URL', +}); + +const TAGS_LABEL = i18n.translate('xpack.synthetics.management.monitorList.tags', { + defaultMessage: 'Tags', +}); + +const ENABLED_LABEL = i18n.translate('xpack.synthetics.detailsPanel.monitorDetails.enabled', { + defaultMessage: 'Enabled', +}); + +const MONITOR_TYPE_LABEL = i18n.translate( + 'xpack.synthetics.detailsPanel.monitorDetails.monitorType', + { + defaultMessage: 'Monitor type', + } +); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/monitor_tags.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/monitor_tags.tsx new file mode 100644 index 0000000000000..7960d5efbc1e7 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/monitor_tags.tsx @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiBadge, EuiBadgeGroup } from '@elastic/eui'; + +export const MonitorTags = ({ tags }: { tags: string[] }) => { + return ( + + {tags.map((tag) => ( + {tag} + ))} + + ); +}; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/summary_tab_content.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/summary_tab_content.tsx index e426ebbf2e309..c0a2f2c3b30d8 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/summary_tab_content.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_summary/tabs_content/summary_tab_content.tsx @@ -5,9 +5,23 @@ * 2.0. */ -import { EuiText } from '@elastic/eui'; import React from 'react'; +import { EuiTitle, EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { MonitorDetailsPanel } from './monitor_details_panel'; export const SummaryTabContent = () => { - return Monitor summary tab content; + return ( + + +

{MONITOR_DETAILS_LABEL}

+
+ +
+ ); }; + +const MONITOR_DETAILS_LABEL = i18n.translate('xpack.synthetics.detailsPanel.monitorDetails', { + defaultMessage: 'Monitor details', +}); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx index 5665c402442ab..d3803a0aa0260 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx @@ -132,12 +132,7 @@ export function getMonitorListColumns({ defaultMessage: 'Enabled', }), render: (_enabled: boolean, monitor: EncryptedSyntheticsSavedMonitor) => ( - + ), }, { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx index e98ca2a466f0d..36527f3316935 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx @@ -10,6 +10,7 @@ import React, { useEffect, useState } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { FETCH_STATUS, useFetcher } from '@kbn/observability-plugin/public'; +import { useCanEditSynthetics } from '../../../../../../hooks/use_capabilities'; import { ConfigKey, EncryptedSyntheticsMonitor } from '../../../../../../../common/runtime_types'; import { fetchUpsertMonitor } from '../../../../state'; @@ -19,10 +20,12 @@ interface Props { id: string; monitor: EncryptedSyntheticsMonitor; reloadPage: () => void; - isDisabled?: boolean; + initialLoading?: boolean; } -export const MonitorEnabled = ({ id, monitor, reloadPage, isDisabled }: Props) => { +export const MonitorEnabled = ({ id, monitor, reloadPage, initialLoading }: Props) => { + const isDisabled = !useCanEditSynthetics(); + const [isEnabled, setIsEnabled] = useState(null); const { notifications } = useKibana(); @@ -69,7 +72,7 @@ export const MonitorEnabled = ({ id, monitor, reloadPage, isDisabled }: Props) = return ( <> - {isLoading ? ( + {isLoading || initialLoading ? ( ) : ( ( ); export const getMonitorStatusAction = createAsyncAction('[MONITOR SUMMARY] GET'); + +export const getSyntheticsMonitorAction = createAsyncAction( + 'fetchSyntheticsMonitorAction' +); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/api.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/api.ts index 0d0a6c628f03a..af01acf97592d 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/api.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/api.ts @@ -5,9 +5,10 @@ * 2.0. */ +import { SavedObject } from '@kbn/core/types'; import { apiService } from '../../../../utils/api_service'; -import { Ping } from '../../../../../common/runtime_types'; -import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; +import { Ping, SyntheticsMonitor } from '../../../../../common/runtime_types'; +import { API_URLS, SYNTHETICS_API_URLS } from '../../../../../common/constants'; export interface QueryParams { monitorId: string; @@ -18,3 +19,11 @@ export interface QueryParams { export const fetchMonitorStatus = async (params: QueryParams): Promise => { return await apiService.get(SYNTHETICS_API_URLS.MONITOR_STATUS, { ...params }); }; + +export const fetchSyntheticsMonitor = async (monitorId: string): Promise => { + const { attributes } = (await apiService.get( + `${API_URLS.SYNTHETICS_MONITORS}/${monitorId}` + )) as SavedObject; + + return attributes; +}; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/effects.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/effects.ts index dae9f72ac804e..9a1b52e1e24df 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/effects.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/effects.ts @@ -7,8 +7,8 @@ import { takeLeading } from 'redux-saga/effects'; import { fetchEffectFactory } from '../utils/fetch_effect'; -import { getMonitorStatusAction } from './actions'; -import { fetchMonitorStatus } from './api'; +import { getMonitorStatusAction, getSyntheticsMonitorAction } from './actions'; +import { fetchMonitorStatus, fetchSyntheticsMonitor } from './api'; export function* fetchMonitorStatusEffect() { yield takeLeading( @@ -20,3 +20,14 @@ export function* fetchMonitorStatusEffect() { ) ); } + +export function* fetchSyntheticsMonitorEffect() { + yield takeLeading( + getSyntheticsMonitorAction.get, + fetchEffectFactory( + fetchSyntheticsMonitor, + getSyntheticsMonitorAction.success, + getSyntheticsMonitorAction.fail + ) + ); +} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/selectors.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/selectors.ts index 09a89a1f07619..d361024e839f2 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/selectors.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/selectors.ts @@ -16,3 +16,5 @@ export const selectSelectedLocationId = createSelector( ); export const selectMonitorStatus = createSelector(getState, (state) => state); + +export const syntheticsMonitorSelector = (state: SyntheticsAppState) => state.syntheticsMonitor; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/synthetics_montior_reducer.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/synthetics_montior_reducer.ts new file mode 100644 index 0000000000000..e1049c3b862d3 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_summary/synthetics_montior_reducer.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; +import { createReducer } from '@reduxjs/toolkit'; +import { SyntheticsMonitor } from '../../../../../common/runtime_types'; +import { getSyntheticsMonitorAction } from './actions'; + +export interface SyntheticsMonitorState { + data: SyntheticsMonitor | null; + loading: boolean; + error: IHttpFetchError | null; +} + +const initialState: SyntheticsMonitorState = { + data: null, + loading: false, + error: null, +}; + +export const syntheticsMonitorReducer = createReducer(initialState, (builder) => { + builder + .addCase(getSyntheticsMonitorAction.get, (state) => { + state.loading = true; + }) + .addCase(getSyntheticsMonitorAction.success, (state, action) => { + state.data = action.payload; + state.loading = false; + }) + .addCase(getSyntheticsMonitorAction.fail, (state, action) => { + state.error = action.payload as IHttpFetchError; + state.loading = false; + }); +}); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/root_effect.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/root_effect.ts index 9cae9249af971..45214cf4d2461 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/state/root_effect.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/root_effect.ts @@ -6,7 +6,7 @@ */ import { all, fork } from 'redux-saga/effects'; -import { fetchMonitorStatusEffect } from './monitor_summary'; +import { fetchMonitorStatusEffect, fetchSyntheticsMonitorEffect } from './monitor_summary'; import { fetchIndexStatusEffect } from './index_status'; import { fetchSyntheticsEnablementEffect } from './synthetics_enablement'; import { fetchMonitorListEffect } from './monitor_list'; @@ -19,5 +19,6 @@ export const rootEffect = function* root(): Generator { fork(fetchServiceLocationsEffect), fork(fetchMonitorListEffect), fork(fetchMonitorStatusEffect), + fork(fetchSyntheticsMonitorEffect), ]); }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/root_reducer.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/root_reducer.ts index 4ecd0dbc265ab..bd4b25b456e93 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/state/root_reducer.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/root_reducer.ts @@ -7,6 +7,7 @@ import { combineReducers } from '@reduxjs/toolkit'; +import { syntheticsMonitorReducer } from './monitor_summary/synthetics_montior_reducer'; import { monitorStatusReducer } from './monitor_summary'; import { uiReducer } from './ui'; import { indexStatusReducer } from './index_status'; @@ -21,6 +22,7 @@ export const rootReducer = combineReducers({ monitorList: monitorListReducer, serviceLocations: serviceLocationsReducer, monitorStatus: monitorStatusReducer, + syntheticsMonitor: syntheticsMonitorReducer, }); export type SyntheticsAppState = ReturnType; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/syncthetics_store.mock.ts b/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/syncthetics_store.mock.ts index c5aad9ffa01ac..3a9c13f928a76 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/syncthetics_store.mock.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/utils/testing/__mocks__/syncthetics_store.mock.ts @@ -84,4 +84,9 @@ export const mockState: SyntheticsAppState = { error: null, selectedLocationId: null, }, + syntheticsMonitor: { + data: null, + loading: false, + error: null, + }, }; diff --git a/x-pack/plugins/synthetics/server/synthetics_service/service_api_client.ts b/x-pack/plugins/synthetics/server/synthetics_service/service_api_client.ts index 02d0f69ddbedc..235055b8c2b38 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/service_api_client.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/service_api_client.ts @@ -55,8 +55,11 @@ export class ServiceAPIClient { this.server = server; } - getHttpsAgent() { + getHttpsAgent(url: string) { const config = this.config; + if (url !== this.config.devUrl && this.authorization && this.server.isDev) { + return; + } if (config.tls && config.tls.certificate && config.tls.key) { const tlsConfig = new SslConfig(config.tls); @@ -92,29 +95,31 @@ export class ServiceAPIClient { return { allowed: true, signupUrl: null }; } - const httpsAgent = this.getHttpsAgent(); - - if (this.locations.length > 0 && httpsAgent) { + if (this.locations.length > 0) { // get a url from a random location const url = this.locations[Math.floor(Math.random() * this.locations.length)].url; - try { - const { data } = await axios({ - method: 'GET', - url: url + '/allowed', - headers: - process.env.NODE_ENV !== 'production' && this.authorization - ? { - Authorization: this.authorization, - } - : undefined, - httpsAgent, - }); - - const { allowed, signupUrl } = data; - return { allowed, signupUrl }; - } catch (e) { - this.logger.error(e); + const httpsAgent = this.getHttpsAgent(url); + + if (httpsAgent) { + try { + const { data } = await axios({ + method: 'GET', + url: url + '/allowed', + headers: + process.env.NODE_ENV !== 'production' && this.authorization + ? { + Authorization: this.authorization, + } + : undefined, + httpsAgent, + }); + + const { allowed, signupUrl } = data; + return { allowed, signupUrl }; + } catch (e) { + this.logger.error(e); + } } } @@ -151,7 +156,7 @@ export class ServiceAPIClient { Authorization: this.authorization, } : undefined, - httpsAgent: this.getHttpsAgent(), + httpsAgent: this.getHttpsAgent(url), }); }; diff --git a/x-pack/plugins/transform/common/api_schemas/type_guards.ts b/x-pack/plugins/transform/common/api_schemas/type_guards.ts index 567eeb030e22d..821eda892deb3 100644 --- a/x-pack/plugins/transform/common/api_schemas/type_guards.ts +++ b/x-pack/plugins/transform/common/api_schemas/type_guards.ts @@ -7,9 +7,10 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + import type { EsIndex } from '../types/es_index'; import type { EsIngestPipeline } from '../types/es_ingest_pipeline'; -import { isPopulatedObject } from '../shared_imports'; // To be able to use the type guards on the client side, we need to make sure we don't import // the code of '@kbn/config-schema' but just its types, otherwise the client side code will diff --git a/x-pack/plugins/transform/common/shared_imports.ts b/x-pack/plugins/transform/common/shared_imports.ts index 0566086046d0e..fd00440e07c5b 100644 --- a/x-pack/plugins/transform/common/shared_imports.ts +++ b/x-pack/plugins/transform/common/shared_imports.ts @@ -8,7 +8,6 @@ export type { ChartData } from '@kbn/ml-plugin/common'; export { composeValidators, - isPopulatedObject, isRuntimeMappings, patternValidator, isRuntimeField, diff --git a/x-pack/plugins/transform/common/types/data_view.ts b/x-pack/plugins/transform/common/types/data_view.ts index 98787a1281dbb..b541254971c35 100644 --- a/x-pack/plugins/transform/common/types/data_view.ts +++ b/x-pack/plugins/transform/common/types/data_view.ts @@ -6,8 +6,7 @@ */ import type { DataView } from '@kbn/data-views-plugin/common'; - -import { isPopulatedObject } from '../shared_imports'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; // Custom minimal type guard for DataView to check against the attributes used in transforms code. export function isDataView(arg: any): arg is DataView { diff --git a/x-pack/plugins/transform/common/types/transform.ts b/x-pack/plugins/transform/common/types/transform.ts index a196111bf6678..f4f9437e05d13 100644 --- a/x-pack/plugins/transform/common/types/transform.ts +++ b/x-pack/plugins/transform/common/types/transform.ts @@ -6,8 +6,8 @@ */ import type { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { LatestFunctionConfig, PutTransformsRequestSchema } from '../api_schemas/transforms'; -import { isPopulatedObject } from '../shared_imports'; import type { PivotGroupByDict } from './pivot_group_by'; import type { PivotAggDict } from './pivot_aggs'; import type { TransformHealthAlertRule } from './alerting'; diff --git a/x-pack/plugins/transform/common/types/transform_stats.ts b/x-pack/plugins/transform/common/types/transform_stats.ts index 00ffa40b84d3b..2f9319201fd6b 100644 --- a/x-pack/plugins/transform/common/types/transform_stats.ts +++ b/x-pack/plugins/transform/common/types/transform_stats.ts @@ -5,8 +5,9 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + import { TransformState, TRANSFORM_STATE } from '../constants'; -import { isPopulatedObject } from '../shared_imports'; import { TransformId } from './transform'; export interface TransformStats { diff --git a/x-pack/plugins/transform/common/utils/errors.ts b/x-pack/plugins/transform/common/utils/errors.ts index 2aff8f332b130..c9d81b740f721 100644 --- a/x-pack/plugins/transform/common/utils/errors.ts +++ b/x-pack/plugins/transform/common/utils/errors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { isPopulatedObject } from '../shared_imports'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; export interface ErrorResponse { body: { diff --git a/x-pack/plugins/transform/public/app/common/pivot_aggs.ts b/x-pack/plugins/transform/public/app/common/pivot_aggs.ts index 9045191a779cb..4b986659fe633 100644 --- a/x-pack/plugins/transform/public/app/common/pivot_aggs.ts +++ b/x-pack/plugins/transform/public/app/common/pivot_aggs.ts @@ -8,13 +8,13 @@ import { FC } from 'react'; import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/data-plugin/common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { AggName } from '../../../common/types/aggregations'; import type { Dictionary } from '../../../common/types/common'; import type { EsFieldName } from '../../../common/types/fields'; import type { PivotAgg, PivotSupportedAggs } from '../../../common/types/pivot_aggs'; import { PIVOT_SUPPORTED_AGGS } from '../../../common/types/pivot_aggs'; -import { isPopulatedObject } from '../../../common/shared_imports'; import { getAggFormConfig } from '../sections/create_transform/components/step_define/common/get_agg_form_config'; import { PivotAggsConfigFilter } from '../sections/create_transform/components/step_define/common/filter_agg/types'; diff --git a/x-pack/plugins/transform/public/app/common/pivot_group_by.ts b/x-pack/plugins/transform/public/app/common/pivot_group_by.ts index dd9a63088e791..b0fa78e8a902f 100644 --- a/x-pack/plugins/transform/public/app/common/pivot_group_by.ts +++ b/x-pack/plugins/transform/public/app/common/pivot_group_by.ts @@ -6,11 +6,11 @@ */ import { KBN_FIELD_TYPES } from '@kbn/data-plugin/common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { AggName } from '../../../common/types/aggregations'; import { Dictionary } from '../../../common/types/common'; import { EsFieldName } from '../../../common/types/fields'; import { GenericAgg } from '../../../common/types/pivot_group_by'; -import { isPopulatedObject } from '../../../common/shared_imports'; import { PivotAggsConfigWithUiSupport } from './pivot_aggs'; export enum PIVOT_SUPPORTED_GROUP_BY_AGGS { diff --git a/x-pack/plugins/transform/public/app/common/request.ts b/x-pack/plugins/transform/public/app/common/request.ts index 350f57a3bcf58..4700e42a3d946 100644 --- a/x-pack/plugins/transform/public/app/common/request.ts +++ b/x-pack/plugins/transform/public/app/common/request.ts @@ -9,6 +9,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { HttpFetchError } from '@kbn/core/public'; import type { DataView } from '@kbn/data-views-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { DEFAULT_CONTINUOUS_MODE_DELAY, @@ -23,7 +24,6 @@ import type { PutTransformsPivotRequestSchema, PutTransformsRequestSchema, } from '../../../common/api_schemas/transforms'; -import { isPopulatedObject } from '../../../common/shared_imports'; import { DateHistogramAgg, HistogramAgg, TermsAgg } from '../../../common/types/pivot_group_by'; import { isDataView } from '../../../common/types/data_view'; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/common.ts b/x-pack/plugins/transform/public/app/lib/authorization/components/common.ts index 659d525643965..c3db9834a5b54 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/common.ts +++ b/x-pack/plugins/transform/public/app/lib/authorization/components/common.ts @@ -6,9 +6,9 @@ */ import { i18n } from '@kbn/i18n'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { Privileges } from '../../../../../common/types/privileges'; -import { isPopulatedObject } from '../../../../../common/shared_imports'; export interface Capabilities { canGetTransform: boolean; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index 649683182dcab..59f80d743a9a3 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -30,6 +30,7 @@ import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/public'; import { DuplicateDataViewError } from '@kbn/data-plugin/public'; import type { RuntimeField } from '@kbn/data-views-plugin/common'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { PutTransformsResponseSchema } from '../../../../../../common/api_schemas/transforms'; import { isGetTransformsStatsResponseSchema, @@ -49,7 +50,6 @@ import { PutTransformsLatestRequestSchema, PutTransformsPivotRequestSchema, } from '../../../../../../common/api_schemas/transforms'; -import { isPopulatedObject } from '../../../../../../common/shared_imports'; import { isContinuousTransform, isLatestTransform } from '../../../../../../common/types/transform'; import { TransformAlertFlyout } from '../../../../../alerting/transform_alerting_flyout'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx index 6f590a0e17892..55ecc18863aa5 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_agg_form.tsx @@ -10,13 +10,13 @@ import { EuiFormRow, EuiIcon, EuiSelect, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import useUpdateEffect from 'react-use/lib/useUpdateEffect'; import { DataView } from '@kbn/data-views-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { CreateTransformWizardContext } from '../../../../wizard/wizard'; import { commonFilterAggs, filterAggsFieldSupport } from '../constants'; import { getFilterAggTypeConfig } from '../config'; import type { FilterAggType, PivotAggsConfigFilter } from '../types'; import type { RuntimeMappings } from '../../types'; import { getKibanaFieldTypeFromEsType } from '../../get_pivot_dropdown_options'; -import { isPopulatedObject } from '../../../../../../../../../common/shared_imports'; /** * Resolves supported filters for provided field. diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/top_metrics_agg/config.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/top_metrics_agg/config.ts index 56d17e7973e16..49be7b299712b 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/top_metrics_agg/config.ts +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/top_metrics_agg/config.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { isPivotAggsConfigWithUiSupport, isSpecialSortField, @@ -16,7 +17,6 @@ import { } from '../../../../../../common/pivot_aggs'; import { PivotAggsConfigTopMetrics } from './types'; import { TopMetricsAggForm } from './components/top_metrics_agg_form'; -import { isPopulatedObject } from '../../../../../../../../common/shared_imports'; /** * Gets initial basic configuration of the top_metrics aggregation. diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts index e97d47864313c..a8a9b5c1e35b0 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/types.ts @@ -6,6 +6,7 @@ */ import { KBN_FIELD_TYPES } from '@kbn/data-plugin/public'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { EsFieldName } from '../../../../../../../common/types/fields'; @@ -24,7 +25,7 @@ import { } from '../../../../../../../common/types/transform'; import { LatestFunctionConfig } from '../../../../../../../common/api_schemas/transforms'; -import { isPopulatedObject, RUNTIME_FIELD_TYPES } from '../../../../../../../common/shared_imports'; +import { RUNTIME_FIELD_TYPES } from '../../../../../../../common/shared_imports'; export interface ErrorMessage { query: string; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts index eb9adbb45b5b4..a2dc9148bf03f 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/use_edit_transform_flyout.ts @@ -11,8 +11,8 @@ import { merge } from 'lodash'; import { useReducer } from 'react'; import { i18n } from '@kbn/i18n'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { isPopulatedObject } from '../../../../../../common/shared_imports'; import { PostTransformsUpdateRequestSchema } from '../../../../../../common/api_schemas/update_transforms'; import { DEFAULT_TRANSFORM_FREQUENCY, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx index 84110e67d701e..6477e33a5c5a7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row.tsx @@ -10,6 +10,7 @@ import React, { FC } from 'react'; import { EuiButtonEmpty, EuiTabbedContent } from '@elastic/eui'; import { Optional } from '@kbn/utility-types'; import { i18n } from '@kbn/i18n'; +import { stringHash } from '@kbn/ml-string-hash'; import moment from 'moment-timezone'; import { TransformListRow } from '../../../../common'; @@ -28,23 +29,6 @@ function getItemDescription(value: any) { return value.toString(); } -/** - * Creates a deterministic number based hash out of a string. - */ -export function stringHash(str: string): number { - let hash = 0; - let chr = 0; - if (str.length === 0) { - return hash; - } - for (let i = 0; i < str.length; i++) { - chr = str.charCodeAt(i); - hash = (hash << 5) - hash + chr; // eslint-disable-line no-bitwise - hash |= 0; // eslint-disable-line no-bitwise - } - return hash < 0 ? hash * -2 : hash; -} - type Item = SectionItem; interface Props { diff --git a/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts b/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts index 426dc3d4fa342..a5f8f014430c7 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts @@ -7,8 +7,9 @@ import Boom from '@hapi/boom'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + import { NODES_INFO_PRIVILEGES } from '../../../common/constants'; -import { isPopulatedObject } from '../../../common/shared_imports'; import { RouteDependencies } from '../../types'; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 3eeda946ada8f..ae829d05815fb 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -209,48 +209,14 @@ "xpack.lens.dragDrop.announce.cancelled": "Mouvement annulé. {label} revenu à sa position initiale", "xpack.lens.dragDrop.announce.cancelledItem": "Mouvement annulé. {label} revenu au groupe {groupLabel} à la position {position}", "xpack.lens.dragDrop.announce.combine.short": " Maintenir la touche Contrôle enfoncée pour combiner", - "xpack.lens.dragDrop.announce.dropped.combineCompatible": "Combinaison de {label} avec {dropGroupLabel} à la position {dropPosition} et de {dropLabel} avec {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.combineIncompatible": "Conversion de {label} en {nextLabel} dans le groupe {groupLabel} à la position {position} et combinaison avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition}", - "xpack.lens.dragDrop.announce.dropped.duplicated": "{label} dupliqué dans le groupe {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.duplicateIncompatible": "Copie de {label} convertie en {nextLabel} et ajoutée au groupe {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.moveCompatible": "{label} déplacé dans le groupe {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.moveIncompatible": "{label} converti en {nextLabel} et déplacé dans le groupe {groupLabel} à la position {position}", "xpack.lens.dragDrop.announce.dropped.reordered": "{label} réorganisé dans le groupe {groupLabel} de la position {prevPosition} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.replaceDuplicateIncompatible": "Copie de {label} convertie en {nextLabel} et {dropLabel} remplacé dans le groupe {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.replaceIncompatible": "{label} converti en {nextLabel} et {dropLabel} remplacé dans le groupe {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.swapCompatible": "{label} déplacé dans {dropGroupLabel} à la position {dropPosition} et {dropLabel} dans {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.dropped.swapIncompatible": "{label} converti en {nextLabel} dans le groupe {groupLabel} à la position {position} et permuté avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition}", - "xpack.lens.dragDrop.announce.droppedDefault": "{label} ajouté dans le groupe {dropGroupLabel} à la position {position}", "xpack.lens.dragDrop.announce.droppedNoPosition": "{label} ajouté à {dropLabel}", "xpack.lens.dragDrop.announce.duplicate.short": " Maintenez la touche Alt ou Option enfoncée pour dupliquer.", - "xpack.lens.dragDrop.announce.duplicated.combine": "Combiner {dropLabel} avec {label} dans {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.duplicated.replace": "{dropLabel} remplacé par {label} dans {groupLabel} à la position {position}", - "xpack.lens.dragDrop.announce.duplicated.replaceDuplicateCompatible": "{dropLabel} remplacé par une copie de {label} dans {groupLabel} à la position {position}", "xpack.lens.dragDrop.announce.lifted": "{label} levé", - "xpack.lens.dragDrop.announce.selectedTarget.combine": "Combinez {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} avec {label}. Appuyez sur la barre d’espace ou sur Entrée pour combiner.", - "xpack.lens.dragDrop.announce.selectedTarget.combineCompatible": "Combinez {label} dans le groupe {groupLabel} à la position {position} avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition}. Maintenez la touche Contrôle enfoncée et appuyez sur la barre d’espace ou sur Entrée pour combiner.", - "xpack.lens.dragDrop.announce.selectedTarget.combineIncompatible": "Convertissez {label} en {nextLabel} dans le groupe {groupLabel} à la position {position} et combinez avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition}. Maintenez la touche Contrôle enfoncée et appuyez sur la barre d’espace ou sur Entrée pour combiner.", - "xpack.lens.dragDrop.announce.selectedTarget.combineMain": "Vous faites glisser {label} à partir de {groupLabel} à la position {position} sur {dropLabel} à partir du groupe {dropGroupLabel} à la position {dropPosition}. Appuyer sur la barre d’espace ou sur Entrée pour combiner {dropLabel} avec {label}.{duplicateCopy}{swapCopy}{combineCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.default": "Ajoutez {label} au groupe {dropGroupLabel} à la position {position}. Appuyer sur la barre d'espace ou sur Entrée pour ajouter", "xpack.lens.dragDrop.announce.selectedTarget.defaultNoPosition": "Ajoutez {label} à {dropLabel}. Appuyer sur la barre d'espace ou sur Entrée pour ajouter", - "xpack.lens.dragDrop.announce.selectedTarget.duplicated": "Dupliquez {label} dans le groupe {dropGroupLabel} à la position {position}. Maintenir la touche Alt ou Option enfoncée et appuyer sur la barre d'espace ou sur Entrée pour dupliquer", - "xpack.lens.dragDrop.announce.selectedTarget.duplicatedInGroup": "Dupliquez {label} dans le groupe {dropGroupLabel} à la position {position}. Appuyer sur la barre d'espace ou sur Entrée pour dupliquer", - "xpack.lens.dragDrop.announce.selectedTarget.duplicateIncompatible": "Convertissez la copie de {label} en {nextLabel} et ajoutez-la au groupe {groupLabel} à la position {position}. Maintenir la touche Alt ou Option enfoncée et appuyer sur la barre d'espace ou sur Entrée pour dupliquer", - "xpack.lens.dragDrop.announce.selectedTarget.moveCompatible": "Déplacez {label} dans le groupe {dropGroupLabel} à la position {dropPosition}. Appuyer sur la barre d'espace ou sur Entrée pour déplacer", - "xpack.lens.dragDrop.announce.selectedTarget.moveCompatibleMain": "Vous faites glisser {label} de {groupLabel} à la position {position} vers la position {dropPosition} dans le groupe {dropGroupLabel}. Appuyez sur la barre d'espace ou sur Entrée pour déplacer.{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.moveIncompatible": "Convertissez {label} en {nextLabel} et déplacez-le dans le groupe {dropGroupLabel} à la position {dropPosition}. Appuyer sur la barre d'espace ou sur Entrée pour déplacer", - "xpack.lens.dragDrop.announce.selectedTarget.moveIncompatibleMain": "Vous faites glisser {label} de {groupLabel} à la position {position} vers la position {dropPosition} dans le groupe {dropGroupLabel}. Appuyez sur la barre d'espace ou sur Entrée pour convertir {label} en {nextLabel} et déplacer.{duplicateCopy}{swapCopy}", "xpack.lens.dragDrop.announce.selectedTarget.noSelected": "Aucune cible sélectionnée. Utiliser les touches fléchées pour sélectionner une cible", "xpack.lens.dragDrop.announce.selectedTarget.reordered": "Réorganisez {label} dans le groupe {groupLabel} de la position {prevPosition} à la position {position}. Appuyer sur la barre d'espace ou sur Entrée pour réorganiser", "xpack.lens.dragDrop.announce.selectedTarget.reorderedBack": "{label} revenu à sa position initiale {prevPosition}", - "xpack.lens.dragDrop.announce.selectedTarget.replace": "Remplacez {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} avec {label}. Appuyez sur la barre d'espace ou sur Entrée pour remplacer.", - "xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateCompatible": "Dupliquez {label} et remplacez {dropLabel} dans {groupLabel} à la position {position}. Maintenir la touche Alt ou Option enfoncée et appuyer sur la barre d'espace ou sur Entrée pour dupliquer et remplacer", - "xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateIncompatible": "Convertissez la copie de {label} en {nextLabel} et remplacez {dropLabel} dans le groupe {groupLabel} à la position {position}. Maintenir la touche Alt ou Option enfoncée et appuyer sur la barre d'espace ou sur Entrée pour dupliquer et remplacer", - "xpack.lens.dragDrop.announce.selectedTarget.replaceIncompatible": "Convertissez {label} en {nextLabel} et remplacez {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition}. Appuyer sur la barre d'espace ou sur Entrée pour remplacer", - "xpack.lens.dragDrop.announce.selectedTarget.replaceIncompatibleMain": "Vous faites glisser {label} à partir de {groupLabel} à la position {position} sur {dropLabel} à partir du groupe {dropGroupLabel} à la position {dropPosition}. Appuyer sur la barre d'espace ou sur Entrée pour convertir {label} en {nextLabel} et remplacer {dropLabel}.{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.replaceMain": "Vous faites glisser {label} à partir de {groupLabel} à la position {position} sur {dropLabel} à partir du groupe {dropGroupLabel} à la position {dropPosition}. Appuyer sur la barre d'espace ou sur Entrée pour remplacer {dropLabel} par {label}.{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.swapCompatible": "Permutez {label} dans le groupe {groupLabel} à la position {position} avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition}. Maintenir la touche Maj enfoncée tout en appuyant sur la barre d'espace ou sur Entrée pour permuter", - "xpack.lens.dragDrop.announce.selectedTarget.swapIncompatible": "Convertir {label} en {nextLabel} dans le groupe {groupLabel} à la position {position} et permutez avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition}. Maintenir la touche Maj enfoncée tout en appuyant sur la barre d'espace ou sur Entrée pour permuter", "xpack.lens.dragDrop.announce.swap.short": " Maintenez la touche Maj enfoncée pour permuter.", "xpack.lens.dragDrop.combine": "Combiner", "xpack.lens.dragDrop.control": "Contrôle", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2fa35f6e723b2..e8e2fc397bf63 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -214,43 +214,14 @@ "xpack.lens.dragDrop.announce.cancelled": "移動がキャンセルされました。{label}は初期位置に戻りました", "xpack.lens.dragDrop.announce.cancelledItem": "移動がキャンセルされました。{label}は位置{position}の{groupLabel}グループに戻りました", "xpack.lens.dragDrop.announce.combine.short": " Ctrlを押しながら結合します", - "xpack.lens.dragDrop.announce.dropped.combineCompatible": "位置{dropPosition}で{label}を{dropGroupLabel}に移動し、位置{position}で{dropLabel}を {groupLabel}グループに結合しました", - "xpack.lens.dragDrop.announce.dropped.combineIncompatible": "位置{position}で{label}を{groupLabel}の{nextLabel}に変換し、位置{dropPosition}で{dropGroupLabel}グループの{dropLabel}と結合しました", - "xpack.lens.dragDrop.announce.dropped.duplicated": "位置{position}の{groupLabel}グループで{label}を複製しました", - "xpack.lens.dragDrop.announce.dropped.duplicateIncompatible": "{label}のコピーを{nextLabel}に変換し、位置{position}の{groupLabel}グループに追加しました", - "xpack.lens.dragDrop.announce.dropped.moveCompatible": "位置{position}の{groupLabel}グループに{label}を移動しました", - "xpack.lens.dragDrop.announce.dropped.moveIncompatible": "{label}を{nextLabel}に変換し、位置{position}の{groupLabel}グループに移動しました", "xpack.lens.dragDrop.announce.dropped.reordered": "{groupLabel}グループの{label}を位置{prevPosition}から位置{position}に並べ替えました", - "xpack.lens.dragDrop.announce.dropped.replaceDuplicateIncompatible": "{label}のコピーを{nextLabel}に変換し、位置{position}の{groupLabel}グループで{dropLabel}を置き換えました", - "xpack.lens.dragDrop.announce.dropped.replaceIncompatible": "{label}を{nextLabel}に変換し、位置{position}の{groupLabel}グループで{dropLabel}を置き換えました", - "xpack.lens.dragDrop.announce.dropped.swapCompatible": "位置{dropPosition}で{label}を{dropGroupLabel}に移動し、位置{position}で{dropLabel}を {groupLabel}グループに移動しました", - "xpack.lens.dragDrop.announce.dropped.swapIncompatible": "位置{position}で{label}を{groupLabel}の{nextLabel}に変換し、位置{dropPosition}で{dropGroupLabel}グループの{dropLabel}と入れ替えました", - "xpack.lens.dragDrop.announce.droppedDefault": "位置{position}の{dropGroupLabel}グループで{label}を追加しました", "xpack.lens.dragDrop.announce.droppedNoPosition": "{label}を{dropLabel}に追加しました", "xpack.lens.dragDrop.announce.duplicate.short": " AltキーまたはOptionを押し続けると複製します。", - "xpack.lens.dragDrop.announce.duplicated.combine": "位置{position}の{groupLabel}で{dropLabel}を{label}と結合しました", - "xpack.lens.dragDrop.announce.duplicated.replace": "位置{position}の{groupLabel}で{dropLabel}を{label}に置き換えました", - "xpack.lens.dragDrop.announce.duplicated.replaceDuplicateCompatible": "位置{position}の{groupLabel}で{dropLabel}を{label}のコピーに置き換えました", "xpack.lens.dragDrop.announce.lifted": "{label}を上げました", - "xpack.lens.dragDrop.announce.selectedTarget.combineCompatible": "位置{position}の{groupLabel}の{label}を、位置{dropPosition}の{dropGroupLabel}グループの{dropLabel}と結合します。Ctrlキーを押しながらスペースバーまたはEnterキーを押すと、結合します", - "xpack.lens.dragDrop.announce.selectedTarget.combineIncompatible": "位置{position}で{label}を{groupLabel}の{nextLabel}に変換し、位置{dropPosition}で{dropGroupLabel}グループの{dropLabel}と結合します。Ctrlキーを押しながらスペースバーまたはEnterキーを押すと、結合します", - "xpack.lens.dragDrop.announce.selectedTarget.default": "位置{position}の{dropGroupLabel}グループに{label}を追加しました。スペースまたはEnterを押して追加します", "xpack.lens.dragDrop.announce.selectedTarget.defaultNoPosition": "{label}を{dropLabel}に追加します。スペースまたはEnterを押して追加します", - "xpack.lens.dragDrop.announce.selectedTarget.duplicated": "位置{position}の{dropGroupLabel}グループに{label}を複製しました。AltまたはOptionを押しながらスペースバーまたはEnterキーを押すと、複製します", - "xpack.lens.dragDrop.announce.selectedTarget.duplicatedInGroup": "位置{position}の{dropGroupLabel}グループに{label}を複製しました。スペースまたはEnterを押して複製します", - "xpack.lens.dragDrop.announce.selectedTarget.duplicateIncompatible": "{label}のコピーを{nextLabel}に変換し、位置{position}で{groupLabel}グループに移動します。AltまたはOptionを押しながらスペースバーまたはEnterキーを押すと、複製します", - "xpack.lens.dragDrop.announce.selectedTarget.moveCompatibleMain": "位置{position}で{groupLabel}の{label}を{dropGroupLabel}グループの位置{dropPosition}にドラッグしています。スペースバーまたはEnterキーを押すと移動します。{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.moveIncompatible": "{label}を{nextLabel}に変換し、位置{dropPosition}で{dropGroupLabel}グループに移動します。スペースまたはEnterを押して移動します", - "xpack.lens.dragDrop.announce.selectedTarget.moveIncompatibleMain": "位置{position}で{groupLabel}の{label}を{dropGroupLabel}グループの位置{dropPosition}にドラッグしています。スペースバーまたはEnterキーを押して、{label}を{nextLabel}に変換して移動します。{duplicateCopy}{swapCopy}", "xpack.lens.dragDrop.announce.selectedTarget.noSelected": "対象が選択されていません。矢印キーを使用して対象を選択してください", "xpack.lens.dragDrop.announce.selectedTarget.reordered": "{groupLabel}グループの{label}を位置{prevPosition}から位置{position}に並べ替えます。スペースまたはEnterを押して並べ替えます", "xpack.lens.dragDrop.announce.selectedTarget.reorderedBack": "{label}は初期位置{prevPosition}に戻りました", - "xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateCompatible": "位置{position}で{label}を複製し、{groupLabel}グループで{dropLabel}を置き換えます。AltまたはOptionを押しながらスペースバーまたはEnterキーを押すと、複製して置換します", - "xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateIncompatible": "{label}のコピーを{nextLabel}に変換し、位置{position}で{groupLabel}グループの{dropLabel}を置き換えます。AltまたはOptionを押しながらスペースバーまたはEnterキーを押すと、複製して置換します", - "xpack.lens.dragDrop.announce.selectedTarget.replaceIncompatibleMain": "位置{position}の{groupLabel}の{label}を、位置{dropPosition}の{dropGroupLabel}グループの{dropLabel}にドラッグしています。スペースバーまたはEnterキーを押して、{label}を{nextLabel}に変換して、{dropLabel}を置き換えます。{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.replaceMain": "位置{position}の{groupLabel}の{label}を、位置{dropPosition}の{dropGroupLabel}グループの{dropLabel}にドラッグしています。スペースまたはEnterを押して、{dropLabel}を{label}で置き換えます。{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.swapCompatible": "位置{position}の{groupLabel}の{label}を、位置{dropPosition}の{dropGroupLabel}グループの{dropLabel}と入れ替えます。Shiftキーを押しながらスペースバーまたはEnterキーを押すと、入れ替えます", - "xpack.lens.dragDrop.announce.selectedTarget.swapIncompatible": "位置{position}で{label}を{groupLabel}の{nextLabel}に変換し、位置{dropPosition}で{dropGroupLabel}グループの{dropLabel}と入れ替えます。Shiftキーを押しながらスペースバーまたはEnterキーを押すと、入れ替えます", "xpack.lens.dragDrop.announce.swap.short": " Shiftキーを押すと入れ替えます。", "xpack.lens.dragDrop.combine": "結合", "xpack.lens.dragDrop.control": "Control", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 01b30dda57b2c..09d512eae30db 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -214,48 +214,14 @@ "xpack.lens.dragDrop.announce.cancelled": "移动已取消。{label} 将返回至其初始位置", "xpack.lens.dragDrop.announce.cancelledItem": "移动已取消。{label} 返回至 {groupLabel} 组中的位置 {position}", "xpack.lens.dragDrop.announce.combine.short": " 按住 Control 键组合", - "xpack.lens.dragDrop.announce.dropped.combineCompatible": "已将 {label} 组合到 {dropGroupLabel} 中的位置 {dropPosition} 并将 {dropLabel} 组合到组 {groupLabel} 中的位置 {position}", - "xpack.lens.dragDrop.announce.dropped.combineIncompatible": "已将 {label} 转换为组 {groupLabel} 中位置 {position} 上的 {nextLabel},并与组 {dropGroupLabel} 中位置 {dropPosition} 上的 {dropLabel} 组合", - "xpack.lens.dragDrop.announce.dropped.duplicated": "已在 {groupLabel} 组中的位置 {position} 复制 {label}", - "xpack.lens.dragDrop.announce.dropped.duplicateIncompatible": "已将 {label} 的副本转换为 {nextLabel} 并添加 {groupLabel} 组中的位置 {position}", - "xpack.lens.dragDrop.announce.dropped.moveCompatible": "已将 {label} 移到 {groupLabel} 组中的位置 {position}", - "xpack.lens.dragDrop.announce.dropped.moveIncompatible": "已将 {label} 转换为 {nextLabel} 并移到 {groupLabel} 组中的位置 {position}", "xpack.lens.dragDrop.announce.dropped.reordered": "已将 {groupLabel} 组中的 {label} 从位置 {prevPosition} 重新排到位置 {position}", - "xpack.lens.dragDrop.announce.dropped.replaceDuplicateIncompatible": "已将 {label} 的副本转换为 {nextLabel} 并替换了 {groupLabel} 组中位置 {position} 上的 {dropLabel}", - "xpack.lens.dragDrop.announce.dropped.replaceIncompatible": "已将 {label} 转换为 {nextLabel} 并替换了 {groupLabel} 组中位置 {position} 上的 {dropLabel}", - "xpack.lens.dragDrop.announce.dropped.swapCompatible": "已将 {label} 移至 {dropGroupLabel} 中的位置 {dropPosition} 并将 {dropLabel} 移至组 {groupLabel} 中的位置 {position}", - "xpack.lens.dragDrop.announce.dropped.swapIncompatible": "已将 {label} 转换为组 {groupLabel} 中位置 {position} 上的 {nextLabel},并与组 {dropGroupLabel} 中位置 {dropPosition} 上的 {dropLabel} 交换", - "xpack.lens.dragDrop.announce.droppedDefault": "已将 {label} 添加到 {dropGroupLabel} 组中的位置 {position}", "xpack.lens.dragDrop.announce.droppedNoPosition": "已将 {label} 添加到 {dropLabel}", "xpack.lens.dragDrop.announce.duplicate.short": " 按住 alt 或 option 键以复制。", - "xpack.lens.dragDrop.announce.duplicated.combine": "将 {dropLabel} 与 {groupLabel} 中位置 {position} 上的 {label} 组合", - "xpack.lens.dragDrop.announce.duplicated.replace": "已将 {groupLabel} 组中位置 {position} 上的 {dropLabel} 替换为 {label}", - "xpack.lens.dragDrop.announce.duplicated.replaceDuplicateCompatible": "已将 {groupLabel} 组中位置 {position} 上的 {dropLabel} 替换为 {label} 的副本", "xpack.lens.dragDrop.announce.lifted": "已提升 {label}", - "xpack.lens.dragDrop.announce.selectedTarget.combine": "将 {dropGroupLabel} 组中位置 {dropPosition} 上的 {dropLabel} 与 {label} 组合。按空格键或 enter 键组合。", - "xpack.lens.dragDrop.announce.selectedTarget.combineCompatible": "将组 {groupLabel} 中位置 {position} 上的 {label} 与组 {dropGroupLabel} 中位置 {dropPosition} 上的 {dropLabel} 组合。按住 Control 键并按空格键或 enter 键组合", - "xpack.lens.dragDrop.announce.selectedTarget.combineIncompatible": "将 {label} 转换为组 {groupLabel} 中位置 {position} 上的 {nextLabel},并与组 {dropGroupLabel} 中位置 {dropPosition} 上的 {dropLabel} 组合。按住 Control 键并按空格键或 enter 键组合", - "xpack.lens.dragDrop.announce.selectedTarget.combineMain": "您正将 {groupLabel} 中位置 {position} 上的{label} 拖到 {dropGroupLabel} 组中位置 {dropPosition} 上的 {dropLabel}。按空格键或 enter 键以将 {dropLabel} 与 {label} 组合。{duplicateCopy}{swapCopy}{combineCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.default": "将 {label} 添加到 {dropGroupLabel} 组中的位置 {position}。按空格键或 enter 键添加", "xpack.lens.dragDrop.announce.selectedTarget.defaultNoPosition": "将 {label} 添加到 {dropLabel}。按空格键或 enter 键添加", - "xpack.lens.dragDrop.announce.selectedTarget.duplicated": "将 {label} 复制到 {dropGroupLabel} 组中的位置 {position}。按住 Alt 或 Option 并按空格键或 enter 键以复制", - "xpack.lens.dragDrop.announce.selectedTarget.duplicatedInGroup": "将 {label} 复制到 {dropGroupLabel} 组中的位置 {position}。按空格键或 enter 键复制", - "xpack.lens.dragDrop.announce.selectedTarget.duplicateIncompatible": "将 {label} 转换为 {nextLabel} 并移到 {groupLabel} 组中的位置 {position}。按住 Alt 或 Option 并按空格键或 enter 键以复制", - "xpack.lens.dragDrop.announce.selectedTarget.moveCompatible": "将 {label} 移至 {dropGroupLabel} 组中的位置 {dropPosition}。按空格键或 enter 键移动", - "xpack.lens.dragDrop.announce.selectedTarget.moveCompatibleMain": "您正将 {groupLabel} 中位置 {position} 上的{label} 拖到 {dropGroupLabel} 组中的位置 {dropPosition} 上。按空格键或 enter 键移动。{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.moveIncompatible": "将 {label} 转换为 {nextLabel} 并移到 {dropGroupLabel} 组中的位置 {dropPosition}。按空格键或 enter 键移动", - "xpack.lens.dragDrop.announce.selectedTarget.moveIncompatibleMain": "您正将 {groupLabel} 中位置 {position} 上的{label} 拖到 {dropGroupLabel} 组中的位置 {dropPosition} 上。按空格键或 enter 键以将 {label} 转换为 {nextLabel} 并移动。{duplicateCopy}{swapCopy}", "xpack.lens.dragDrop.announce.selectedTarget.noSelected": "未选择任何目标。使用箭头键选择目标", "xpack.lens.dragDrop.announce.selectedTarget.reordered": "将 {groupLabel} 组中的 {label} 从位置 {prevPosition} 重新排到位置 {position}。按空格键或 enter 键重新排列", "xpack.lens.dragDrop.announce.selectedTarget.reorderedBack": "{label} 已返回至其初始位置 {prevPosition}", - "xpack.lens.dragDrop.announce.selectedTarget.replace": "将 {dropGroupLabel} 组中位置 {dropPosition} 上的 {dropLabel} 替换为 {label}。按空格键或 enter 键替换。", - "xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateCompatible": "复制 {label} 并替换 {groupLabel} 中位置 {position} 上的 {dropLabel}。按住 Alt 或 Option 并按空格键或 enter 键以复制并替换", - "xpack.lens.dragDrop.announce.selectedTarget.replaceDuplicateIncompatible": "将 {label} 的副本转换为 {nextLabel} 并替换 {groupLabel} 组中位置 {position} 上的 {dropLabel}。按住 Alt 或 Option 并按空格键或 enter 键以复制并替换", - "xpack.lens.dragDrop.announce.selectedTarget.replaceIncompatible": "将 {label} 转换为 {nextLabel} 并替换 {dropGroupLabel} 组中位置 {dropPosition} 上的 {dropLabel}。按空格键或 enter 键替换", - "xpack.lens.dragDrop.announce.selectedTarget.replaceIncompatibleMain": "您正将 {groupLabel} 中位置 {position} 上的{label} 拖到 {dropGroupLabel} 组中位置 {dropPosition} 上的 {dropLabel}。按空格键或 enter 键以将 {label} 转换为 {nextLabel} 并替换 {dropLabel}。{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.replaceMain": "您正将 {groupLabel} 中位置 {position} 上的{label} 拖到 {dropGroupLabel} 组中位置 {dropPosition} 上的 {dropLabel}。按空格键或 enter 键以将 {dropLabel} 替换为 {label}。{duplicateCopy}{swapCopy}", - "xpack.lens.dragDrop.announce.selectedTarget.swapCompatible": "将组 {groupLabel} 中位置 {position} 上的 {label} 与组 {dropGroupLabel} 中位置 {dropPosition} 上的 {dropLabel} 交换。按住 Shift 键并按空格键或 enter 键交换", - "xpack.lens.dragDrop.announce.selectedTarget.swapIncompatible": "将 {label} 转换为组 {groupLabel} 中位置 {position} 上的 {nextLabel},并与组 {dropGroupLabel} 中位置 {dropPosition} 上的 {dropLabel} 交换。按住 Shift 键并按空格键或 enter 键交换", "xpack.lens.dragDrop.announce.swap.short": " 按住 Shift 键交换。", "xpack.lens.dragDrop.combine": "组合", "xpack.lens.dragDrop.control": "Control 键", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx index fc8ad1bb31c09..88e6006a601e7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx @@ -312,7 +312,10 @@ const mockedRulesData = [ beforeEach(() => { (getIsExperimentalFeatureEnabled as jest.Mock).mockImplementation(() => false); }); -describe('Update Api Key', () => { + +// FLAKY: https://github.com/elastic/kibana/issues/134922 +// FLAKY: https://github.com/elastic/kibana/issues/134923 +describe.skip('Update Api Key', () => { const addSuccess = jest.fn(); const addError = jest.fn(); @@ -398,7 +401,8 @@ describe('Update Api Key', () => { }); }); -describe('rules_list component empty', () => { +// FLAKY: https://github.com/elastic/kibana/issues/134924 +describe.skip('rules_list component empty', () => { let wrapper: ReactWrapper; async function setup() { loadRules.mockResolvedValue({ diff --git a/x-pack/plugins/ux/e2e/journeys/core_web_vitals.ts b/x-pack/plugins/ux/e2e/journeys/core_web_vitals.ts index 4138027a6b356..afbec5c055cf1 100644 --- a/x-pack/plugins/ux/e2e/journeys/core_web_vitals.ts +++ b/x-pack/plugins/ux/e2e/journeys/core_web_vitals.ts @@ -29,7 +29,7 @@ journey('Core Web Vitals', async ({ page, params }) => { }); await loginToKibana({ page, - user: { username: 'viewer_user', password: 'changeme' }, + user: { username: 'viewer', password: 'changeme' }, }); }); diff --git a/x-pack/plugins/ux/e2e/journeys/url_ux_query.journey.ts b/x-pack/plugins/ux/e2e/journeys/url_ux_query.journey.ts index f5e8fd19a9557..1762cd22a1186 100644 --- a/x-pack/plugins/ux/e2e/journeys/url_ux_query.journey.ts +++ b/x-pack/plugins/ux/e2e/journeys/url_ux_query.journey.ts @@ -29,7 +29,7 @@ journey('UX URL Query', async ({ page, params }) => { }); await loginToKibana({ page, - user: { username: 'viewer_user', password: 'changeme' }, + user: { username: 'viewer', password: 'changeme' }, }); }); diff --git a/x-pack/plugins/ux/e2e/journeys/ux_js_errors.journey.ts b/x-pack/plugins/ux/e2e/journeys/ux_js_errors.journey.ts index eb61a6e446013..8e124d8a5e4b7 100644 --- a/x-pack/plugins/ux/e2e/journeys/ux_js_errors.journey.ts +++ b/x-pack/plugins/ux/e2e/journeys/ux_js_errors.journey.ts @@ -34,7 +34,7 @@ journey('UX JsErrors', async ({ page, params }) => { }); await loginToKibana({ page, - user: { username: 'viewer_user', password: 'changeme' }, + user: { username: 'viewer', password: 'changeme' }, }); }); diff --git a/x-pack/test/accessibility/apps/dashboard_edit_panel.ts b/x-pack/test/accessibility/apps/dashboard_edit_panel.ts index 20b72e142f5c7..56e854f448412 100644 --- a/x-pack/test/accessibility/apps/dashboard_edit_panel.ts +++ b/x-pack/test/accessibility/apps/dashboard_edit_panel.ts @@ -22,7 +22,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Dashboard Edit Panel Accessibility', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/dashboard/drilldowns'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns' + ); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); await PageObjects.common.navigateToApp('dashboard'); @@ -31,7 +34,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/dashboard/drilldowns'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('can open menu', async () => { diff --git a/x-pack/test/accessibility/apps/lens.ts b/x-pack/test/accessibility/apps/lens.ts index 18459b56c0542..854ff1b349e49 100644 --- a/x-pack/test/accessibility/apps/lens.ts +++ b/x-pack/test/accessibility/apps/lens.ts @@ -146,23 +146,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.createLayer(); await PageObjects.lens.switchToVisualization('area'); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', - operation: 'date_histogram', - field: '@timestamp', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', - operation: 'median', - field: 'bytes', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'median', + field: 'bytes', + }); await a11y.testAppSnapshot(); }); diff --git a/x-pack/test/api_integration/apis/ml/modules/get_module.ts b/x-pack/test/api_integration/apis/ml/modules/get_module.ts index 5810b4bf7e6c8..4ff71201d9ad9 100644 --- a/x-pack/test/api_integration/apis/ml/modules/get_module.ts +++ b/x-pack/test/api_integration/apis/ml/modules/get_module.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; -import { isPopulatedObject } from '@kbn/ml-plugin/common/util/object_utils'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { USER } from '../../../../functional/services/ml/security_common'; import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api'; diff --git a/x-pack/test/api_integration/apis/monitoring/elasticsearch_settings/set_collection_enabled.js b/x-pack/test/api_integration/apis/monitoring/elasticsearch_settings/set_collection_enabled.js index ea94031c782c3..54c3eaa7f9049 100644 --- a/x-pack/test/api_integration/apis/monitoring/elasticsearch_settings/set_collection_enabled.js +++ b/x-pack/test/api_integration/apis/monitoring/elasticsearch_settings/set_collection_enabled.js @@ -28,7 +28,7 @@ export default function ({ getService }) { }; await esSupertest.put('/_cluster/settings').send(disableCollection).expect(200); - await esDeleteAllIndices('/.monitoring-*'); + await esDeleteAllIndices('.monitoring-*'); }); it('should set collection.enabled to true', async () => { diff --git a/x-pack/test/apm_api_integration/common/authentication.ts b/x-pack/test/apm_api_integration/common/authentication.ts index 288f483c8c005..28dffac7f80ca 100644 --- a/x-pack/test/apm_api_integration/common/authentication.ts +++ b/x-pack/test/apm_api_integration/common/authentication.ts @@ -7,25 +7,33 @@ import { Client } from '@elastic/elasticsearch'; import { PrivilegeType } from '@kbn/apm-plugin/common/privilege_type'; +import { ToolingLog } from '@kbn/tooling-log'; +import { omit } from 'lodash'; +import { KbnClientRequesterError } from '@kbn/test'; +import { AxiosError } from 'axios'; import { SecurityServiceProvider } from '../../../../test/common/services/security'; type SecurityService = Awaited>; -export enum ApmUser { +export enum ApmUsername { noAccessUser = 'no_access_user', - viewerUser = 'viewer_user', - editorUser = 'editor_user', + viewerUser = 'viewer', + editorUser = 'editor', apmAnnotationsWriteUser = 'apm_annotations_write_user', apmReadUserWithoutMlAccess = 'apm_read_user_without_ml_access', apmManageOwnAgentKeys = 'apm_manage_own_agent_keys', apmManageOwnAndCreateAgentKeys = 'apm_manage_own_and_create_agent_keys', } -const roles = { - [ApmUser.noAccessUser]: {}, - [ApmUser.viewerUser]: {}, - [ApmUser.editorUser]: {}, - [ApmUser.apmReadUserWithoutMlAccess]: { +export enum ApmCustomRolename { + apmReadUserWithoutMlAccess = 'apm_read_user_without_ml_access', + apmAnnotationsWriteUser = 'apm_annotations_write_user', + apmManageOwnAgentKeys = 'apm_manage_own_agent_keys', + apmManageOwnAndCreateAgentKeys = 'apm_manage_own_and_create_agent_keys', +} + +const customRoles = { + [ApmCustomRolename.apmReadUserWithoutMlAccess]: { elasticsearch: { cluster: [], indices: [ @@ -43,7 +51,7 @@ const roles = { }, ], }, - [ApmUser.apmAnnotationsWriteUser]: { + [ApmCustomRolename.apmAnnotationsWriteUser]: { elasticsearch: { cluster: [], indices: [ @@ -61,12 +69,12 @@ const roles = { ], }, }, - [ApmUser.apmManageOwnAgentKeys]: { + [ApmCustomRolename.apmManageOwnAgentKeys]: { elasticsearch: { cluster: ['manage_own_api_key'], }, }, - [ApmUser.apmManageOwnAndCreateAgentKeys]: { + [ApmCustomRolename.apmManageOwnAndCreateAgentKeys]: { applications: [ { application: 'apm', @@ -77,55 +85,101 @@ const roles = { }, }; -const users = { - [ApmUser.noAccessUser]: { - roles: [], - }, - [ApmUser.viewerUser]: { - roles: ['viewer'], +const users: Record< + ApmUsername, + { builtInRoleNames?: string[]; customRoleNames?: ApmCustomRolename[] } +> = { + [ApmUsername.noAccessUser]: {}, + [ApmUsername.viewerUser]: { + builtInRoleNames: ['viewer'], }, - [ApmUser.editorUser]: { - roles: ['editor'], + [ApmUsername.editorUser]: { + builtInRoleNames: ['editor'], }, - [ApmUser.apmReadUserWithoutMlAccess]: { - roles: [ApmUser.apmReadUserWithoutMlAccess], + [ApmUsername.apmReadUserWithoutMlAccess]: { + customRoleNames: [ApmCustomRolename.apmReadUserWithoutMlAccess], }, - [ApmUser.apmAnnotationsWriteUser]: { - roles: ['editor', ApmUser.apmAnnotationsWriteUser], + [ApmUsername.apmAnnotationsWriteUser]: { + builtInRoleNames: ['editor'], + customRoleNames: [ApmCustomRolename.apmAnnotationsWriteUser], }, - [ApmUser.apmManageOwnAgentKeys]: { - roles: ['editor', ApmUser.apmManageOwnAgentKeys], + [ApmUsername.apmManageOwnAgentKeys]: { + builtInRoleNames: ['editor'], + customRoleNames: [ApmCustomRolename.apmManageOwnAgentKeys], }, - [ApmUser.apmManageOwnAndCreateAgentKeys]: { - roles: ['editor', ApmUser.apmManageOwnAgentKeys, ApmUser.apmManageOwnAndCreateAgentKeys], + [ApmUsername.apmManageOwnAndCreateAgentKeys]: { + builtInRoleNames: ['editor'], + customRoleNames: [ + ApmCustomRolename.apmManageOwnAgentKeys, + ApmCustomRolename.apmManageOwnAndCreateAgentKeys, + ], }, }; -export async function createApmUser(security: SecurityService, apmUser: ApmUser, es: Client) { - const role = roles[apmUser]; - const user = users[apmUser]; +function logErrorResponse(logger: ToolingLog, e: Error) { + if (e instanceof KbnClientRequesterError) { + logger.error(`KbnClientRequesterError: ${JSON.stringify(e.axiosError?.response?.data)}`); + } else if (e instanceof AxiosError) { + logger.error(`AxiosError: ${JSON.stringify(e.response?.data)}`); + } else { + logger.error(`Unknown error: ${e.constructor.name}`); + } +} + +export async function createApmUser({ + username, + security, + es, + logger, +}: { + username: ApmUsername; + security: SecurityService; + es: Client; + logger: ToolingLog; +}) { + const user = users[username]; - if (!role || !user) { - throw new Error(`No configuration found for ${apmUser}`); + if (!user) { + throw new Error(`No configuration found for ${username}`); } - if ('applications' in role) { - // Add application privileges with es client as they are not supported by - // security.user.create. They are preserved when updating the role below - await es.security.putRole({ - name: apmUser, - body: role, + const { builtInRoleNames = [], customRoleNames = [] } = user; + + try { + // create custom roles + await Promise.all( + customRoleNames.map(async (roleName) => createCustomRole({ roleName, security, es })) + ); + + // create user + await security.user.create(username, { + full_name: username, + password: APM_TEST_PASSWORD, + roles: [...builtInRoleNames, ...customRoleNames], }); - delete (role as any).applications; + } catch (e) { + logErrorResponse(logger, e); + throw e; } +} - await security.role.create(apmUser, role); +async function createCustomRole({ + roleName, + security, + es, +}: { + roleName: ApmCustomRolename; + security: SecurityService; + es: Client; +}) { + const role = customRoles[roleName]; - await security.user.create(apmUser, { - full_name: apmUser, - password: APM_TEST_PASSWORD, - roles: user.roles, - }); + // Add application privileges with es client as they are not supported by + // security.user.create. They are preserved when updating the role below + if ('applications' in role) { + await es.security.putRole({ name: roleName, body: role }); + } + await security.role.create(roleName, omit(role, 'applications')); } export const APM_TEST_PASSWORD = 'changeme'; diff --git a/x-pack/test/apm_api_integration/common/config.ts b/x-pack/test/apm_api_integration/common/config.ts index 4b56ad52c2e3f..3c9e99d645c7b 100644 --- a/x-pack/test/apm_api_integration/common/config.ts +++ b/x-pack/test/apm_api_integration/common/config.ts @@ -9,9 +9,10 @@ import { FtrConfigProviderContext } from '@kbn/test'; import supertest from 'supertest'; import { format, UrlObject } from 'url'; import { Client } from '@elastic/elasticsearch'; +import { ToolingLog } from '@kbn/tooling-log'; import { SecurityServiceProvider } from '../../../../test/common/services/security'; import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_context'; -import { createApmUser, APM_TEST_PASSWORD, ApmUser } from './authentication'; +import { createApmUser, APM_TEST_PASSWORD, ApmUsername } from './authentication'; import { APMFtrConfigName } from '../configs'; import { createApmApiClient } from './apm_api_supertest'; import { RegistryProvider } from './registry'; @@ -26,34 +27,42 @@ export interface ApmFtrConfig { type SecurityService = Awaited>; -function getLegacySupertestClient(kibanaServer: UrlObject, apmUser: ApmUser) { +function getLegacySupertestClient(kibanaServer: UrlObject, username: ApmUsername) { return async (context: InheritedFtrProviderContext) => { const security = context.getService('security'); const es = context.getService('es'); + const logger = context.getService('log'); await security.init(); - await createApmUser(security, apmUser, es); + await createApmUser({ security, username, es, logger }); const url = format({ ...kibanaServer, - auth: `${apmUser}:${APM_TEST_PASSWORD}`, + auth: `${username}:${APM_TEST_PASSWORD}`, }); return supertest(url); }; } -async function getApmApiClient( - kibanaServer: UrlObject, - security: SecurityService, - apmUser: ApmUser, - es: Client -) { - await createApmUser(security, apmUser, es); +async function getApmApiClient({ + kibanaServer, + security, + username, + es, + logger, +}: { + kibanaServer: UrlObject; + security: SecurityService; + username: ApmUsername; + es: Client; + logger: ToolingLog; +}) { + await createApmUser({ security, username, es, logger }); const url = format({ ...kibanaServer, - auth: `${apmUser}:${APM_TEST_PASSWORD}`, + auth: `${username}:${APM_TEST_PASSWORD}`, }); return createApmApiClient(supertest(url)); @@ -85,50 +94,83 @@ export function createTestConfig(config: ApmFtrConfig) { apmApiClient: async (context: InheritedFtrProviderContext) => { const security = context.getService('security'); const es = context.getService('es'); + const logger = context.getService('log'); + await security.init(); return { - noAccessUser: await getApmApiClient(servers.kibana, security, ApmUser.noAccessUser, es), - readUser: await getApmApiClient(servers.kibana, security, ApmUser.viewerUser, es), - writeUser: await getApmApiClient(servers.kibana, security, ApmUser.editorUser, es), - annotationWriterUser: await getApmApiClient( - servers.kibana, + noAccessUser: await getApmApiClient({ + kibanaServer: servers.kibana, + security, + username: ApmUsername.noAccessUser, + es, + logger, + }), + readUser: await getApmApiClient({ + kibanaServer: servers.kibana, + security, + username: ApmUsername.viewerUser, + es, + logger, + }), + writeUser: await getApmApiClient({ + kibanaServer: servers.kibana, security, - ApmUser.apmAnnotationsWriteUser, - es - ), - noMlAccessUser: await getApmApiClient( - servers.kibana, + username: ApmUsername.editorUser, + es, + logger, + }), + annotationWriterUser: await getApmApiClient({ + kibanaServer: servers.kibana, security, - ApmUser.apmReadUserWithoutMlAccess, - es - ), - manageOwnAgentKeysUser: await getApmApiClient( - servers.kibana, + username: ApmUsername.apmAnnotationsWriteUser, + es, + logger, + }), + noMlAccessUser: await getApmApiClient({ + kibanaServer: servers.kibana, security, - ApmUser.apmManageOwnAgentKeys, - es - ), - createAndAllAgentKeysUser: await getApmApiClient( - servers.kibana, + username: ApmUsername.apmReadUserWithoutMlAccess, + es, + logger, + }), + manageOwnAgentKeysUser: await getApmApiClient({ + kibanaServer: servers.kibana, security, - ApmUser.apmManageOwnAndCreateAgentKeys, - es - ), + username: ApmUsername.apmManageOwnAgentKeys, + es, + logger, + }), + createAndAllAgentKeysUser: await getApmApiClient({ + kibanaServer: servers.kibana, + security, + username: ApmUsername.apmManageOwnAndCreateAgentKeys, + es, + logger, + }), }; }, ml: MachineLearningAPIProvider, // legacy clients - legacySupertestAsNoAccessUser: getLegacySupertestClient(kibanaServer, ApmUser.noAccessUser), - legacySupertestAsApmReadUser: getLegacySupertestClient(kibanaServer, ApmUser.viewerUser), - legacySupertestAsApmWriteUser: getLegacySupertestClient(kibanaServer, ApmUser.editorUser), + legacySupertestAsNoAccessUser: getLegacySupertestClient( + kibanaServer, + ApmUsername.noAccessUser + ), + legacySupertestAsApmReadUser: getLegacySupertestClient( + kibanaServer, + ApmUsername.viewerUser + ), + legacySupertestAsApmWriteUser: getLegacySupertestClient( + kibanaServer, + ApmUsername.editorUser + ), legacySupertestAsApmAnnotationsWriteUser: getLegacySupertestClient( kibanaServer, - ApmUser.apmAnnotationsWriteUser + ApmUsername.apmAnnotationsWriteUser ), legacySupertestAsApmReadUserWithoutMlAccess: getLegacySupertestClient( kibanaServer, - ApmUser.apmReadUserWithoutMlAccess + ApmUsername.apmReadUserWithoutMlAccess ), }, junit: { diff --git a/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts b/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts index 4a32ef4a023a6..2f607cecb75bb 100644 --- a/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/agent_keys/agent_keys.spec.ts @@ -9,7 +9,7 @@ import { first } from 'lodash'; import { PrivilegeType } from '@kbn/apm-plugin/common/privilege_type'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { ApmApiError, ApmApiSupertest } from '../../../common/apm_api_supertest'; -import { ApmUser } from '../../../common/authentication'; +import { ApmUsername } from '../../../common/authentication'; export default function ApiTest({ getService }: FtrProviderContext) { const registry = getService('registry'); @@ -92,7 +92,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { () => { afterEach(async () => { await esClient.security.invalidateApiKey({ - username: ApmUser.apmManageOwnAndCreateAgentKeys, + username: ApmUsername.apmManageOwnAndCreateAgentKeys, }); }); diff --git a/x-pack/test/functional/apps/dashboard/group3/drilldowns/index.ts b/x-pack/test/functional/apps/dashboard/group3/drilldowns/index.ts index eaa1189ab1007..a8af67665e845 100644 --- a/x-pack/test/functional/apps/dashboard/group3/drilldowns/index.ts +++ b/x-pack/test/functional/apps/dashboard/group3/drilldowns/index.ts @@ -16,12 +16,15 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); - await esArchiver.load('x-pack/test/functional/es_archives/dashboard/drilldowns'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns' + ); await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/dashboard/drilldowns'); + await kibanaServer.savedObjects.cleanStandardList(); }); loadTestFile(require.resolve('./dashboard_to_dashboard_drilldown')); diff --git a/x-pack/test/functional/apps/discover/value_suggestions.ts b/x-pack/test/functional/apps/discover/value_suggestions.ts index 5afd3d53ca85b..3151f729aa58c 100644 --- a/x-pack/test/functional/apps/discover/value_suggestions.ts +++ b/x-pack/test/functional/apps/discover/value_suggestions.ts @@ -13,7 +13,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const queryBar = getService('queryBar'); const filterBar = getService('filterBar'); - const docTable = getService('docTable'); + const dataGrid = getService('dataGrid'); const PageObjects = getPageObjects(['common', 'timePicker', 'settings', 'context']); async function setAutocompleteUseTimeRange(value: boolean) { @@ -27,16 +27,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('value suggestions', function describeIndexTests() { before(async function () { + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); - await esArchiver.load('x-pack/test/functional/es_archives/dashboard/drilldowns'); + + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns' + ); await kibanaServer.uiSettings.update({ - 'doc_table:legacy': true, + 'doc_table:legacy': false, }); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/dashboard/drilldowns'); await kibanaServer.uiSettings.unset('doc_table:legacy'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('useTimeRange enabled', () => { @@ -86,9 +90,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); // navigate to context - await docTable.clickRowToggle({ rowIndex: 0 }); - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - await rowActions[0].click(); + await dataGrid.clickRowToggle({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); + await rowActions[1].click(); await PageObjects.context.waitUntilContextLoadingHasFinished(); // Apply filter in context view diff --git a/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts b/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts index 8d95d85a88e1e..7d8f8a302b05c 100644 --- a/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts +++ b/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts @@ -24,7 +24,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await kibanaServer.uiSettings.replace({ defaultIndex: 'without-timefield' }); await kibanaServer.uiSettings.update({ - 'doc_table:legacy': true, + 'doc_table:legacy': false, }); }); diff --git a/x-pack/test/functional/apps/lens/group1/smokescreen.ts b/x-pack/test/functional/apps/lens/group1/smokescreen.ts index 70887b337114f..2f82218b42a7a 100644 --- a/x-pack/test/functional/apps/lens/group1/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/group1/smokescreen.ts @@ -125,23 +125,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await PageObjects.lens.hasChartSwitchWarning('line')).to.eql(false); await PageObjects.lens.switchToVisualization('line'); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', - operation: 'terms', - field: 'geo.src', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'terms', + field: 'geo.src', + }); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', - operation: 'median', - field: 'bytes', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'median', + field: 'bytes', + }); expect(await PageObjects.lens.getLayerCount()).to.eql(2); await PageObjects.lens.removeLayer(); @@ -308,23 +302,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.createLayer(); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', - operation: 'terms', - field: 'geo.src', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'terms', + field: 'geo.src', + }); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', - operation: 'average', - field: 'bytes', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'average', + field: 'bytes', + }); await PageObjects.lens.save('twolayerchart'); await testSubjects.click('lnsSuggestion-asDonut > lnsSuggestion'); diff --git a/x-pack/test/functional/apps/lens/group1/table.ts b/x-pack/test/functional/apps/lens/group1/table.ts index 18ecc2e90cfe4..7bf9b49c53d8d 100644 --- a/x-pack/test/functional/apps/lens/group1/table.ts +++ b/x-pack/test/functional/apps/lens/group1/table.ts @@ -73,10 +73,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should allow to transpose columns', async () => { - await PageObjects.lens.dragDimensionToDimension( - 'lnsDatatable_rows > lns-dimensionTrigger', - 'lnsDatatable_columns > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsDatatable_rows > lns-dimensionTrigger', + to: 'lnsDatatable_columns > lns-empty-dimension', + }); expect(await PageObjects.lens.getDatatableHeaderText(0)).to.equal('@timestamp per 3 hours'); expect(await PageObjects.lens.getDatatableHeaderText(1)).to.equal( '169.228.188.120 › Average of bytes' diff --git a/x-pack/test/functional/apps/lens/group2/dashboard.ts b/x-pack/test/functional/apps/lens/group2/dashboard.ts index 787a0a6a6d99a..a6f315deba86d 100644 --- a/x-pack/test/functional/apps/lens/group2/dashboard.ts +++ b/x-pack/test/functional/apps/lens/group2/dashboard.ts @@ -183,23 +183,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await PageObjects.lens.hasChartSwitchWarning('line')).to.eql(false); await PageObjects.lens.switchToVisualization('line'); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', - operation: 'date_histogram', - field: '@timestamp', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', - operation: 'median', - field: 'bytes', - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'median', + field: 'bytes', + }); await PageObjects.lens.saveAndReturn(); await panelActions.openContextMenu(); diff --git a/x-pack/test/functional/apps/lens/group3/annotations.ts b/x-pack/test/functional/apps/lens/group3/annotations.ts index 2b641c6c161d4..62e5edb564871 100644 --- a/x-pack/test/functional/apps/lens/group3/annotations.ts +++ b/x-pack/test/functional/apps/lens/group3/annotations.ts @@ -51,10 +51,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should duplicate the style when duplicating an annotation and group them in the chart', async () => { // drag and drop to the empty field to generate a duplicate - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_xAnnotationsPanel > lns-dimensionTrigger', - 'lnsXY_xAnnotationsPanel > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_xAnnotationsPanel > lns-dimensionTrigger', + to: 'lnsXY_xAnnotationsPanel > lns-empty-dimension', + }); await ( await find.byCssSelector( diff --git a/x-pack/test/functional/apps/lens/group3/drag_and_drop.ts b/x-pack/test/functional/apps/lens/group3/drag_and_drop.ts index dec72008d6f04..626527a9c35cf 100644 --- a/x-pack/test/functional/apps/lens/group3/drag_and_drop.ts +++ b/x-pack/test/functional/apps/lens/group3/drag_and_drop.ts @@ -8,8 +8,10 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function ({ getPageObjects }: FtrProviderContext) { +export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['visualize', 'lens', 'common', 'header']); + + const listingTable = getService('listingTable'); const xyChartContainer = 'xyVisChart'; describe('lens drag and drop tests', () => { @@ -72,10 +74,10 @@ export default function ({ getPageObjects }: FtrProviderContext) { await PageObjects.lens.getDimensionTriggersTexts('lnsXY_splitDimensionPanel') ).to.eql(['Top 3 values of clientip']); - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_xDimensionPanel > lns-dimensionTrigger', - 'lnsXY_splitDimensionPanel > lns-dimensionTrigger' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lns-layerPanel-0 > lnsXY_xDimensionPanel > lns-dimensionTrigger', + to: 'lns-layerPanel-0 > lnsXY_splitDimensionPanel > lns-dimensionTrigger', + }); expect(await PageObjects.lens.getDimensionTriggersTexts('lnsXY_xDimensionPanel')).to.eql( [] @@ -90,10 +92,10 @@ export default function ({ getPageObjects }: FtrProviderContext) { await PageObjects.lens.getDimensionTriggersTexts('lnsXY_splitDimensionPanel') ).to.eql(['Top 3 values of @message.raw']); - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_splitDimensionPanel > lns-dimensionTrigger', - 'lnsXY_yDimensionPanel > lns-dimensionTrigger' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_splitDimensionPanel > lns-dimensionTrigger', + to: 'lnsXY_yDimensionPanel > lns-dimensionTrigger', + }); expect( await PageObjects.lens.getDimensionTriggersTexts('lnsXY_splitDimensionPanel') @@ -106,14 +108,14 @@ export default function ({ getPageObjects }: FtrProviderContext) { ]); }); it('should duplicate the column when dragging to empty dimension in the same group', async () => { - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yDimensionPanel > lns-dimensionTrigger', - 'lnsXY_yDimensionPanel > lns-empty-dimension' - ); - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yDimensionPanel > lns-dimensionTrigger', - 'lnsXY_yDimensionPanel > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_yDimensionPanel > lns-dimensionTrigger', + to: 'lnsXY_yDimensionPanel > lns-empty-dimension', + }); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_yDimensionPanel > lns-dimensionTrigger', + to: 'lnsXY_yDimensionPanel > lns-empty-dimension', + }); expect(await PageObjects.lens.getDimensionTriggersTexts('lnsXY_yDimensionPanel')).to.eql([ 'Unique count of @message.raw', 'Unique count of @message.raw [1]', @@ -121,10 +123,10 @@ export default function ({ getPageObjects }: FtrProviderContext) { ]); }); it('should move duplicated column to non-compatible dimension group', async () => { - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yDimensionPanel > lns-dimensionTrigger', - 'lnsXY_xDimensionPanel > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_yDimensionPanel > lns-dimensionTrigger', + to: 'lnsXY_xDimensionPanel > lns-empty-dimension', + }); expect(await PageObjects.lens.getDimensionTriggersTexts('lnsXY_yDimensionPanel')).to.eql([ 'Unique count of @message.raw', 'Unique count of @message.raw [1]', @@ -340,5 +342,132 @@ export default function ({ getPageObjects }: FtrProviderContext) { ]); }); }); + + describe('dropping between layers', () => { + it('should move the column', async () => { + await PageObjects.visualize.gotoVisualizationLandingPage(); + await listingTable.searchForItemWithName('lnsXYvis'); + await PageObjects.lens.clickVisualizeListItemTitle('lnsXYvis'); + await PageObjects.lens.goToTimeRange(); + + await PageObjects.lens.createLayer('data'); + + await PageObjects.lens.dragDimensionToExtraDropType( + 'lns-layerPanel-0 > lnsXY_xDimensionPanel > lns-dimensionTrigger', + 'lns-layerPanel-1 > lnsXY_xDimensionPanel', + 'duplicate' + ); + + await PageObjects.lens.assertFocusedDimension('@timestamp [1]'); + + await PageObjects.lens.dragDimensionToExtraDropType( + 'lns-layerPanel-0 > lnsXY_yDimensionPanel > lns-dimensionTrigger', + 'lns-layerPanel-1 > lnsXY_yDimensionPanel', + 'duplicate' + ); + + await PageObjects.lens.assertFocusedDimension('Average of bytes [1]'); + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-0')).to.eql([ + '@timestamp', + 'Average of bytes', + 'Top values of ip', + ]); + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-1')).to.eql([ + '@timestamp [1]', + 'Average of bytes [1]', + ]); + }); + + it('should move formula to empty dimension', async () => { + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-dimensionTrigger', + operation: 'formula', + formula: `moving_average(average(bytes), window=5`, + }); + await PageObjects.lens.dragDimensionToExtraDropType( + 'lns-layerPanel-0 > lnsXY_yDimensionPanel > lns-dimensionTrigger', + 'lns-layerPanel-1 > lnsXY_yDimensionPanel', + 'duplicate' + ); + + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-0')).to.eql([ + '@timestamp', + 'moving_average(average(bytes), window=5)', + 'Top 3 values of ip', + ]); + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-1')).to.eql([ + '@timestamp [1]', + 'moving_average(average(bytes), window=5) [1]', + ]); + }); + + it('should replace formula with another formula', async () => { + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_yDimensionPanel > lns-dimensionTrigger', + operation: 'formula', + formula: `sum(bytes) + 5`, + }); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lns-layerPanel-0 > lnsXY_yDimensionPanel > lns-dimensionTrigger', + to: 'lns-layerPanel-1 > lnsXY_yDimensionPanel > lns-dimensionTrigger', + }); + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-0')).to.eql([ + '@timestamp', + 'Top 3 values of ip', + ]); + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-1')).to.eql([ + '@timestamp [1]', + 'moving_average(average(bytes), window=5)', + ]); + }); + it('swaps dimensions', async () => { + await PageObjects.visualize.gotoVisualizationLandingPage(); + await listingTable.searchForItemWithName('lnsXYvis'); + await PageObjects.lens.clickVisualizeListItemTitle('lnsXYvis'); + await PageObjects.lens.goToTimeRange(); + + await PageObjects.lens.createLayer('data'); + await PageObjects.lens.dragFieldToDimensionTrigger( + 'bytes', + 'lns-layerPanel-0 > lnsXY_yDimensionPanel > lns-empty-dimension' + ); + await PageObjects.lens.dragFieldToDimensionTrigger( + 'bytes', + 'lns-layerPanel-1 > lnsXY_splitDimensionPanel > lns-empty-dimension' + ); + + await PageObjects.lens.dragDimensionToExtraDropType( + 'lns-layerPanel-1 > lnsXY_splitDimensionPanel > lns-dimensionTrigger', + 'lns-layerPanel-0 > lnsXY_splitDimensionPanel', + 'swap' + ); + + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-0')).to.eql([ + '@timestamp', + 'Average of bytes', + 'Median of bytes', + 'bytes', + ]); + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-1')).to.eql([ + 'Top 3 values of ip', + ]); + }); + it('can combine dimensions', async () => { + await PageObjects.lens.dragDimensionToExtraDropType( + 'lns-layerPanel-0 > lnsXY_splitDimensionPanel > lns-dimensionTrigger', + 'lns-layerPanel-1 > lnsXY_splitDimensionPanel', + 'combine' + ); + + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-0')).to.eql([ + '@timestamp', + 'Average of bytes', + 'Median of bytes', + ]); + expect(await PageObjects.lens.getDimensionTriggersTexts('lns-layerPanel-1')).to.eql([ + 'Top values of ip + 1 other', + ]); + }); + }); }); } diff --git a/x-pack/test/functional/apps/lens/group3/error_handling.ts b/x-pack/test/functional/apps/lens/group3/error_handling.ts index 8f6659bda1562..794547fb96f05 100644 --- a/x-pack/test/functional/apps/lens/group3/error_handling.ts +++ b/x-pack/test/functional/apps/lens/group3/error_handling.ts @@ -56,10 +56,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.waitForMissingDataViewWarning(); await PageObjects.lens.openDimensionEditor('lnsXY_yDimensionPanel > lns-dimensionTrigger'); await PageObjects.lens.closeDimensionEditor(); - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yDimensionPanel > lns-dimensionTrigger', - 'lnsXY_yDimensionPanel > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_yDimensionPanel > lns-dimensionTrigger', + to: 'lnsXY_yDimensionPanel > lns-empty-dimension', + }); await PageObjects.lens.switchFirstLayerIndexPattern('log*'); await PageObjects.lens.waitForMissingDataViewWarningDisappear(); await PageObjects.lens.waitForEmptyWorkspace(); diff --git a/x-pack/test/functional/apps/lens/group3/formula.ts b/x-pack/test/functional/apps/lens/group3/formula.ts index 33a24d3aefb1c..806e892cec643 100644 --- a/x-pack/test/functional/apps/lens/group3/formula.ts +++ b/x-pack/test/functional/apps/lens/group3/formula.ts @@ -205,10 +205,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.closeDimensionEditor(); - await PageObjects.lens.dragDimensionToDimension( - 'lnsDatatable_metrics > lns-dimensionTrigger', - 'lnsDatatable_metrics > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsDatatable_metrics > lns-dimensionTrigger', + to: 'lnsDatatable_metrics > lns-empty-dimension', + }); expect(await PageObjects.lens.getDatatableCellText(1, 1)).to.eql('222,420'); expect(await PageObjects.lens.getDatatableCellText(1, 2)).to.eql('222,420'); }); @@ -249,15 +249,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.createLayer('referenceLine'); - await PageObjects.lens.configureDimension( - { - dimension: 'lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger', - operation: 'formula', - formula: `count()`, - keepOpen: true, - }, - 1 - ); + await PageObjects.lens.configureDimension({ + dimension: 'lns-layerPanel-1 > lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger', + operation: 'formula', + formula: `count()`, + keepOpen: true, + }); await PageObjects.lens.switchToStaticValue(); await PageObjects.lens.closeDimensionEditor(); @@ -280,10 +277,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { formula: `0`, }); - await PageObjects.lens.dragDimensionToDimension( - 'lnsDatatable_metrics > lns-dimensionTrigger', - 'lnsDatatable_metrics > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsDatatable_metrics > lns-dimensionTrigger', + to: 'lnsDatatable_metrics > lns-empty-dimension', + }); expect(await PageObjects.lens.getDatatableCellText(0, 0)).to.eql('0'); expect(await PageObjects.lens.getDatatableCellText(0, 1)).to.eql('0'); }); diff --git a/x-pack/test/functional/apps/lens/group3/reference_lines.ts b/x-pack/test/functional/apps/lens/group3/reference_lines.ts index f022a6cef6e7a..ab2bc48ba57b8 100644 --- a/x-pack/test/functional/apps/lens/group3/reference_lines.ts +++ b/x-pack/test/functional/apps/lens/group3/reference_lines.ts @@ -86,10 +86,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.lens.closeDimensionEditor(); // drag and drop it to the left axis - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger', - 'lnsXY_yReferenceLineRightPanel > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_yReferenceLineLeftPanel > lns-dimensionTrigger', + to: 'lnsXY_yReferenceLineRightPanel > lns-empty-dimension', + }); await testSubjects.click('lnsXY_yReferenceLineRightPanel > lns-dimensionTrigger'); expect( @@ -100,10 +100,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should duplicate also the original style when duplicating a reference line', async () => { // drag and drop to the empty field to generate a duplicate - await PageObjects.lens.dragDimensionToDimension( - 'lnsXY_yReferenceLineRightPanel > lns-dimensionTrigger', - 'lnsXY_yReferenceLineRightPanel > lns-empty-dimension' - ); + await PageObjects.lens.dragDimensionToDimension({ + from: 'lnsXY_yReferenceLineRightPanel > lns-dimensionTrigger', + to: 'lnsXY_yReferenceLineRightPanel > lns-empty-dimension', + }); await ( await find.byCssSelector( diff --git a/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js b/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js index cce6401453d21..c60ef8617f16d 100644 --- a/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js +++ b/x-pack/test/functional/apps/monitoring/enable_monitoring/index.js @@ -40,7 +40,7 @@ export default function ({ getService, getPageObjects }) { }; await esSupertest.put('/_cluster/settings').send(disableCollection).expect(200); - await esDeleteAllIndices('/.monitoring-*'); + await esDeleteAllIndices('.monitoring-*'); }); it('Monitoring enabled', async function () { diff --git a/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json b/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json deleted file mode 100644 index 220daaeb61d0e..0000000000000 --- a/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json +++ /dev/null @@ -1,263 +0,0 @@ -{ - "type": "doc", - "value": { - "id": "space:default", - "index": ".kibana", - "source": { - "space": { - "description": "This is the default space!", - "name": "Default" - }, - "type": "space" - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization☺漢字-DataTable", - "index": ".kibana", - "source": { - "type": "visualization", - "visualization": { - "description": "DataTable", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" - }, - "title": "Visualization☺漢字 DataTable", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"histogram\",\"schema\":\"bucket\",\"params\":{\"field\":\"bytes\",\"interval\":2000,\"extended_bounds\":{}}}],\"listeners\":{}}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization☺-VerticalBarChart", - "index": ".kibana", - "source": { - "type": "visualization", - "visualization": { - "description": "VerticalBarChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" - }, - "title": "Visualization☺ VerticalBarChart", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization-TileMap", - "index": ".kibana", - "source": { - "type": "visualization", - "visualization": { - "description": "TileMap", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" - }, - "title": "Visualization TileMap", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"tile_map\",\"params\":{\"mapType\":\"Scaled Circle Markers\",\"isDesaturated\":true,\"addTooltip\":true,\"heatMaxZoom\":16,\"heatMinOpacity\":0.1,\"heatRadius\":25,\"heatBlur\":15,\"heatNormalizeData\":true,\"wms\":{\"enabled\":false,\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\",\"options\":{\"version\":\"1.3.0\",\"layers\":\"0\",\"format\":\"image/png\",\"transparent\":true,\"attribution\":\"Maps provided by USGS\",\"styles\":\"\"}}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"geohash_grid\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.coordinates\",\"autoPrecision\":true,\"precision\":2}}],\"listeners\":{}}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "index-pattern:logstash-*", - "index": ".kibana", - "source": { - "index-pattern": { - "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", - "timeFieldName": "@timestamp", - "title": "logstash-*" - }, - "type": "index-pattern" - } - } -} - -{ - "type": "doc", - "value": { - "id": "index-pattern:logstash*", - "index": ".kibana", - "source": { - "index-pattern": { - "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", - "timeFieldName": "@timestamp", - "title": "logstash*" - }, - "type": "index-pattern" - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization-PieChart", - "index": ".kibana", - "source": { - "type": "visualization", - "visualization": { - "description": "PieChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" - }, - "title": "Visualization PieChart", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"pie\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"isDonut\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"memory\",\"interval\":40000,\"extended_bounds\":{}}}],\"listeners\":{}}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization漢字-LineChart", - "index": ".kibana", - "source": { - "type": "visualization", - "visualization": { - "description": "LineChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" - }, - "title": "Visualization漢字 LineChart", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"line\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"showCircles\":true,\"smoothLines\":false,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"extension.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"row\":false}}],\"listeners\":{}}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization-MetricChart", - "index": ".kibana", - "source": { - "type": "visualization", - "visualization": { - "description": "MetricChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" - }, - "title": "Visualization MetricChart", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"metric\",\"params\":{\"handleNoResults\":true,\"fontSize\":60},\"aggs\":[{\"id\":\"1\",\"type\":\"percentile_ranks\",\"schema\":\"metric\",\"params\":{\"field\":\"memory\",\"values\":[99]}}],\"listeners\":{}}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:Visualization漢字-AreaChart", - "index": ".kibana", - "source": { - "type": "visualization", - "visualization": { - "description": "AreaChart", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" - }, - "title": "Visualization漢字 AreaChart", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "dashboard:24f3f950-69d9-11ea-a14d-e341629a29e6", - "index": ".kibana", - "source": { - "dashboard": { - "description": "", - "hits": 0, - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", - "panelsJSON": "[{\"version\":\"7.7.0\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"e637d5f0-a7e6-4635-81ed-39f2b1aac6f4\"},\"panelIndex\":\"e637d5f0-a7e6-4635-81ed-39f2b1aac6f4\",\"embeddableConfig\":{\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"ffd3e4dc-cb1a-419f-afeb-03e8c7742bbf\",\"triggers\":[\"VALUE_CLICK_TRIGGER\",\"SELECT_RANGE_TRIGGER\"],\"action\":{\"name\":\"Go to pie chart dashboard\",\"config\":{\"dashboardId\":\"41e77910-69d9-11ea-a14d-e341629a29e6\",\"useCurrentDateRange\":true,\"useCurrentFilters\":true},\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\"}}]}}},\"panelRefName\":\"panel_0\"}]", - "refreshInterval": { "pause": true, "value": 0 }, - "timeFrom": "2015-09-19T17:34:10.297Z", - "timeRestore": true, - "timeTo": "2015-09-23T00:09:17.180Z", - "title": "Dashboard With Area Chart", - "version": 1 - }, - "references": [ - { - "id": "Visualization漢字-AreaChart", - "name": "panel_0", - "type": "visualization" - } - ], - "type": "dashboard", - "updated_at": "2020-03-19T11:59:53.701Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "dashboard:41e77910-69d9-11ea-a14d-e341629a29e6", - "index": ".kibana", - "source": { - "dashboard": { - "description": "", - "hits": 0, - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" - }, - "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", - "panelsJSON": "[{\"version\":\"7.7.0\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\"},\"panelIndex\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"}]", - "refreshInterval": { "pause": true, "value": 0 }, - "timeFrom": "2015-09-19T17:34:10.297Z", - "timeRestore": true, - "timeTo": "2015-09-23T00:09:17.180Z", - "title": "Dashboard with Pie Chart", - "version": 1 - }, - "references": [ - { - "id": "Visualization-PieChart", - "name": "panel_0", - "type": "visualization" - } - ], - "type": "dashboard", - "updated_at": "2020-03-19T11:59:53.701Z" - } - } -} - - diff --git a/x-pack/test/functional/es_archives/dashboard/drilldowns/mappings.json b/x-pack/test/functional/es_archives/dashboard/drilldowns/mappings.json deleted file mode 100644 index 8382a490ac230..0000000000000 --- a/x-pack/test/functional/es_archives/dashboard/drilldowns/mappings.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - ".kibana": {} - }, - "index": ".kibana_1", - "mappings": { - "properties": { - "config": { - "dynamic": "true", - "properties": { - "buildNum": { - "type": "keyword" - } - } - }, - "dashboard": { - "dynamic": "strict", - "properties": { - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "optionsJSON": { - "type": "text" - }, - "panelsJSON": { - "type": "text" - }, - "refreshInterval": { - "properties": { - "display": { - "type": "keyword" - }, - "pause": { - "type": "boolean" - }, - "section": { - "type": "integer" - }, - "value": { - "type": "integer" - } - } - }, - "timeFrom": { - "type": "keyword" - }, - "timeRestore": { - "type": "boolean" - }, - "timeTo": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "index-pattern": { - "dynamic": "strict", - "properties": { - "fieldFormatMap": { - "type": "text" - }, - "fields": { - "type": "text" - }, - "intervalName": { - "type": "keyword" - }, - "notExpandable": { - "type": "boolean" - }, - "sourceFilters": { - "type": "text" - }, - "timeFieldName": { - "type": "keyword" - }, - "title": { - "type": "text" - } - } - }, - "search": { - "dynamic": "strict", - "properties": { - "columns": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "sort": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "server": { - "dynamic": "strict", - "properties": { - "uuid": { - "type": "keyword" - } - } - }, - "type": { - "type": "keyword" - }, - "url": { - "dynamic": "strict", - "properties": { - "accessCount": { - "type": "long" - }, - "accessDate": { - "type": "date" - }, - "createDate": { - "type": "date" - }, - "url": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "visualization": { - "dynamic": "strict", - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "savedSearchId": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - }, - "visState": { - "type": "text" - } - } - } - } - }, - "settings": { - "index": { - "number_of_replicas": "1", - "number_of_shards": "1" - } - } - } -} diff --git a/x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns.json b/x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns.json new file mode 100644 index 0000000000000..03dfed507d469 --- /dev/null +++ b/x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns.json @@ -0,0 +1,297 @@ +{ + "attributes": { + "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", + "timeFieldName": "@timestamp", + "title": "logstash-*" + }, + "coreMigrationVersion": "8.4.0", + "id": "logstash-*", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "version": "WzE2LDJd" +} + +{ + "attributes": { + "description": "AreaChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "Visualization漢字 AreaChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{},\"legendSize\":\"auto\"},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" + }, + "coreMigrationVersion": "8.4.0", + "id": "Visualization漢字-AreaChart", + "migrationVersion": { + "visualization": "8.3.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "version": "WzIxLDJd" +} + +{ + "attributes": { + "description": "PieChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "Visualization PieChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"pie\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"isDonut\":false,\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"distinctColors\":true,\"legendDisplay\":\"show\",\"legendSize\":\"auto\"},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"memory\",\"interval\":40000,\"extended_bounds\":{}}}],\"listeners\":{}}" + }, + "coreMigrationVersion": "8.4.0", + "id": "Visualization-PieChart", + "migrationVersion": { + "visualization": "8.3.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "version": "WzE4LDJd" +} + +{ + "attributes": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"7.7.0\",\"type\":\"visualization\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\"},\"panelIndex\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\",\"embeddableConfig\":{\"enhancements\":{}},\"panelRefName\":\"panel_8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\"}]", + "refreshInterval": { + "pause": true, + "value": 0 + }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title": "Dashboard with Pie Chart", + "version": 1 + }, + "coreMigrationVersion": "8.4.0", + "id": "41e77910-69d9-11ea-a14d-e341629a29e6", + "migrationVersion": { + "dashboard": "8.3.0" + }, + "references": [ + { + "id": "Visualization-PieChart", + "name": "8c5df6b2-0cc9-4887-a2d9-6a9a192f3407:panel_8c5df6b2-0cc9-4887-a2d9-6a9a192f3407", + "type": "visualization" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z", + "version": "WzIzLDJd" +} + +{ + "attributes": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"7.7.0\",\"type\":\"visualization\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"e637d5f0-a7e6-4635-81ed-39f2b1aac6f4\"},\"panelIndex\":\"e637d5f0-a7e6-4635-81ed-39f2b1aac6f4\",\"embeddableConfig\":{\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"ffd3e4dc-cb1a-419f-afeb-03e8c7742bbf\",\"triggers\":[\"VALUE_CLICK_TRIGGER\",\"SELECT_RANGE_TRIGGER\"],\"action\":{\"name\":\"Go to pie chart dashboard\",\"config\":{\"useCurrentDateRange\":true,\"useCurrentFilters\":true},\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\"}}]}}},\"panelRefName\":\"panel_e637d5f0-a7e6-4635-81ed-39f2b1aac6f4\"}]", + "refreshInterval": { + "pause": true, + "value": 0 + }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title": "Dashboard With Area Chart", + "version": 1 + }, + "coreMigrationVersion": "8.4.0", + "id": "24f3f950-69d9-11ea-a14d-e341629a29e6", + "migrationVersion": { + "dashboard": "8.3.0" + }, + "references": [ + { + "id": "Visualization漢字-AreaChart", + "name": "e637d5f0-a7e6-4635-81ed-39f2b1aac6f4:panel_e637d5f0-a7e6-4635-81ed-39f2b1aac6f4", + "type": "visualization" + }, + { + "id": "41e77910-69d9-11ea-a14d-e341629a29e6", + "name": "e637d5f0-a7e6-4635-81ed-39f2b1aac6f4:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:ffd3e4dc-cb1a-419f-afeb-03e8c7742bbf:dashboardId", + "type": "dashboard" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z", + "version": "WzIyLDJd" +} + +{ + "attributes": { + "description": "MetricChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "Visualization MetricChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"metric\",\"params\":{\"handleNoResults\":true,\"fontSize\":60},\"aggs\":[{\"id\":\"1\",\"type\":\"percentile_ranks\",\"schema\":\"metric\",\"params\":{\"field\":\"memory\",\"values\":[99]}}],\"listeners\":{}}" + }, + "coreMigrationVersion": "8.4.0", + "id": "Visualization-MetricChart", + "migrationVersion": { + "visualization": "8.3.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "version": "WzIwLDJd" +} + +{ + "attributes": { + "description": "TileMap", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "Visualization TileMap", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"tile_map\",\"params\":{\"mapType\":\"Scaled Circle Markers\",\"isDesaturated\":true,\"addTooltip\":true,\"heatMaxZoom\":16,\"heatMinOpacity\":0.1,\"heatRadius\":25,\"heatBlur\":15,\"heatNormalizeData\":true,\"wms\":{\"enabled\":false,\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\",\"options\":{\"version\":\"1.3.0\",\"layers\":\"0\",\"format\":\"image/png\",\"transparent\":true,\"attribution\":\"Maps provided by USGS\",\"styles\":\"\"}}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"geohash_grid\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.coordinates\",\"autoPrecision\":true,\"precision\":2}}],\"listeners\":{}}" + }, + "coreMigrationVersion": "8.4.0", + "id": "Visualization-TileMap", + "migrationVersion": { + "visualization": "8.3.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "version": "WzE1LDJd" +} + +{ + "attributes": { + "description": "VerticalBarChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "Visualization☺ VerticalBarChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{},\"legendSize\":\"auto\"},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" + }, + "coreMigrationVersion": "8.4.0", + "id": "Visualization☺-VerticalBarChart", + "migrationVersion": { + "visualization": "8.3.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "version": "WzE0LDJd" +} + +{ + "attributes": { + "description": "DataTable", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "Visualization☺漢字 DataTable", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false,\"showToolbar\":true},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"histogram\",\"schema\":\"bucket\",\"params\":{\"field\":\"bytes\",\"interval\":2000,\"extended_bounds\":{}}}],\"listeners\":{}}" + }, + "coreMigrationVersion": "8.4.0", + "id": "Visualization☺漢字-DataTable", + "migrationVersion": { + "visualization": "8.3.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "version": "WzEzLDJd" +} + +{ + "attributes": { + "description": "LineChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "Visualization漢字 LineChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"line\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"showCircles\":true,\"smoothLines\":false,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{},\"row\":false,\"legendSize\":\"auto\"},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"extension.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}" + }, + "coreMigrationVersion": "8.4.0", + "id": "Visualization漢字-LineChart", + "migrationVersion": { + "visualization": "8.3.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "version": "WzE5LDJd" +} + +{ + "attributes": { + "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", + "timeFieldName": "@timestamp", + "title": "logstash*" + }, + "coreMigrationVersion": "8.4.0", + "id": "logstash*", + "migrationVersion": { + "index-pattern": "8.0.0" + }, + "references": [], + "type": "index-pattern", + "version": "WzE3LDJd" +} \ No newline at end of file diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index d1125fbb08175..b76cb96e19baa 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -111,22 +111,19 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param opts.field - the desired field for the dimension * @param layerIndex - the index of the layer */ - async configureDimension( - opts: { - dimension: string; - operation: string; - field?: string; - isPreviousIncompatible?: boolean; - keepOpen?: boolean; - palette?: string; - formula?: string; - disableEmptyRows?: boolean; - }, - layerIndex = 0 - ) { + async configureDimension(opts: { + dimension: string; + operation: string; + field?: string; + isPreviousIncompatible?: boolean; + keepOpen?: boolean; + palette?: string; + formula?: string; + disableEmptyRows?: boolean; + }) { await retry.try(async () => { if (!(await testSubjects.exists('lns-indexPattern-dimensionContainerClose'))) { - await testSubjects.click(`lns-layerPanel-${layerIndex} > ${opts.dimension}`); + await testSubjects.click(opts.dimension); } await testSubjects.existOrFail('lns-indexPattern-dimensionContainerClose'); }); @@ -450,8 +447,9 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont * @param from - the selector of the dimension being moved * @param to - the selector of the dimension being dropped to * */ - async dragDimensionToDimension(from: string, to: string) { + async dragDimensionToDimension({ from, to }: { from: string; to: string }) { await find.existsByCssSelector(from); + await find.existsByCssSelector(to); await browser.html5DragAndDrop( testSubjects.getCssSelector(from), testSubjects.getCssSelector(to) @@ -891,7 +889,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont return dimensionTexts[index]; }, /** - * Gets label of all dimension triggers in dimension group + * Gets label of all dimension triggers in an element * * @param dimension - the selector of the dimension */ diff --git a/x-pack/test/functional/services/dashboard/drilldowns_manage.ts b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts index 10634ab371345..440c29bf2276e 100644 --- a/x-pack/test/functional/services/dashboard/drilldowns_manage.ts +++ b/x-pack/test/functional/services/dashboard/drilldowns_manage.ts @@ -18,21 +18,24 @@ export function DashboardDrilldownsManageProvider({ getService }: FtrProviderCon const testSubjects = getService('testSubjects'); const flyout = getService('flyout'); const comboBox = getService('comboBox'); - const esArchiver = getService('esArchiver'); const find = getService('find'); const browser = getService('browser'); + const kibanaServer = getService('kibanaServer'); return new (class DashboardDrilldownsManage { readonly DASHBOARD_WITH_PIE_CHART_NAME = 'Dashboard with Pie Chart'; readonly DASHBOARD_WITH_AREA_CHART_NAME = 'Dashboard With Area Chart'; async loadData() { log.debug('loadData'); - await esArchiver.load('x-pack/test/functional/es_archives/dashboard/drilldowns'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns' + ); } async unloadData() { log.debug('unloadData'); - await esArchiver.unload('x-pack/test/functional/es_archives/dashboard/drilldowns'); + await kibanaServer.savedObjects.cleanStandardList(); } async expectsCreateDrilldownFlyoutOpen() { diff --git a/yarn.lock b/yarn.lock index 5f2e28835e141..5233110b1f99f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1476,13 +1476,13 @@ dependencies: "@elastic/ecs-helpers" "^1.1.0" -"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@8.2.0-canary.2": - version "8.2.0-canary.2" - resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-8.2.0-canary.2.tgz#2513926cdbfe7c070e1fa6926f7829171b27cdba" - integrity sha512-Ki2lQ3/UlOnBaf5EjNw0WmCdXiW+J020aYtdVnIuCNhPSLoNPKoM7P+MlggdfeRnENvINlStrMy4bkYF/h6Vbw== +"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@8.3.0-canary.1": + version "8.3.0-canary.1" + resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-8.3.0-canary.1.tgz#31dc18f724433c4135ed85fde5fd018393134552" + integrity sha512-CSNP4vTL/90VRD3MbvfBggy4VBxEgNmlHQf7mlWiPRTxo24t68PqNS+TnsfzO7fbY/nOALoX9hE8VlxRcMo0iA== dependencies: - "@elastic/transport" "^8.0.2" - tslib "^2.3.0" + "@elastic/transport" "^8.2.0" + tslib "^2.4.0" "@elastic/ems-client@8.3.3": version "8.3.3" @@ -1661,17 +1661,17 @@ ts-node "^10.5.0" typescript "^4.5.5" -"@elastic/transport@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@elastic/transport/-/transport-8.0.2.tgz#715f06c7739516867508108df30c33973ca8e81c" - integrity sha512-OlDz3WO3pKE9vSxW4wV/mn7rYCtBmSsDwxr64h/S1Uc/zrIBXb0iUsRMSkiybXugXhjwyjqG2n1Wc7jjFxrskQ== +"@elastic/transport@^8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@elastic/transport/-/transport-8.2.0.tgz#f292cb79c918a36268dd853431e41f13544814ad" + integrity sha512-H/HmefMNQfLiBSVTmNExu2lYs5EzwipUnQB53WLr17RCTDaQX0oOLHcWpDsbKQSRhDAMPPzp5YZsZMJxuxPh7A== dependencies: - debug "^4.3.2" - hpagent "^0.1.2" + debug "^4.3.4" + hpagent "^1.0.0" ms "^2.1.3" secure-json-parse "^2.4.0" - tslib "^2.3.0" - undici "^4.14.1" + tslib "^2.4.0" + undici "^5.1.1" "@emotion/babel-plugin-jsx-pragmatic@^0.1.5": version "0.1.5" @@ -2991,6 +2991,10 @@ version "0.0.0" uid "" +"@kbn/ci-stats-performance-metrics@link:bazel-bin/packages/kbn-ci-stats-performance-metrics": + version "0.0.0" + uid "" + "@kbn/ci-stats-reporter@link:bazel-bin/packages/kbn-ci-stats-reporter": version "0.0.0" uid "" @@ -3027,6 +3031,18 @@ version "0.0.0" uid "" +"@kbn/core-analytics-server-internal@link:bazel-bin/packages/core/analytics/core-analytics-server-internal": + version "0.0.0" + uid "" + +"@kbn/core-analytics-server-mocks@link:bazel-bin/packages/core/analytics/core-analytics-server-mocks": + version "0.0.0" + uid "" + +"@kbn/core-analytics-server@link:bazel-bin/packages/core/analytics/core-analytics-server": + version "0.0.0" + uid "" + "@kbn/core-base-browser-internal@link:bazel-bin/packages/core/base/core-base-browser-internal": version "0.0.0" uid "" @@ -3051,6 +3067,14 @@ version "0.0.0" uid "" +"@kbn/core-config-server-internal@link:bazel-bin/packages/core/config/core-config-server-internal": + version "0.0.0" + uid "" + +"@kbn/core-config-server-mocks@link:bazel-bin/packages/core/config/core-config-server-mocks": + version "0.0.0" + uid "" + "@kbn/core-doc-links-browser-internal@link:bazel-bin/packages/core/doc-links/core-doc-links-browser-internal": version "0.0.0" uid "" @@ -3075,6 +3099,18 @@ version "0.0.0" uid "" +"@kbn/core-i18n-browser-internal@link:bazel-bin/packages/core/i18n/core-i18n-browser-internal": + version "0.0.0" + uid "" + +"@kbn/core-i18n-browser-mocks@link:bazel-bin/packages/core/i18n/core-i18n-browser-mocks": + version "0.0.0" + uid "" + +"@kbn/core-i18n-browser@link:bazel-bin/packages/core/i18n/core-i18n-browser": + version "0.0.0" + uid "" + "@kbn/core-injected-metadata-browser-internal@link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser-internal": version "0.0.0" uid "" @@ -3219,6 +3255,10 @@ version "0.0.0" uid "" +"@kbn/kbn-ci-stats-performance-metrics@link:bazel-bin/packages/kbn-kbn-ci-stats-performance-metrics": + version "0.0.0" + uid "" + "@kbn/kibana-json-schema@link:bazel-bin/packages/kbn-kibana-json-schema": version "0.0.0" uid "" @@ -3235,6 +3275,18 @@ version "0.0.0" uid "" +"@kbn/ml-agg-utils@link:bazel-bin/x-pack/packages/ml/agg_utils": + version "0.0.0" + uid "" + +"@kbn/ml-is-populated-object@link:bazel-bin/x-pack/packages/ml/is_populated_object": + version "0.0.0" + uid "" + +"@kbn/ml-string-hash@link:bazel-bin/x-pack/packages/ml/string_hash": + version "0.0.0" + uid "" + "@kbn/monaco@link:bazel-bin/packages/kbn-monaco": version "0.0.0" uid "" @@ -3351,6 +3403,10 @@ version "0.0.0" uid "" +"@kbn/shared-ux-button-toolbar@link:bazel-bin/packages/shared-ux/button_toolbar": + version "0.0.0" + uid "" + "@kbn/shared-ux-card-no-data@link:bazel-bin/packages/shared-ux/card/no_data": version "0.0.0" uid "" @@ -3379,10 +3435,6 @@ version "0.0.0" uid "" -"@kbn/shared-ux-button-toolbar@link:bazel-bin/packages/shared-ux/button_toolbar": - version "0.0.0" - uid "" - "@kbn/shared-ux-storybook@link:bazel-bin/packages/kbn-shared-ux-storybook": version "0.0.0" uid "" @@ -6370,6 +6422,10 @@ version "0.0.0" uid "" +"@types/kbn__ci-stats-performance-metrics@link:bazel-bin/packages/kbn-ci-stats-performance-metrics/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__ci-stats-reporter@link:bazel-bin/packages/kbn-ci-stats-reporter/npm_module_types": version "0.0.0" uid "" @@ -6406,6 +6462,18 @@ version "0.0.0" uid "" +"@types/kbn__core-analytics-server-internal@link:bazel-bin/packages/core/analytics/core-analytics-server-internal/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-analytics-server-mocks@link:bazel-bin/packages/core/analytics/core-analytics-server-mocks/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-analytics-server@link:bazel-bin/packages/core/analytics/core-analytics-server/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__core-base-browser-internal@link:bazel-bin/packages/core/base/core-base-browser-internal/npm_module_types": version "0.0.0" uid "" @@ -6442,6 +6510,14 @@ version "0.0.0" uid "" +"@types/kbn__core-config-server-internal@link:bazel-bin/packages/core/config/core-config-server-internal/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-config-server-mocks@link:bazel-bin/packages/core/config/core-config-server-mocks/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__core-doc-links-browser-internal@link:bazel-bin/packages/core/doc-links/core-doc-links-browser-internal/npm_module_types": version "0.0.0" uid "" @@ -6466,6 +6542,18 @@ version "0.0.0" uid "" +"@types/kbn__core-i18n-browser-internal@link:bazel-bin/packages/core/i18n/core-i18n-browser-internal/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-i18n-browser-mocks@link:bazel-bin/packages/core/i18n/core-i18n-browser-mocks/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__core-i18n-browser@link:bazel-bin/packages/core/i18n/core-i18n-browser/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__core-injected-metadata-browser-internal@link:bazel-bin/packages/core/injected-metadata/core-injected-metadata-browser-internal/npm_module_types": version "0.0.0" uid "" @@ -6598,6 +6686,10 @@ version "0.0.0" uid "" +"@types/kbn__kbn-ci-stats-performance-metrics@link:bazel-bin/packages/kbn-kbn-ci-stats-performance-metrics/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__kibana-json-schema@link:bazel-bin/packages/kbn-kibana-json-schema/npm_module_types": version "0.0.0" uid "" @@ -6614,6 +6706,18 @@ version "0.0.0" uid "" +"@types/kbn__ml-agg-utils@link:bazel-bin/x-pack/packages/ml/agg_utils/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__ml-is-populated-object@link:bazel-bin/x-pack/packages/ml/is_populated_object/npm_module_types": + version "0.0.0" + uid "" + +"@types/kbn__ml-string-hash@link:bazel-bin/x-pack/packages/ml/string_hash/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__monaco@link:bazel-bin/packages/kbn-monaco/npm_module_types": version "0.0.0" uid "" @@ -6726,6 +6830,10 @@ version "0.0.0" uid "" +"@types/kbn__shared-ux-button-toolbar@link:bazel-bin/packages/shared-ux/button_toolbar/npm_module_types": + version "0.0.0" + uid "" + "@types/kbn__shared-ux-card-no-data@link:bazel-bin/packages/shared-ux/card/no_data/npm_module_types": version "0.0.0" uid "" @@ -6754,10 +6862,6 @@ version "0.0.0" uid "" -"@types/kbn__shared-ux-button-toolbar@link:bazel-bin/packages/shared-ux/button_toolbar/npm_module_types": - version "0.0.0" - uid "" - "@types/kbn__shared-ux-storybook@link:bazel-bin/packages/kbn-shared-ux-storybook/npm_module_types": version "0.0.0" uid "" @@ -7041,10 +7145,10 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@12.20.24", "@types/node@16.11.7", "@types/node@>= 8", "@types/node@>=8.9.0", "@types/node@^10.1.0", "@types/node@^14.0.10", "@types/node@^14.14.31": - version "16.11.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" - integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw== +"@types/node@*", "@types/node@12.20.24", "@types/node@16.11.41", "@types/node@>= 8", "@types/node@>=8.9.0", "@types/node@^10.1.0", "@types/node@^14.0.10", "@types/node@^14.14.31": + version "16.11.41" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.41.tgz#88eb485b1bfdb4c224d878b7832239536aa2f813" + integrity sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ== "@types/nodemailer@^6.4.0": version "6.4.0" @@ -12538,6 +12642,13 @@ debug@4.3.2: dependencies: ms "2.1.2" +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -16590,10 +16701,10 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -hpagent@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-0.1.2.tgz#cab39c66d4df2d4377dbd212295d878deb9bdaa9" - integrity sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ== +hpagent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-1.0.0.tgz#c68f68b3df845687dbdc4896546713ce09cc6bee" + integrity sha512-SCleE2Uc1bM752ymxg8QXYGW0TWtAV4ZW3TqH1aOnyi6T6YW2xadCcclm5qeVjvMvfQ2RKNtZxO7uVb9CTPt1A== hsl-regex@^1.0.0: version "1.0.0" @@ -23792,6 +23903,13 @@ qs@^6.10.0: dependencies: side-channel "^1.0.4" +qs@^6.10.5: + version "6.10.5" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.5.tgz#974715920a80ff6a262264acd2c7e6c2a53282b4" + integrity sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ== + dependencies: + side-channel "^1.0.4" + qs@^6.7.0: version "6.9.4" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" @@ -28448,7 +28566,7 @@ tsd@^0.20.0: path-exists "^4.0.0" read-pkg-up "^7.0.0" -tslib@2.3.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@~2.3.1: +tslib@2.3.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@~2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -28463,6 +28581,11 @@ tslib@^2.0.0, tslib@^2.0.1, tslib@^2.2.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== +tslib@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" @@ -28727,10 +28850,10 @@ undertaker@^1.2.1: object.reduce "^1.0.0" undertaker-registry "^1.0.0" -undici@^4.14.1: - version "4.14.1" - resolved "https://registry.yarnpkg.com/undici/-/undici-4.14.1.tgz#7633b143a8a10d6d63335e00511d071e8d52a1d9" - integrity sha512-WJ+g+XqiZcATcBaUeluCajqy4pEDcQfK1vy+Fo+bC4/mqXI9IIQD/XWHLS70fkGUT6P52Drm7IFslO651OdLPQ== +undici@^5.1.1: + version "5.5.1" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.5.1.tgz#baaf25844a99eaa0b22e1ef8d205bffe587c8f43" + integrity sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw== unfetch@^4.2.0: version "4.2.0"