From 6e87b01f850d9e4a26bc1d1e93b36438c124d3f0 Mon Sep 17 00:00:00 2001 From: liza-mae Date: Mon, 22 Aug 2022 17:52:13 -0600 Subject: [PATCH 01/41] Fix cloud test failures for 8.4 (#139155) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../apps/dashboard/group1/url_field_formatter.ts | 3 +++ .../apps/dashboard/group6/dashboard_query_bar.ts | 3 +++ .../controls/control_group_chaining.ts | 6 ++++++ .../dashboard_elements/controls/options_list.ts | 3 +++ .../dashboard_elements/controls/replace_controls.ts | 6 ++++++ .../apps/management/_data_view_relationships.ts | 1 + .../reporting_and_security/usage/api_counters.ts | 13 ++++++++----- .../reporting_and_security/validation.ts | 2 +- 8 files changed, 31 insertions(+), 6 deletions(-) diff --git a/test/functional/apps/dashboard/group1/url_field_formatter.ts b/test/functional/apps/dashboard/group1/url_field_formatter.ts index ec6b39d7dc659..9cdebca739635 100644 --- a/test/functional/apps/dashboard/group1/url_field_formatter.ts +++ b/test/functional/apps/dashboard/group1/url_field_formatter.ts @@ -24,6 +24,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const fieldName = 'clientip'; const deployment = getService('deployment'); const retry = getService('retry'); + const security = getService('security'); const clickFieldAndCheckUrl = async (fieldLink: WebElementWrapper) => { const fieldValue = await fieldLink.getVisibleText(); @@ -38,6 +39,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Changing field formatter to Url', () => { before(async function () { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader', 'animals']); await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.importExport.load( 'test/functional/fixtures/kbn_archiver/dashboard/current/kibana' @@ -57,6 +59,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await kibanaServer.savedObjects.cleanStandardList(); + await security.testUser.restoreDefaults(); }); it('applied on dashboard', async () => { diff --git a/test/functional/apps/dashboard/group6/dashboard_query_bar.ts b/test/functional/apps/dashboard/group6/dashboard_query_bar.ts index 6890ba5bed24f..010aec9607816 100644 --- a/test/functional/apps/dashboard/group6/dashboard_query_bar.ts +++ b/test/functional/apps/dashboard/group6/dashboard_query_bar.ts @@ -16,10 +16,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const pieChart = getService('pieChart'); const queryBar = getService('queryBar'); const retry = getService('retry'); + const security = getService('security'); const PageObjects = getPageObjects(['common', 'dashboard', 'discover']); describe('dashboard query bar', () => { before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader', 'animals']); await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.importExport.load( 'test/functional/fixtures/kbn_archiver/dashboard/current/kibana' @@ -34,6 +36,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { after(async () => { await kibanaServer.savedObjects.cleanStandardList(); + await security.testUser.restoreDefaults(); }); it('causes panels to reload when refresh is clicked', async () => { diff --git a/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts b/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts index ba25fcfce98e2..a27a1a4814cfb 100644 --- a/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts +++ b/test/functional/apps/dashboard_elements/controls/control_group_chaining.ts @@ -13,6 +13,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); + const security = getService('security'); const { dashboardControls, common, dashboard, timePicker } = getPageObjects([ 'dashboardControls', 'timePicker', @@ -32,6 +33,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }; before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader', 'animals']); await common.navigateToApp('dashboard'); await dashboard.gotoDashboardLandingPage(); await dashboard.clickNewDashboard(); @@ -62,6 +64,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { controlIds = await dashboardControls.getAllControlIds(); }); + after(async () => { + await security.testUser.restoreDefaults(); + }); + it('Shows all available options in first Options List control', async () => { await dashboardControls.optionsListOpenPopover(controlIds[0]); await retry.try(async () => { diff --git a/test/functional/apps/dashboard_elements/controls/options_list.ts b/test/functional/apps/dashboard_elements/controls/options_list.ts index c6847d2ab618c..d6f49b9b435e8 100644 --- a/test/functional/apps/dashboard_elements/controls/options_list.ts +++ b/test/functional/apps/dashboard_elements/controls/options_list.ts @@ -15,6 +15,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const queryBar = getService('queryBar'); const pieChart = getService('pieChart'); + const security = getService('security'); const elasticChart = getService('elasticChart'); const filterBar = getService('filterBar'); const testSubjects = getService('testSubjects'); @@ -32,6 +33,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Dashboard options list integration', () => { before(async () => { + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader', 'animals']); await common.navigateToApp('dashboard'); await dashboard.gotoDashboardLandingPage(); await dashboard.clickNewDashboard(); @@ -422,6 +424,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await filterBar.removeAllFilters(); await queryBar.clickQuerySubmitButton(); await dashboardControls.clearAllControls(); + await security.testUser.restoreDefaults(); }); }); }); diff --git a/test/functional/apps/dashboard_elements/controls/replace_controls.ts b/test/functional/apps/dashboard_elements/controls/replace_controls.ts index e81788a1946a9..2d1f4509f04ce 100644 --- a/test/functional/apps/dashboard_elements/controls/replace_controls.ts +++ b/test/functional/apps/dashboard_elements/controls/replace_controls.ts @@ -17,6 +17,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const retry = getService('retry'); + const security = getService('security'); const { dashboardControls, timePicker, common, dashboard } = getPageObjects([ 'dashboardControls', @@ -59,12 +60,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { before(async () => { await common.navigateToApp('dashboard'); + await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader', 'animals']); await dashboard.gotoDashboardLandingPage(); await dashboard.clickNewDashboard(); await timePicker.setDefaultDataRange(); await dashboard.saveDashboard(DASHBOARD_NAME, { exitFromEditMode: false }); }); + after(async () => { + await security.testUser.restoreDefaults(); + }); + describe('Replace options list', async () => { beforeEach(async () => { await dashboardControls.clearAllControls(); diff --git a/test/functional/apps/management/_data_view_relationships.ts b/test/functional/apps/management/_data_view_relationships.ts index c8e78eab4ce64..680500f58a60c 100644 --- a/test/functional/apps/management/_data_view_relationships.ts +++ b/test/functional/apps/management/_data_view_relationships.ts @@ -29,6 +29,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.settings.clickKibanaIndexPatterns(); await PageObjects.settings.clickIndexPatternLogstash(); await PageObjects.settings.clickRelationshipsTab(); + await PageObjects.header.waitUntilLoadingHasFinished(); expect(parseInt(await PageObjects.settings.getRelationshipsTabCount(), 10)).to.be(1); }); }); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/usage/api_counters.ts b/x-pack/test/reporting_api_integration/reporting_and_security/usage/api_counters.ts index b3b90fcd9c5a3..eeeba2130629f 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/usage/api_counters.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/usage/api_counters.ts @@ -29,11 +29,14 @@ export default function ({ getService }: FtrProviderContext) { await reportingAPI.teardownEcommerce(); }); - it('configuration settings of the tests_server', async () => { - const usage = await usageAPI.getUsageStats(); - expect(usage.kibana_config_usage.xpack_reporting_capture_max_attempts).to.be(1); - expect(usage.kibana_config_usage.xpack_reporting_csv_max_size_bytes).to.be(6000); - expect(usage.kibana_config_usage.xpack_reporting_roles_enabled).to.be(false); + describe('server', function () { + this.tags('skipCloud'); + it('configuration settings of the tests_server', async () => { + const usage = await usageAPI.getUsageStats(); + expect(usage.kibana_config_usage.xpack_reporting_capture_max_attempts).to.be(1); + expect(usage.kibana_config_usage.xpack_reporting_csv_max_size_bytes).to.be(6000); + expect(usage.kibana_config_usage.xpack_reporting_roles_enabled).to.be(false); + }); }); describe('API counters: management', () => { diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts b/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts index 803e03993b3c5..dfd75d2e65248 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/validation.ts @@ -43,7 +43,7 @@ export default function ({ getService }: FtrProviderContext) { { jobParams: createPdfV2Params(1541.5999755859375) } ); - await retry.tryForTime(48000, async () => { + await retry.tryForTime(60000, async () => { const response: supertest.Response = await supertestSvc .get(downloadReportPath) .responseType('blob') From 2dcc65d803907bfe235aeab716d0f9b8b61f07d7 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 22 Aug 2022 17:29:40 -0700 Subject: [PATCH 02/41] remove reference to removed plugin in dev-docs --- dev_docs/contributing/best_practices.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev_docs/contributing/best_practices.mdx b/dev_docs/contributing/best_practices.mdx index 16c66417b89c1..7ec289561c816 100644 --- a/dev_docs/contributing/best_practices.mdx +++ b/dev_docs/contributing/best_practices.mdx @@ -70,7 +70,7 @@ const dataView = savedObjectsClient.get(dataViewId) as DataView; ## Resusable react components -Use [EUI](https://elastic.github.io/eui) for all your basic UI components to create a consistent UI experience. We also have generic UI components offered from the plugin and the plugin. +Use [EUI](https://elastic.github.io/eui) for all your basic UI components to create a consistent UI experience. We also have generic UI components offered from the plugin. ## Don't export code that doesn't need to be public From ec342cac59a8ede4f850cfe52145374c684e7048 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 23 Aug 2022 02:07:01 +0100 Subject: [PATCH 03/41] remove custom styling (#137848) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../synthetics/public/apps/synthetics/routes.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/routes.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/routes.tsx index 9356b55ce5eb2..8112e9f19d982 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/routes.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/routes.tsx @@ -7,7 +7,6 @@ import { EuiThemeComputed } from '@elastic/eui/src/services/theme/types'; import React, { FC, useEffect } from 'react'; -import { tint } from 'polished'; import { EuiPageTemplateProps, EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; import { Route, Switch, useHistory } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -158,17 +157,7 @@ const getRoutes = ( ), dataTestSubj: 'syntheticsMonitorManagementPage', - paddingSize: 'none', - pageBodyProps: { - style: { backgroundColor: tint(0.5, euiTheme.colors.body) }, - }, - pageContentProps: { - paddingSize: 'l', - style: { backgroundColor: euiTheme.colors.ghost }, - }, pageHeader: { - paddingSize: 'l', - style: { margin: 0 }, pageTitle: , tabs: [ { From eec3e68d7530574ea6fd9b23ed51e9518aeae9d2 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 23 Aug 2022 00:41:44 -0400 Subject: [PATCH 04/41] [api-docs] Daily api_docs build (#139261) --- api_docs/actions.mdx | 2 +- api_docs/advanced_settings.mdx | 2 +- api_docs/aiops.mdx | 2 +- api_docs/alerting.mdx | 2 +- api_docs/apm.mdx | 2 +- api_docs/banners.mdx | 2 +- api_docs/bfetch.mdx | 2 +- api_docs/canvas.mdx | 2 +- api_docs/cases.mdx | 2 +- api_docs/charts.mdx | 2 +- api_docs/cloud.mdx | 2 +- api_docs/cloud_security_posture.mdx | 2 +- api_docs/console.mdx | 2 +- api_docs/controls.devdocs.json | 175 +- api_docs/controls.mdx | 4 +- api_docs/core.devdocs.json | 1463 +++++++++++++ api_docs/core.mdx | 4 +- api_docs/core_application.mdx | 4 +- api_docs/core_chrome.mdx | 4 +- api_docs/core_saved_objects.devdocs.json | 1468 +------------ api_docs/core_saved_objects.mdx | 7 +- api_docs/custom_integrations.mdx | 2 +- api_docs/dashboard.mdx | 2 +- api_docs/dashboard_enhanced.mdx | 2 +- api_docs/data.devdocs.json | 36 + api_docs/data.mdx | 4 +- api_docs/data_query.mdx | 4 +- api_docs/data_search.devdocs.json | 2 +- api_docs/data_search.mdx | 4 +- api_docs/data_view_editor.mdx | 2 +- api_docs/data_view_field_editor.mdx | 2 +- api_docs/data_view_management.mdx | 2 +- api_docs/data_views.mdx | 2 +- api_docs/data_visualizer.mdx | 2 +- api_docs/deprecations_by_api.mdx | 2 +- api_docs/deprecations_by_plugin.mdx | 2 +- api_docs/deprecations_by_team.mdx | 2 +- api_docs/dev_tools.mdx | 2 +- api_docs/discover.mdx | 2 +- api_docs/discover_enhanced.mdx | 2 +- api_docs/embeddable.mdx | 2 +- api_docs/embeddable_enhanced.mdx | 2 +- api_docs/encrypted_saved_objects.mdx | 2 +- api_docs/enterprise_search.mdx | 2 +- api_docs/es_ui_shared.mdx | 2 +- api_docs/event_annotation.mdx | 2 +- api_docs/event_log.mdx | 2 +- api_docs/expression_error.mdx | 2 +- api_docs/expression_gauge.mdx | 2 +- api_docs/expression_heatmap.mdx | 2 +- api_docs/expression_image.mdx | 2 +- api_docs/expression_legacy_metric_vis.mdx | 2 +- api_docs/expression_metric.mdx | 2 +- api_docs/expression_metric_vis.mdx | 2 +- api_docs/expression_partition_vis.mdx | 2 +- api_docs/expression_repeat_image.mdx | 2 +- api_docs/expression_reveal_image.mdx | 2 +- api_docs/expression_shape.mdx | 2 +- api_docs/expression_tagcloud.mdx | 2 +- api_docs/expression_x_y.mdx | 2 +- api_docs/expressions.mdx | 2 +- api_docs/features.mdx | 2 +- api_docs/field_formats.mdx | 2 +- api_docs/file_upload.mdx | 2 +- api_docs/files.mdx | 2 +- api_docs/fleet.mdx | 2 +- api_docs/global_search.mdx | 2 +- api_docs/home.mdx | 2 +- api_docs/index_lifecycle_management.mdx | 2 +- api_docs/index_management.mdx | 2 +- api_docs/infra.mdx | 2 +- api_docs/inspector.mdx | 2 +- api_docs/interactive_setup.mdx | 2 +- api_docs/kbn_ace.mdx | 2 +- api_docs/kbn_aiops_components.mdx | 2 +- api_docs/kbn_aiops_utils.mdx | 2 +- api_docs/kbn_alerts.mdx | 2 +- api_docs/kbn_analytics.mdx | 2 +- api_docs/kbn_analytics_client.mdx | 2 +- ..._analytics_shippers_elastic_v3_browser.mdx | 2 +- ...n_analytics_shippers_elastic_v3_common.mdx | 2 +- ...n_analytics_shippers_elastic_v3_server.mdx | 2 +- api_docs/kbn_analytics_shippers_fullstory.mdx | 2 +- api_docs/kbn_apm_config_loader.mdx | 2 +- api_docs/kbn_apm_synthtrace.mdx | 2 +- api_docs/kbn_apm_utils.mdx | 2 +- api_docs/kbn_axe_config.mdx | 2 +- api_docs/kbn_bazel_packages.mdx | 2 +- api_docs/kbn_chart_icons.mdx | 2 +- api_docs/kbn_ci_stats_core.mdx | 2 +- api_docs/kbn_ci_stats_performance_metrics.mdx | 2 +- api_docs/kbn_ci_stats_reporter.mdx | 2 +- api_docs/kbn_cli_dev_mode.mdx | 2 +- api_docs/kbn_coloring.mdx | 2 +- api_docs/kbn_config.mdx | 2 +- api_docs/kbn_config_mocks.mdx | 2 +- api_docs/kbn_config_schema.mdx | 2 +- api_docs/kbn_core_analytics_browser.mdx | 2 +- .../kbn_core_analytics_browser_internal.mdx | 2 +- api_docs/kbn_core_analytics_browser_mocks.mdx | 2 +- api_docs/kbn_core_analytics_server.mdx | 2 +- .../kbn_core_analytics_server_internal.mdx | 2 +- api_docs/kbn_core_analytics_server_mocks.mdx | 2 +- api_docs/kbn_core_base_browser_mocks.mdx | 2 +- api_docs/kbn_core_base_common.mdx | 2 +- api_docs/kbn_core_base_server_internal.mdx | 2 +- api_docs/kbn_core_base_server_mocks.mdx | 2 +- api_docs/kbn_core_capabilities_common.mdx | 2 +- api_docs/kbn_core_capabilities_server.mdx | 2 +- .../kbn_core_capabilities_server_mocks.mdx | 2 +- api_docs/kbn_core_config_server_internal.mdx | 2 +- api_docs/kbn_core_deprecations_browser.mdx | 2 +- ...kbn_core_deprecations_browser_internal.mdx | 2 +- .../kbn_core_deprecations_browser_mocks.mdx | 2 +- api_docs/kbn_core_deprecations_common.mdx | 2 +- api_docs/kbn_core_doc_links_browser.mdx | 2 +- api_docs/kbn_core_doc_links_browser_mocks.mdx | 2 +- api_docs/kbn_core_doc_links_server.mdx | 2 +- api_docs/kbn_core_doc_links_server_mocks.mdx | 2 +- ...e_elasticsearch_client_server_internal.mdx | 2 +- ...core_elasticsearch_client_server_mocks.mdx | 2 +- api_docs/kbn_core_elasticsearch_server.mdx | 2 +- ...kbn_core_elasticsearch_server_internal.mdx | 2 +- .../kbn_core_elasticsearch_server_mocks.mdx | 2 +- .../kbn_core_environment_server_internal.mdx | 2 +- .../kbn_core_environment_server_mocks.mdx | 2 +- .../kbn_core_execution_context_browser.mdx | 2 +- ...ore_execution_context_browser_internal.mdx | 2 +- ...n_core_execution_context_browser_mocks.mdx | 2 +- .../kbn_core_execution_context_common.mdx | 2 +- .../kbn_core_execution_context_server.mdx | 2 +- ...core_execution_context_server_internal.mdx | 2 +- ...bn_core_execution_context_server_mocks.mdx | 2 +- api_docs/kbn_core_fatal_errors_browser.mdx | 2 +- .../kbn_core_fatal_errors_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_browser.mdx | 2 +- api_docs/kbn_core_http_browser_internal.mdx | 2 +- api_docs/kbn_core_http_browser_mocks.mdx | 2 +- api_docs/kbn_core_http_common.mdx | 2 +- .../kbn_core_http_context_server_mocks.mdx | 2 +- .../kbn_core_http_router_server_internal.mdx | 2 +- .../kbn_core_http_router_server_mocks.mdx | 2 +- api_docs/kbn_core_http_server.mdx | 2 +- api_docs/kbn_core_http_server_internal.mdx | 2 +- api_docs/kbn_core_http_server_mocks.mdx | 2 +- api_docs/kbn_core_i18n_browser.mdx | 2 +- api_docs/kbn_core_i18n_browser_mocks.mdx | 2 +- .../kbn_core_injected_metadata_browser.mdx | 2 +- ...n_core_injected_metadata_browser_mocks.mdx | 2 +- ...kbn_core_integrations_browser_internal.mdx | 2 +- .../kbn_core_integrations_browser_mocks.mdx | 2 +- api_docs/kbn_core_logging_server.mdx | 2 +- api_docs/kbn_core_logging_server_internal.mdx | 2 +- api_docs/kbn_core_logging_server_mocks.mdx | 2 +- ...ore_metrics_collectors_server_internal.mdx | 2 +- ...n_core_metrics_collectors_server_mocks.mdx | 2 +- api_docs/kbn_core_metrics_server.mdx | 2 +- api_docs/kbn_core_metrics_server_internal.mdx | 2 +- api_docs/kbn_core_metrics_server_mocks.mdx | 2 +- api_docs/kbn_core_mount_utils_browser.mdx | 2 +- .../kbn_core_mount_utils_browser_internal.mdx | 2 +- api_docs/kbn_core_node_server.mdx | 2 +- api_docs/kbn_core_node_server_internal.mdx | 2 +- api_docs/kbn_core_node_server_mocks.mdx | 2 +- api_docs/kbn_core_notifications_browser.mdx | 2 +- ...bn_core_notifications_browser_internal.mdx | 2 +- .../kbn_core_notifications_browser_mocks.mdx | 2 +- api_docs/kbn_core_overlays_browser.mdx | 2 +- .../kbn_core_overlays_browser_internal.mdx | 2 +- api_docs/kbn_core_overlays_browser_mocks.mdx | 2 +- api_docs/kbn_core_preboot_server.mdx | 2 +- api_docs/kbn_core_preboot_server_mocks.mdx | 2 +- .../kbn_core_saved_objects_api_browser.mdx | 2 +- .../kbn_core_saved_objects_api_server.mdx | 2 +- ..._objects_base_server_internal.devdocs.json | 585 ++++++ ...ore_saved_objects_base_server_internal.mdx | 39 + ...ved_objects_base_server_mocks.devdocs.json | 90 + ...n_core_saved_objects_base_server_mocks.mdx | 30 + api_docs/kbn_core_saved_objects_browser.mdx | 2 +- ...bn_core_saved_objects_browser_internal.mdx | 2 +- .../kbn_core_saved_objects_browser_mocks.mdx | 2 +- api_docs/kbn_core_saved_objects_common.mdx | 2 +- api_docs/kbn_core_saved_objects_server.mdx | 2 +- ...re_saved_objects_utils_server.devdocs.json | 1836 +++++++++++++++++ .../kbn_core_saved_objects_utils_server.mdx | 39 + ...core_test_helpers_deprecations_getters.mdx | 2 +- ...n_core_test_helpers_http_setup_browser.mdx | 2 +- api_docs/kbn_core_theme_browser.mdx | 2 +- api_docs/kbn_core_theme_browser_internal.mdx | 2 +- api_docs/kbn_core_theme_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_browser.mdx | 2 +- .../kbn_core_ui_settings_browser_internal.mdx | 2 +- .../kbn_core_ui_settings_browser_mocks.mdx | 2 +- api_docs/kbn_core_ui_settings_common.mdx | 2 +- api_docs/kbn_crypto.mdx | 2 +- api_docs/kbn_crypto_browser.mdx | 2 +- api_docs/kbn_datemath.mdx | 2 +- api_docs/kbn_dev_cli_errors.mdx | 2 +- api_docs/kbn_dev_cli_runner.mdx | 2 +- api_docs/kbn_dev_proc_runner.mdx | 2 +- api_docs/kbn_dev_utils.mdx | 2 +- api_docs/kbn_doc_links.mdx | 2 +- api_docs/kbn_docs_utils.mdx | 2 +- api_docs/kbn_ebt_tools.mdx | 2 +- api_docs/kbn_es_archiver.mdx | 2 +- api_docs/kbn_es_errors.mdx | 2 +- api_docs/kbn_es_query.mdx | 2 +- api_docs/kbn_eslint_plugin_imports.mdx | 2 +- api_docs/kbn_field_types.mdx | 2 +- api_docs/kbn_find_used_node_modules.mdx | 2 +- api_docs/kbn_generate.mdx | 2 +- api_docs/kbn_get_repo_files.mdx | 2 +- api_docs/kbn_handlebars.mdx | 2 +- api_docs/kbn_hapi_mocks.mdx | 2 +- api_docs/kbn_home_sample_data_card.mdx | 2 +- api_docs/kbn_home_sample_data_tab.mdx | 2 +- api_docs/kbn_i18n.mdx | 2 +- api_docs/kbn_import_resolver.mdx | 2 +- api_docs/kbn_interpreter.mdx | 2 +- api_docs/kbn_io_ts_utils.mdx | 2 +- api_docs/kbn_jest_serializers.mdx | 2 +- api_docs/kbn_kibana_manifest_parser.mdx | 2 +- api_docs/kbn_kibana_manifest_schema.mdx | 2 +- api_docs/kbn_logging.mdx | 2 +- api_docs/kbn_logging_mocks.mdx | 2 +- api_docs/kbn_managed_vscode_config.mdx | 2 +- api_docs/kbn_mapbox_gl.mdx | 2 +- api_docs/kbn_ml_agg_utils.mdx | 2 +- api_docs/kbn_ml_is_populated_object.mdx | 2 +- api_docs/kbn_ml_string_hash.mdx | 2 +- api_docs/kbn_monaco.mdx | 2 +- api_docs/kbn_optimizer.mdx | 2 +- api_docs/kbn_optimizer_webpack_helpers.mdx | 2 +- ..._performance_testing_dataset_extractor.mdx | 2 +- api_docs/kbn_plugin_generator.mdx | 2 +- api_docs/kbn_plugin_helpers.mdx | 2 +- api_docs/kbn_react_field.mdx | 2 +- api_docs/kbn_repo_source_classifier.mdx | 2 +- api_docs/kbn_rule_data_utils.mdx | 2 +- .../kbn_securitysolution_autocomplete.mdx | 2 +- api_docs/kbn_securitysolution_es_utils.mdx | 2 +- api_docs/kbn_securitysolution_hook_utils.mdx | 2 +- ..._securitysolution_io_ts_alerting_types.mdx | 2 +- .../kbn_securitysolution_io_ts_list_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_types.mdx | 2 +- api_docs/kbn_securitysolution_io_ts_utils.mdx | 2 +- api_docs/kbn_securitysolution_list_api.mdx | 2 +- .../kbn_securitysolution_list_constants.mdx | 2 +- api_docs/kbn_securitysolution_list_hooks.mdx | 2 +- api_docs/kbn_securitysolution_list_utils.mdx | 2 +- api_docs/kbn_securitysolution_rules.mdx | 2 +- api_docs/kbn_securitysolution_t_grid.mdx | 2 +- api_docs/kbn_securitysolution_utils.mdx | 2 +- api_docs/kbn_server_http_tools.mdx | 2 +- api_docs/kbn_server_route_repository.mdx | 2 +- api_docs/kbn_shared_svg.mdx | 2 +- ...hared_ux_button_exit_full_screen_mocks.mdx | 2 +- api_docs/kbn_shared_ux_button_toolbar.mdx | 2 +- .../kbn_shared_ux_card_no_data.devdocs.json | 2 +- api_docs/kbn_shared_ux_card_no_data.mdx | 2 +- api_docs/kbn_shared_ux_card_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_link_redirect_app_mocks.mdx | 2 +- .../kbn_shared_ux_page_analytics_no_data.mdx | 2 +- ...shared_ux_page_analytics_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_no_data.mdx | 2 +- ...bn_shared_ux_page_kibana_no_data_mocks.mdx | 2 +- .../kbn_shared_ux_page_kibana_template.mdx | 2 +- ...n_shared_ux_page_kibana_template_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data.mdx | 2 +- .../kbn_shared_ux_page_no_data_config.mdx | 2 +- ...bn_shared_ux_page_no_data_config_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_no_data_mocks.mdx | 2 +- api_docs/kbn_shared_ux_page_solution_nav.mdx | 2 +- .../kbn_shared_ux_prompt_no_data_views.mdx | 2 +- ...n_shared_ux_prompt_no_data_views_mocks.mdx | 2 +- api_docs/kbn_shared_ux_storybook_mock.mdx | 2 +- api_docs/kbn_shared_ux_utility.mdx | 2 +- api_docs/kbn_some_dev_log.mdx | 2 +- api_docs/kbn_sort_package_json.mdx | 2 +- api_docs/kbn_std.mdx | 2 +- api_docs/kbn_stdio_dev_helpers.mdx | 2 +- api_docs/kbn_storybook.mdx | 2 +- api_docs/kbn_telemetry_tools.mdx | 2 +- api_docs/kbn_test.mdx | 2 +- api_docs/kbn_test_jest_helpers.mdx | 2 +- api_docs/kbn_tooling_log.mdx | 2 +- api_docs/kbn_type_summarizer.mdx | 2 +- api_docs/kbn_type_summarizer_core.mdx | 2 +- api_docs/kbn_typed_react_router_config.mdx | 2 +- api_docs/kbn_ui_theme.mdx | 2 +- api_docs/kbn_user_profile_components.mdx | 2 +- api_docs/kbn_utility_types.mdx | 2 +- api_docs/kbn_utility_types_jest.mdx | 2 +- api_docs/kbn_utils.mdx | 2 +- api_docs/kbn_yarn_lock_validator.mdx | 2 +- api_docs/kibana_overview.mdx | 2 +- api_docs/kibana_react.mdx | 2 +- api_docs/kibana_utils.mdx | 2 +- api_docs/kubernetes_security.mdx | 2 +- api_docs/lens.mdx | 2 +- api_docs/license_api_guard.mdx | 2 +- api_docs/license_management.mdx | 2 +- api_docs/licensing.mdx | 2 +- api_docs/lists.mdx | 2 +- api_docs/management.mdx | 2 +- api_docs/maps.mdx | 2 +- api_docs/maps_ems.mdx | 2 +- api_docs/ml.mdx | 2 +- api_docs/monitoring.mdx | 2 +- api_docs/monitoring_collection.mdx | 2 +- api_docs/navigation.mdx | 2 +- api_docs/newsfeed.mdx | 2 +- api_docs/observability.devdocs.json | 4 +- api_docs/observability.mdx | 2 +- api_docs/osquery.mdx | 2 +- api_docs/plugin_directory.mdx | 19 +- api_docs/presentation_util.mdx | 2 +- api_docs/remote_clusters.mdx | 2 +- api_docs/reporting.mdx | 2 +- api_docs/rollup.mdx | 2 +- api_docs/rule_registry.mdx | 2 +- api_docs/runtime_fields.mdx | 2 +- api_docs/saved_objects.mdx | 2 +- .../saved_objects_management.devdocs.json | 2 +- api_docs/saved_objects_management.mdx | 2 +- api_docs/saved_objects_tagging.mdx | 2 +- api_docs/saved_objects_tagging_oss.mdx | 2 +- api_docs/saved_search.mdx | 2 +- api_docs/screenshot_mode.mdx | 2 +- api_docs/screenshotting.mdx | 2 +- api_docs/security.mdx | 2 +- api_docs/security_solution.mdx | 2 +- api_docs/session_view.mdx | 2 +- api_docs/share.mdx | 2 +- api_docs/snapshot_restore.mdx | 2 +- api_docs/spaces.mdx | 2 +- api_docs/stack_alerts.mdx | 2 +- api_docs/task_manager.mdx | 2 +- api_docs/telemetry.mdx | 2 +- api_docs/telemetry_collection_manager.mdx | 2 +- api_docs/telemetry_collection_xpack.mdx | 2 +- api_docs/telemetry_management_section.mdx | 2 +- api_docs/threat_intelligence.devdocs.json | 111 +- api_docs/threat_intelligence.mdx | 4 +- api_docs/timelines.mdx | 2 +- api_docs/transform.mdx | 2 +- api_docs/triggers_actions_ui.mdx | 2 +- api_docs/ui_actions.mdx | 2 +- api_docs/ui_actions_enhanced.mdx | 2 +- api_docs/unified_search.mdx | 2 +- api_docs/unified_search_autocomplete.mdx | 2 +- api_docs/url_forwarding.mdx | 2 +- api_docs/usage_collection.mdx | 2 +- api_docs/ux.mdx | 2 +- api_docs/vis_default_editor.mdx | 2 +- api_docs/vis_type_gauge.mdx | 2 +- api_docs/vis_type_heatmap.mdx | 2 +- api_docs/vis_type_pie.mdx | 2 +- api_docs/vis_type_table.mdx | 2 +- api_docs/vis_type_timelion.mdx | 2 +- api_docs/vis_type_timeseries.mdx | 2 +- api_docs/vis_type_vega.mdx | 2 +- api_docs/vis_type_vislib.mdx | 2 +- api_docs/vis_type_xy.mdx | 2 +- api_docs/visualizations.devdocs.json | 56 +- api_docs/visualizations.mdx | 4 +- 366 files changed, 4689 insertions(+), 1989 deletions(-) create mode 100644 api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json create mode 100644 api_docs/kbn_core_saved_objects_base_server_internal.mdx create mode 100644 api_docs/kbn_core_saved_objects_base_server_mocks.devdocs.json create mode 100644 api_docs/kbn_core_saved_objects_base_server_mocks.mdx create mode 100644 api_docs/kbn_core_saved_objects_utils_server.devdocs.json create mode 100644 api_docs/kbn_core_saved_objects_utils_server.mdx diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index fb370fac704c4..c3ec6ff5cea3e 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index c681b05886b0c..919ab9152d9d1 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index bcec7684a470d..ceff930ca4229 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 815b17bb70560..ca578fd099f4e 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 448a918e81d3c..0c1e93866ca04 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index c35d69909e4fb..f92b26599d72e 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 0e4d1ce76d72b..49bd8b22d15ca 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 936a16e38a6d3..49e969a447fda 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index cf2fb0c0e5c1b..41d48c3884216 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 7f4b3027a61c8..a4cd6c9d09965 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 030f78d1063cb..0248f43cc8e12 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index d833bb0e50cfc..a957d84ea6932 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index ffaacdcb0eb4f..c32c221f4a597 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.devdocs.json b/api_docs/controls.devdocs.json index 6ebca7b46dd34..e7a02b67fc192 100644 --- a/api_docs/controls.devdocs.json +++ b/api_docs/controls.devdocs.json @@ -1906,7 +1906,7 @@ }, ">" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "children": [ { @@ -1919,7 +1919,7 @@ "signature": [ "\"rangeSliderControl\"" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false }, { @@ -1929,7 +1929,7 @@ "tags": [], "label": "deferEmbeddableLoad", "description": [], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false }, { @@ -1942,7 +1942,7 @@ "signature": [ "any" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "children": [ { @@ -1961,7 +1961,7 @@ "text": "ReduxEmbeddablePackage" } ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "isRequired": true }, @@ -1981,7 +1981,7 @@ "text": "RangeSliderEmbeddableInput" } ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "isRequired": true }, @@ -2001,7 +2001,7 @@ "text": "ControlOutput" } ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "isRequired": true }, @@ -2038,7 +2038,7 @@ }, "> | undefined" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "isRequired": false } @@ -2055,7 +2055,7 @@ "signature": [ "() => void" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "children": [], "returnComment": [] @@ -2070,7 +2070,7 @@ "signature": [ "() => void" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "children": [], "returnComment": [] @@ -2085,7 +2085,7 @@ "signature": [ "(node: HTMLElement) => void" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "children": [ { @@ -2098,7 +2098,7 @@ "signature": [ "HTMLElement" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable.tsx", "deprecated": false, "isRequired": true } @@ -2191,7 +2191,7 @@ }, ">" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "children": [ { @@ -2201,9 +2201,54 @@ "tags": [], "label": "type", "description": [], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false }, + { + "parentPluginId": "controls", + "id": "def-public.RangeSliderEmbeddableFactory.getDisplayName", + "type": "Function", + "tags": [], + "label": "getDisplayName", + "description": [], + "signature": [ + "() => string" + ], + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "controls", + "id": "def-public.RangeSliderEmbeddableFactory.getDescription", + "type": "Function", + "tags": [], + "label": "getDescription", + "description": [], + "signature": [ + "() => string" + ], + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "controls", + "id": "def-public.RangeSliderEmbeddableFactory.getIconType", + "type": "Function", + "tags": [], + "label": "getIconType", + "description": [], + "signature": [ + "() => string" + ], + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", + "deprecated": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "controls", "id": "def-public.RangeSliderEmbeddableFactory.canCreateNew", @@ -2214,22 +2259,22 @@ "signature": [ "() => boolean" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "children": [], "returnComment": [] }, { "parentPluginId": "controls", - "id": "def-public.RangeSliderEmbeddableFactory.Unnamed", + "id": "def-public.RangeSliderEmbeddableFactory.isEditable", "type": "Function", "tags": [], - "label": "Constructor", + "label": "isEditable", "description": [], "signature": [ - "any" + "() => Promise" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "children": [], "returnComment": [] @@ -2284,7 +2329,7 @@ }, ">" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "children": [ { @@ -2303,7 +2348,7 @@ "text": "RangeSliderEmbeddableInput" } ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "isRequired": true }, @@ -2340,7 +2385,7 @@ }, "> | undefined" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "isRequired": false } @@ -2397,7 +2442,7 @@ }, ">" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "children": [ { @@ -2418,7 +2463,7 @@ }, ">" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "isRequired": true }, @@ -2455,7 +2500,7 @@ }, "> | undefined" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "isRequired": false } @@ -2474,7 +2519,7 @@ "DataControlField", ") => void" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "children": [ { @@ -2487,73 +2532,13 @@ "signature": [ "DataControlField" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "isRequired": true } ], "returnComment": [] }, - { - "parentPluginId": "controls", - "id": "def-public.RangeSliderEmbeddableFactory.isEditable", - "type": "Function", - "tags": [], - "label": "isEditable", - "description": [], - "signature": [ - "() => Promise" - ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "controls", - "id": "def-public.RangeSliderEmbeddableFactory.getDisplayName", - "type": "Function", - "tags": [], - "label": "getDisplayName", - "description": [], - "signature": [ - "() => string" - ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "controls", - "id": "def-public.RangeSliderEmbeddableFactory.getIconType", - "type": "Function", - "tags": [], - "label": "getIconType", - "description": [], - "signature": [ - "() => string" - ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "controls", - "id": "def-public.RangeSliderEmbeddableFactory.getDescription", - "type": "Function", - "tags": [], - "label": "getDescription", - "description": [], - "signature": [ - "() => string" - ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", - "deprecated": false, - "children": [], - "returnComment": [] - }, { "parentPluginId": "controls", "id": "def-public.RangeSliderEmbeddableFactory.inject", @@ -2581,7 +2566,7 @@ "text": "EmbeddableStateWithType" } ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "returnComment": [], "children": [ @@ -2642,7 +2627,7 @@ "SavedObjectReference", "[]; }" ], - "path": "src/plugins/controls/public/control_types/range_slider/range_slider_embeddable_factory.tsx", + "path": "src/plugins/controls/public/range_slider/embeddable/range_slider_embeddable_factory.tsx", "deprecated": false, "returnComment": [], "children": [ @@ -3281,7 +3266,7 @@ " extends ", "DataControlInput" ], - "path": "src/plugins/controls/common/control_types/range_slider/types.ts", + "path": "src/plugins/controls/common/range_slider/types.ts", "deprecated": false, "children": [ { @@ -3294,7 +3279,7 @@ "signature": [ "[string, string]" ], - "path": "src/plugins/controls/common/control_types/range_slider/types.ts", + "path": "src/plugins/controls/common/range_slider/types.ts", "deprecated": false } ], @@ -3529,7 +3514,7 @@ "signature": [ "\"rangeSliderControl\"" ], - "path": "src/plugins/controls/common/control_types/range_slider/types.ts", + "path": "src/plugins/controls/common/range_slider/types.ts", "deprecated": false, "initialIsOpen": false }, @@ -4263,7 +4248,7 @@ " extends ", "DataControlInput" ], - "path": "src/plugins/controls/common/control_types/range_slider/types.ts", + "path": "src/plugins/controls/common/range_slider/types.ts", "deprecated": false, "children": [ { @@ -4276,7 +4261,7 @@ "signature": [ "[string, string]" ], - "path": "src/plugins/controls/common/control_types/range_slider/types.ts", + "path": "src/plugins/controls/common/range_slider/types.ts", "deprecated": false } ], @@ -4395,7 +4380,7 @@ "signature": [ "\"rangeSliderControl\"" ], - "path": "src/plugins/controls/common/control_types/range_slider/types.ts", + "path": "src/plugins/controls/common/range_slider/types.ts", "deprecated": false, "initialIsOpen": false }, diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index e9526ae69f446..4f564cb0f1bc1 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-prese | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 207 | 0 | 199 | 7 | +| 206 | 0 | 198 | 7 | ## Client diff --git a/api_docs/core.devdocs.json b/api_docs/core.devdocs.json index a4b351471464c..416752a227c67 100644 --- a/api_docs/core.devdocs.json +++ b/api_docs/core.devdocs.json @@ -10498,9 +10498,1472 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers", + "type": "Class", + "tags": [], + "label": "SavedObjectsErrorHelpers", + "description": [], + "signature": [ + "SavedObjectsErrorHelpers" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isSavedObjectsClientError", + "type": "Function", + "tags": [], + "label": "isSavedObjectsClientError", + "description": [], + "signature": [ + "(error: any) => error is ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isSavedObjectsClientError.$1", + "type": "Any", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "any" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError", + "type": "Function", + "tags": [], + "label": "decorateBadRequestError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createBadRequestError", + "type": "Function", + "tags": [], + "label": "createBadRequestError", + "description": [], + "signature": [ + "(reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createBadRequestError.$1", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createUnsupportedTypeError", + "type": "Function", + "tags": [], + "label": "createUnsupportedTypeError", + "description": [], + "signature": [ + "(type: string) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createUnsupportedTypeError.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isBadRequestError", + "type": "Function", + "tags": [], + "label": "isBadRequestError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isBadRequestError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createInvalidVersionError", + "type": "Function", + "tags": [], + "label": "createInvalidVersionError", + "description": [], + "signature": [ + "(versionInput?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createInvalidVersionError.$1", + "type": "string", + "tags": [], + "label": "versionInput", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isInvalidVersionError", + "type": "Function", + "tags": [], + "label": "isInvalidVersionError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isInvalidVersionError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError", + "type": "Function", + "tags": [], + "label": "decorateNotAuthorizedError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isNotAuthorizedError", + "type": "Function", + "tags": [], + "label": "isNotAuthorizedError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isNotAuthorizedError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError", + "type": "Function", + "tags": [], + "label": "decorateForbiddenError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isForbiddenError", + "type": "Function", + "tags": [], + "label": "isForbiddenError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isForbiddenError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError", + "type": "Function", + "tags": [], + "label": "decorateRequestEntityTooLargeError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isRequestEntityTooLargeError", + "type": "Function", + "tags": [], + "label": "isRequestEntityTooLargeError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isRequestEntityTooLargeError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError", + "type": "Function", + "tags": [], + "label": "createGenericNotFoundError", + "description": [], + "signature": [ + "(type?: string | null | undefined, id?: string | null | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError.$1", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | null | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError.$2", + "type": "CompoundType", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | null | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createIndexAliasNotFoundError", + "type": "Function", + "tags": [], + "label": "createIndexAliasNotFoundError", + "description": [], + "signature": [ + "(alias: string) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createIndexAliasNotFoundError.$1", + "type": "string", + "tags": [], + "label": "alias", + "description": [], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError", + "type": "Function", + "tags": [], + "label": "decorateIndexAliasNotFoundError", + "description": [], + "signature": [ + "(error: Error, alias: string) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError.$2", + "type": "string", + "tags": [], + "label": "alias", + "description": [], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isNotFoundError", + "type": "Function", + "tags": [], + "label": "isNotFoundError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isNotFoundError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError", + "type": "Function", + "tags": [], + "label": "decorateConflictError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError", + "type": "Function", + "tags": [], + "label": "createConflictError", + "description": [], + "signature": [ + "(type: string, id: string, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$2", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$3", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isConflictError", + "type": "Function", + "tags": [], + "label": "isConflictError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isConflictError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError", + "type": "Function", + "tags": [], + "label": "decorateTooManyRequestsError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError", + "type": "Function", + "tags": [], + "label": "createTooManyRequestsError", + "description": [], + "signature": [ + "(type: string, id: string) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError.$2", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isTooManyRequestsError", + "type": "Function", + "tags": [], + "label": "isTooManyRequestsError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isTooManyRequestsError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError", + "type": "Function", + "tags": [], + "label": "decorateEsCannotExecuteScriptError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isEsCannotExecuteScriptError", + "type": "Function", + "tags": [], + "label": "isEsCannotExecuteScriptError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isEsCannotExecuteScriptError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError", + "type": "Function", + "tags": [], + "label": "decorateEsUnavailableError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isEsUnavailableError", + "type": "Function", + "tags": [], + "label": "isEsUnavailableError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isEsUnavailableError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError", + "type": "Function", + "tags": [], + "label": "decorateGeneralError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isGeneralError", + "type": "Function", + "tags": [], + "label": "isGeneralError", + "description": [], + "signature": [ + "(error: Error | ", + "DecoratedError", + ") => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.isGeneralError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError", + "type": "Function", + "tags": [], + "label": "createGenericNotFoundEsUnavailableError", + "description": [], + "signature": [ + "(type?: string | null | undefined, id?: string | null | undefined) => ", + "DecoratedError" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError.$1", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | null | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError.$2", + "type": "CompoundType", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | null | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils", + "type": "Class", + "tags": [], + "label": "SavedObjectsUtils", + "description": [], + "signature": [ + "SavedObjectsUtils" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.namespaceIdToString", + "type": "Function", + "tags": [], + "label": "namespaceIdToString", + "description": [ + "\nConverts a given saved object namespace ID to its string representation. All namespace IDs have an identical string representation, with\nthe exception of the `undefined` namespace ID (which has a namespace string of `'default'`).\n" + ], + "signature": [ + "(namespace?: string | undefined) => string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.namespaceIdToString.$1", + "type": "string", + "tags": [], + "label": "namespace", + "description": [ + "The namespace ID, which must be either a non-empty string or `undefined`." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.namespaceStringToId", + "type": "Function", + "tags": [], + "label": "namespaceStringToId", + "description": [ + "\nConverts a given saved object namespace string to its ID representation. All namespace strings have an identical ID representation, with\nthe exception of the `'default'` namespace string (which has a namespace ID of `undefined`).\n" + ], + "signature": [ + "(namespace: string) => string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.namespaceStringToId.$1", + "type": "string", + "tags": [], + "label": "namespace", + "description": [ + "The namespace string, which must be non-empty." + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.createEmptyFindResponse", + "type": "Function", + "tags": [], + "label": "createEmptyFindResponse", + "description": [ + "\nCreates an empty response for a find operation. This is only intended to be used by saved objects client wrappers." + ], + "signature": [ + "({ page, perPage, }: ", + "SavedObjectsFindOptions", + ") => ", + "SavedObjectsFindResponse", + "" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.createEmptyFindResponse.$1", + "type": "Object", + "tags": [], + "label": "__0", + "description": [], + "signature": [ + "SavedObjectsFindOptions" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false + } + ] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.generateId", + "type": "Function", + "tags": [], + "label": "generateId", + "description": [ + "\nGenerates a random ID for a saved objects." + ], + "signature": [ + "() => string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.isRandomId", + "type": "Function", + "tags": [ + "todo" + ], + "label": "isRandomId", + "description": [ + "\nValidates that a saved object ID has been randomly generated.\n" + ], + "signature": [ + "(id: string | undefined) => boolean" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.isRandomId.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "The ID of a saved object." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId", + "type": "Function", + "tags": [], + "label": "getConvertedObjectId", + "description": [ + "\nUses a single-namespace object's \"legacy ID\" to determine what its new ID will be after it is converted to a multi-namespace type.\n" + ], + "signature": [ + "(namespace: string | undefined, type: string, id: string) => string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$1", + "type": "string", + "tags": [], + "label": "namespace", + "description": [ + "The namespace of the saved object before it is converted." + ], + "signature": [ + "string | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": false + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$2", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "The type of the saved object before it is converted." + ], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$3", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "The ID of the saved object before it is converted." + ], + "signature": [ + "string" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [ + "The ID of the saved object after it is converted." + ] + } + ], + "initialIsOpen": false } ], "functions": [ + { + "parentPluginId": "core", + "id": "def-server.mergeSavedObjectMigrationMaps", + "type": "Function", + "tags": [], + "label": "mergeSavedObjectMigrationMaps", + "description": [ + "\nMerges two saved object migration maps.\n\nIf there is a migration for a given version on only one of the maps,\nthat migration function will be used:\n\nmergeSavedObjectMigrationMaps({ '1.2.3': f }, { '4.5.6': g }) -> { '1.2.3': f, '4.5.6': g }\n\nIf there is a migration for a given version on both maps, the migrations will be composed:\n\nmergeSavedObjectMigrationMaps({ '1.2.3': f }, { '1.2.3': g }) -> { '1.2.3': (doc, context) => f(g(doc, context), context) }\n" + ], + "signature": [ + "(map1: ", + "SavedObjectMigrationMap", + ", map2: ", + "SavedObjectMigrationMap", + ") => ", + "SavedObjectMigrationMap" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "core", + "id": "def-server.mergeSavedObjectMigrationMaps.$1", + "type": "Object", + "tags": [], + "label": "map1", + "description": [], + "signature": [ + "SavedObjectMigrationMap" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false + }, + { + "parentPluginId": "core", + "id": "def-server.mergeSavedObjectMigrationMaps.$2", + "type": "Object", + "tags": [], + "label": "map2", + "description": [], + "signature": [ + "SavedObjectMigrationMap" + ], + "path": "node_modules/@types/kbn__core-saved-objects-utils-server/index.d.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "core", "id": "def-server.pollEsNodesVersion", diff --git a/api_docs/core.mdx b/api_docs/core.mdx index c263ced17e2e2..33d87f244a33d 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github description: API docs for the core plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] --- import coreObj from './core.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2524 | 2 | 296 | 6 | +| 2524 | 1 | 216 | 5 | ## Client diff --git a/api_docs/core_application.mdx b/api_docs/core_application.mdx index 0f737a23baba3..cb769db54eaed 100644 --- a/api_docs/core_application.mdx +++ b/api_docs/core_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-application title: "core.application" image: https://source.unsplash.com/400x175/?github description: API docs for the core.application plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.application'] --- import coreApplicationObj from './core_application.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2524 | 2 | 296 | 6 | +| 2524 | 1 | 216 | 5 | ## Client diff --git a/api_docs/core_chrome.mdx b/api_docs/core_chrome.mdx index 3b4972563bed1..bb6b32b4c04ea 100644 --- a/api_docs/core_chrome.mdx +++ b/api_docs/core_chrome.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-chrome title: "core.chrome" image: https://source.unsplash.com/400x175/?github description: API docs for the core.chrome plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.chrome'] --- import coreChromeObj from './core_chrome.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2524 | 2 | 296 | 6 | +| 2524 | 1 | 216 | 5 | ## Client diff --git a/api_docs/core_saved_objects.devdocs.json b/api_docs/core_saved_objects.devdocs.json index 7c494cf0fad8e..86cf67bdb6a5c 100644 --- a/api_docs/core_saved_objects.devdocs.json +++ b/api_docs/core_saved_objects.devdocs.json @@ -10,1181 +10,6 @@ }, "server": { "classes": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers", - "type": "Class", - "tags": [], - "label": "SavedObjectsErrorHelpers", - "description": [], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isSavedObjectsClientError", - "type": "Function", - "tags": [], - "label": "isSavedObjectsClientError", - "description": [], - "signature": [ - "(error: any) => error is ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isSavedObjectsClientError.$1", - "type": "Any", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "any" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError", - "type": "Function", - "tags": [], - "label": "decorateBadRequestError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createBadRequestError", - "type": "Function", - "tags": [], - "label": "createBadRequestError", - "description": [], - "signature": [ - "(reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createBadRequestError.$1", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createUnsupportedTypeError", - "type": "Function", - "tags": [], - "label": "createUnsupportedTypeError", - "description": [], - "signature": [ - "(type: string) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createUnsupportedTypeError.$1", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isBadRequestError", - "type": "Function", - "tags": [], - "label": "isBadRequestError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isBadRequestError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createInvalidVersionError", - "type": "Function", - "tags": [], - "label": "createInvalidVersionError", - "description": [], - "signature": [ - "(versionInput?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createInvalidVersionError.$1", - "type": "string", - "tags": [], - "label": "versionInput", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isInvalidVersionError", - "type": "Function", - "tags": [], - "label": "isInvalidVersionError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isInvalidVersionError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError", - "type": "Function", - "tags": [], - "label": "decorateNotAuthorizedError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isNotAuthorizedError", - "type": "Function", - "tags": [], - "label": "isNotAuthorizedError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isNotAuthorizedError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError", - "type": "Function", - "tags": [], - "label": "decorateForbiddenError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isForbiddenError", - "type": "Function", - "tags": [], - "label": "isForbiddenError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isForbiddenError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError", - "type": "Function", - "tags": [], - "label": "decorateRequestEntityTooLargeError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isRequestEntityTooLargeError", - "type": "Function", - "tags": [], - "label": "isRequestEntityTooLargeError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isRequestEntityTooLargeError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError", - "type": "Function", - "tags": [], - "label": "createGenericNotFoundError", - "description": [], - "signature": [ - "(type?: string | null, id?: string | null) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError.$1", - "type": "CompoundType", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string | null" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError.$2", - "type": "CompoundType", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string | null" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createIndexAliasNotFoundError", - "type": "Function", - "tags": [], - "label": "createIndexAliasNotFoundError", - "description": [], - "signature": [ - "(alias: string) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createIndexAliasNotFoundError.$1", - "type": "string", - "tags": [], - "label": "alias", - "description": [], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError", - "type": "Function", - "tags": [], - "label": "decorateIndexAliasNotFoundError", - "description": [], - "signature": [ - "(error: Error, alias: string) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError.$2", - "type": "string", - "tags": [], - "label": "alias", - "description": [], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isNotFoundError", - "type": "Function", - "tags": [], - "label": "isNotFoundError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isNotFoundError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError", - "type": "Function", - "tags": [], - "label": "decorateConflictError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createConflictError", - "type": "Function", - "tags": [], - "label": "createConflictError", - "description": [], - "signature": [ - "(type: string, id: string, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$1", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$2", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$3", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isConflictError", - "type": "Function", - "tags": [], - "label": "isConflictError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isConflictError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError", - "type": "Function", - "tags": [], - "label": "decorateTooManyRequestsError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError", - "type": "Function", - "tags": [], - "label": "createTooManyRequestsError", - "description": [], - "signature": [ - "(type: string, id: string) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError.$1", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError.$2", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isTooManyRequestsError", - "type": "Function", - "tags": [], - "label": "isTooManyRequestsError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isTooManyRequestsError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError", - "type": "Function", - "tags": [], - "label": "decorateEsCannotExecuteScriptError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isEsCannotExecuteScriptError", - "type": "Function", - "tags": [], - "label": "isEsCannotExecuteScriptError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isEsCannotExecuteScriptError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError", - "type": "Function", - "tags": [], - "label": "decorateEsUnavailableError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isEsUnavailableError", - "type": "Function", - "tags": [], - "label": "isEsUnavailableError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isEsUnavailableError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError", - "type": "Function", - "tags": [], - "label": "decorateGeneralError", - "description": [], - "signature": [ - "(error: Error, reason?: string | undefined) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError.$1", - "type": "Object", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError.$2", - "type": "string", - "tags": [], - "label": "reason", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isGeneralError", - "type": "Function", - "tags": [], - "label": "isGeneralError", - "description": [], - "signature": [ - "(error: Error | ", - "DecoratedError", - ") => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.isGeneralError.$1", - "type": "CompoundType", - "tags": [], - "label": "error", - "description": [], - "signature": [ - "Error | ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError", - "type": "Function", - "tags": [], - "label": "createGenericNotFoundEsUnavailableError", - "description": [], - "signature": [ - "(type?: string | null, id?: string | null) => ", - "DecoratedError" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError.$1", - "type": "CompoundType", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string | null" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError.$2", - "type": "CompoundType", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string | null" - ], - "path": "src/core/server/saved_objects/service/lib/errors.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "core", "id": "def-server.SavedObjectsExportError", @@ -2791,300 +1616,9 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils", - "type": "Class", - "tags": [], - "label": "SavedObjectsUtils", - "description": [], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.namespaceIdToString", - "type": "Function", - "tags": [], - "label": "namespaceIdToString", - "description": [ - "\nConverts a given saved object namespace ID to its string representation. All namespace IDs have an identical string representation, with\nthe exception of the `undefined` namespace ID (which has a namespace string of `'default'`).\n" - ], - "signature": [ - "(namespace?: string | undefined) => string" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.namespaceIdToString.$1", - "type": "string", - "tags": [], - "label": "namespace", - "description": [ - "The namespace ID, which must be either a non-empty string or `undefined`." - ], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.namespaceStringToId", - "type": "Function", - "tags": [], - "label": "namespaceStringToId", - "description": [ - "\nConverts a given saved object namespace string to its ID representation. All namespace strings have an identical ID representation, with\nthe exception of the `'default'` namespace string (which has a namespace ID of `undefined`).\n" - ], - "signature": [ - "(namespace: string) => string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.namespaceStringToId.$1", - "type": "string", - "tags": [], - "label": "namespace", - "description": [ - "The namespace string, which must be non-empty." - ], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.createEmptyFindResponse", - "type": "Function", - "tags": [], - "label": "createEmptyFindResponse", - "description": [ - "\nCreates an empty response for a find operation. This is only intended to be used by saved objects client wrappers." - ], - "signature": [ - "({ page, perPage, }: ", - "SavedObjectsFindOptions", - ") => ", - "SavedObjectsFindResponse", - "" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.createEmptyFindResponse.$1", - "type": "Object", - "tags": [], - "label": "{\n page = FIND_DEFAULT_PAGE,\n perPage = FIND_DEFAULT_PER_PAGE,\n }", - "description": [], - "signature": [ - "SavedObjectsFindOptions" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.generateId", - "type": "Function", - "tags": [], - "label": "generateId", - "description": [ - "\nGenerates a random ID for a saved objects." - ], - "signature": [ - "() => string" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.isRandomId", - "type": "Function", - "tags": [ - "todo" - ], - "label": "isRandomId", - "description": [ - "\nValidates that a saved object ID has been randomly generated.\n" - ], - "signature": [ - "(id: string | undefined) => boolean" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.isRandomId.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [ - "The ID of a saved object." - ], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "isRequired": false - } - ], - "returnComment": [] - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.getConvertedObjectId", - "type": "Function", - "tags": [], - "label": "getConvertedObjectId", - "description": [ - "\nUses a single-namespace object's \"legacy ID\" to determine what its new ID will be after it is converted to a multi-namespace type.\n" - ], - "signature": [ - "(namespace: string | undefined, type: string, id: string) => string" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$1", - "type": "string", - "tags": [], - "label": "namespace", - "description": [ - "The namespace of the saved object before it is converted." - ], - "signature": [ - "string | undefined" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "isRequired": false - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$2", - "type": "string", - "tags": [], - "label": "type", - "description": [ - "The type of the saved object before it is converted." - ], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$3", - "type": "string", - "tags": [], - "label": "id", - "description": [ - "The ID of the saved object before it is converted." - ], - "signature": [ - "string" - ], - "path": "src/core/server/saved_objects/service/lib/utils.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [ - "The ID of the saved object after it is converted." - ] - } - ], - "initialIsOpen": false - } - ], - "functions": [ - { - "parentPluginId": "core", - "id": "def-server.mergeSavedObjectMigrationMaps", - "type": "Function", - "tags": [], - "label": "mergeSavedObjectMigrationMaps", - "description": [ - "\nMerges two saved object migration maps.\n\nIf there is a migration for a given version on only one of the maps,\nthat migration function will be used:\n\nmergeSavedObjectMigrationMaps({ '1.2.3': f }, { '4.5.6': g }) -> { '1.2.3': f, '4.5.6': g }\n\nIf there is a migration for a given version on both maps, the migrations will be composed:\n\nmergeSavedObjectMigrationMaps({ '1.2.3': f }, { '1.2.3': g }) -> { '1.2.3': (doc, context) => f(g(doc, context), context) }\n" - ], - "signature": [ - "(map1: ", - "SavedObjectMigrationMap", - ", map2: ", - "SavedObjectMigrationMap", - ") => ", - "SavedObjectMigrationMap" - ], - "path": "src/core/server/saved_objects/migrations/utils.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.mergeSavedObjectMigrationMaps.$1", - "type": "Object", - "tags": [], - "label": "map1", - "description": [], - "signature": [ - "SavedObjectMigrationMap" - ], - "path": "src/core/server/saved_objects/migrations/utils.ts", - "deprecated": false, - "isRequired": true - }, - { - "parentPluginId": "core", - "id": "def-server.mergeSavedObjectMigrationMaps.$2", - "type": "Object", - "tags": [], - "label": "map2", - "description": [], - "signature": [ - "SavedObjectMigrationMap" - ], - "path": "src/core/server/saved_objects/migrations/utils.ts", - "deprecated": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false } ], + "functions": [], "interfaces": [], "enums": [], "misc": [], diff --git a/api_docs/core_saved_objects.mdx b/api_docs/core_saved_objects.mdx index 9a8e01136ac2b..684e4f0036a6f 100644 --- a/api_docs/core_saved_objects.mdx +++ b/api_docs/core_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core-savedObjects title: "core.savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the core.savedObjects plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core.savedObjects'] --- import coreSavedObjectsObj from './core_saved_objects.devdocs.json'; @@ -21,13 +21,10 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2524 | 2 | 296 | 6 | +| 2524 | 1 | 216 | 5 | ## Server -### Functions - - ### Classes diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 133041b0baec6..321197a449a9d 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index 3796d5be1fdd8..682aad767ec99 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index e3603336d6f06..b6181b13a58e6 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 78c8f4c0dec76..92bb53862bd10 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -10634,6 +10634,42 @@ ], "path": "src/plugins/data/public/index.ts", "deprecated": false + }, + { + "parentPluginId": "data", + "id": "def-public.search.aggs.calcAutoIntervalLessThan", + "type": "Function", + "tags": [], + "label": "calcAutoIntervalLessThan", + "description": [], + "signature": [ + "(maxBucketCount: number, duration: number) => moment.Duration" + ], + "path": "src/plugins/data/public/index.ts", + "deprecated": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-public.search.aggs.calcAutoIntervalLessThan.$1", + "type": "number", + "tags": [], + "label": "maxBucketCount", + "description": [], + "path": "src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts", + "deprecated": false + }, + { + "parentPluginId": "data", + "id": "def-public.search.aggs.calcAutoIntervalLessThan.$2", + "type": "number", + "tags": [], + "label": "duration", + "description": [], + "path": "src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts", + "deprecated": false + } + ] } ] }, diff --git a/api_docs/data.mdx b/api_docs/data.mdx index b432b21937d84..a4dfc956ab86a 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3114 | 34 | 2428 | 22 | +| 3117 | 34 | 2431 | 22 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index d452015312014..bff320e0afb5b 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3114 | 34 | 2428 | 22 | +| 3117 | 34 | 2431 | 22 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index 73d0c6793eac8..6d60b92265a0f 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -20481,7 +20481,7 @@ "label": "aggregate", "description": [], "signature": [ - "\"min\" | \"max\" | \"concat\" | \"sum\" | \"average\"" + "\"min\" | \"max\" | \"sum\" | \"average\" | \"concat\"" ], "path": "src/plugins/data/common/search/aggs/metrics/top_hit.ts", "deprecated": false diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index a38b65ac8f2b6..4f867c11de78b 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3114 | 34 | 2428 | 22 | +| 3117 | 34 | 2431 | 22 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 246f0f1d56fa4..072af10cfd44f 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 3b80d5cd6d62c..da4c7c83a4f49 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index a4c22013a7391..0058eed3fbd91 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 7245a253b5a4b..ddd52b1c6887d 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index c9ce1886651f6..c013d84288b44 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index af93c369b8bbe..289fec2eb63cf 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 35c5b9e35340d..cc570a401d482 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 212481753680f..7857bea1ccfba 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index d35c58ba11425..47e2425b3b89d 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 341a8d0e8ff75..e9516c80dd08e 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 79bba874c8503..89e46db501521 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 32d11e69592e9..c1573e9c557fe 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 490ab4a490165..5d55592350d12 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 3e280a9a3af49..bca90471f04d4 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 107f4985c9a1a..e15f217b3caf0 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 8756693deb3d4..76043ca99d8af 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 8bb87d9675760..32551880db4f7 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index accbeb8dd3cd1..f98a5c6b57bdc 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 27120b4b39baf..86c6a90aad327 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 99f0e8a96126b..770f43f403edf 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index e89310339a2ff..1495b6a3b7b17 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index b069a55c33ff3..c86d8e4cd39e0 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index c43c215cd56e3..434a95d560c9b 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index 5cc3c2e272204..def0586f94784 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index a32beeda69a71..d735e0eac87ee 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 58381a2c030d9..e6661944b12d3 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index 84d5978ec0717..c4d497fb88fb6 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index bb42d0c3c0ef8..98afa2b7e6eef 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index aff78c3a8b5ce..ebaab4968e7d9 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index 0d7c788777029..2bf997203e91b 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 72629a6cee2f0..620dfb19c8824 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 95486711230d5..18f6377fbf287 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 8801ae66f5f3f..45d9c4d70c28d 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index 73e36008e12c9..9a6de84523cdc 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 27a24293f037e..79e16545d5f05 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 4fa0f071191b4..ccf5fc8ac5560 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 0f0f20355f8c9..3119de26cc49e 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index e1d92210fda2f..f30a92d9dc6c8 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 2516ace023b1d..b5e237a77869c 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 265130a5a3e40..3079b15c14c35 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 50791c3d1b735..2887cdcbf2bca 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 4bfe04ae84795..5c31619bbe540 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index fee794d32b8c7..62ae1f5710475 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 5c92316cd80c2..88049ba3d455f 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index bca38d0a78201..54f8426838e8f 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index a7bb99de9d298..8bdbc985b6bc5 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index fd47ee26950e4..d220922d8e8e1 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index 4d736109e9f6a..3b006d777b2f5 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 27f3a4bc41abd..07a2b081aa682 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index a8ba75f884b89..10cba6c9c818a 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 11cd1fdc20f02..dd212d82d5456 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,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 description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 7e0becc951edf..caa5e741760be 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,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 description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index 24c9fc0fddc8c..e9c60a3a541bd 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,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 description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 9bc9fe8fb51ff..44d9002a74c02 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 398fa3a6741ce..3c912520647ec 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 48c281f3209f0..7f3da3e562afc 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index a14331bc7ab0d..fb47443b3f652 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index fcf90f98d9f78..06c3b25d6e655 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bazel_packages.mdx b/api_docs/kbn_bazel_packages.mdx index 30f02e6901cc4..12d7d9c3cf81b 100644 --- a/api_docs/kbn_bazel_packages.mdx +++ b/api_docs/kbn_bazel_packages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bazel-packages title: "@kbn/bazel-packages" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bazel-packages plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bazel-packages'] --- import kbnBazelPackagesObj from './kbn_bazel_packages.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index e15c84c31c26d..a96c307eaa5ef 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 254809a6d1f7d..8cc7a94eb87f9 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index cfac6e2bbac2a..9dfac087b5691 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 3eac48be7b0df..ffb861a5ed784 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index 4e660d395d984..d6e2e8be716b3 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index c552d7cdb70ee..a173a60760e16 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 2923881891db8..3bfaefa7da26e 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index d5e4ce5113fbc..9940d262ed90b 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index a5967a1b0201c..673b933cd455c 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 99a3e55b8e2e9..0adf25037c19c 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 7a8c720617f59..5cb22be772a3e 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 745799822d5fa..4512695964200 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index f36509f058ed9..c844026ed5d9d 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 7df3a89fc7b8b..900c76a8b5082 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 664a3112a93aa..9b5006e1f40c2 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 0403ecfd608b0..3041bc1651ab4 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index a834fb3bbdecd..1b7b3fcf69dd7 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 460b2eb0e2ad6..b2add4d4a1978 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index 62b7be0845220..70ede2118a655 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 88ec128e46195..b49e0e3c64fe6 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index 74a48d0ebd92a..4d752a0370c6c 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 3d3754ac5e20d..95c7bb7c2a941 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 5a951169615a3..66a5642f9fa36 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 5fd78381685ec..34185f64d10ff 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index a723eb168b4c0..2b75a68053f77 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index fefd13b56b777..6a3748703e4f3 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index dabd876b8a02c..88024b0421ddd 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index fd587ebcf9743..c48481e85fab4 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index fc126aa7d7dde..433ec8c2418dc 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,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 description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 1f95047b4792b..c76b4b1683ea1 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 18b28851864c1..3a6ffa6671de2 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,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 description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index e81db294cca91..e79bf5cfd43ab 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index a90f68dc84f87..3c90cd43f3277 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 09a5dfa1860ff..974ff5f772047 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 0a45d168e696f..37dbb74ebf9cc 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 86b8bc9c13b41..bd6c5e057ee3b 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index c536f9c5ea0ba..d8cf266601451 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index b94917f722255..654d2649b7feb 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index e1d30875f4d61..6e8fe83b89531 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index df721518ade4e..c92347071b4b0 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 29f6e5f423f89..cfffe837864f0 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index b81f424104cdf..96c76f0663414 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index d566a343d7593..fe641b402acf8 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 18b7e18629e39..29a9eab7a276a 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index d6692a43a46c9..59c6e46e4168b 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index d08d70027d79f..d82654e942eb3 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 9a0599f073e53..075458fbfe269 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index ae80c851095d9..418ae645fa1a3 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index ee67080afb77f..f83ba3ae57980 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 1c5e6894a840f..c11524f8d61fc 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 5f4c6227e0c45..9d68d1b05cd0a 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index 0149e5a1ef736..e71dc5f1dd2ac 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 0c0189dec35c2..5bc43d071fea6 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 13f6a86caed93..74d081091554f 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 0bb31ce2eecea..4f4323720fdb6 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 19418ae307e27..08d45cbc7cd69 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index 0ad1c9167d6d0..14a503b3201b8 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 4f748bb1eb1b4..d0fd9e4b5c667 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 47693b62e96aa..2816d317cf9df 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index 00954b3bb5b9f..1308d664c1da3 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] --- import kbnCoreInjectedMetadataBrowserObj from './kbn_core_injected_metadata_browser.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 7561f8d543fba..a4c9dd46cf83a 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,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 description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 7f578f29af98f..e0bd552efad25 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 6ed8ee5e8fc1b..9a3622e48e5ab 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index d8218355ffb2a..e2f257a283f5e 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 4de18c9ad80bf..7a684b587e50e 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 7888fbe99e446..f4598190bd6b1 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index e02038e325924..32a1e8edb9e49 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 8678aaced144c..bef75fc492a0a 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 9ed3a21ad56a4..bc75927c87c65 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 9cbafa5d52179..983b863b4cffa 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index abe7d0b334d8c..a44699b9829af 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index f1f8727b9eee7..6c4c988800920 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser_internal.mdx b/api_docs/kbn_core_mount_utils_browser_internal.mdx index 9f9061bd2db2f..bbe50b7afe127 100644 --- a/api_docs/kbn_core_mount_utils_browser_internal.mdx +++ b/api_docs/kbn_core_mount_utils_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser-internal title: "@kbn/core-mount-utils-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser-internal'] --- import kbnCoreMountUtilsBrowserInternalObj from './kbn_core_mount_utils_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 249929402bb4c..b4df77f64ea41 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 232d8c9b6ad1b..161f626fb4eb1 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index 1dc7820421fc8..502fd822054a4 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index 8b5697e29e1bc..16e7af167a3a0 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index a670d97534b1a..34918eeecc9cd 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 489c0180a7f74..08d6ab0c9ddf9 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index fc6dbb27609db..6043dc1a389af 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index ff891d2b6cc6b..f4e12809cc9ce 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 229ca743a2ce0..2f2b7d0034526 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 7c406e1fb0af6..b719c8b63a3ed 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 546ae71d30209..b77516104ef8f 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 9a560592e3ea2..831cd004a8b31 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 78c00a6865fe9..40138d2729502 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json b/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json new file mode 100644 index 0000000000000..b30cc8fc4006f --- /dev/null +++ b/api_docs/kbn_core_saved_objects_base_server_internal.devdocs.json @@ -0,0 +1,585 @@ +{ + "id": "@kbn/core-saved-objects-base-server-internal", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectConfig", + "type": "Class", + "tags": [], + "label": "SavedObjectConfig", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectConfig.maxImportPayloadBytes", + "type": "number", + "tags": [], + "label": "maxImportPayloadBytes", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectConfig.maxImportExportSize", + "type": "number", + "tags": [], + "label": "maxImportExportSize", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectConfig.migration", + "type": "Object", + "tags": [], + "label": "migration", + "description": [], + "signature": [ + "{ readonly discardUnknownObjects?: string | undefined; readonly discardCorruptObjects?: string | undefined; readonly pollInterval: number; readonly skip: boolean; readonly batchSize: number; readonly maxBatchSizeBytes: ", + "ByteSizeValue", + "; readonly scrollDuration: string; readonly retryAttempts: number; }" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectConfig.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectConfig.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "rawConfig", + "description": [], + "signature": [ + "Readonly<{} & { maxImportPayloadBytes: ", + "ByteSizeValue", + "; maxImportExportSize: number; }>" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectConfig.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "rawMigrationConfig", + "description": [], + "signature": [ + "Readonly<{ discardUnknownObjects?: string | undefined; discardCorruptObjects?: string | undefined; } & { pollInterval: number; skip: boolean; batchSize: number; maxBatchSizeBytes: ", + "ByteSizeValue", + "; scrollDuration: string; retryAttempts: number; }>" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.decodeRequestVersion", + "type": "Function", + "tags": [], + "label": "decodeRequestVersion", + "description": [ + "\nHelper for decoding version to request params that are driven\nby the version info" + ], + "signature": [ + "(version: string | undefined) => { if_seq_no: number; if_primary_term: number; }" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/decode_request_version.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.decodeRequestVersion.$1", + "type": "string", + "tags": [], + "label": "version", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/decode_request_version.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.decodeVersion", + "type": "Function", + "tags": [], + "label": "decodeVersion", + "description": [ + "\nDecode the \"opaque\" version string to the sequence params we\ncan use to activate optimistic concurrency in Elasticsearch" + ], + "signature": [ + "(version: string | undefined) => { _seq_no: number; _primary_term: number; }" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/decode_version.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.decodeVersion.$1", + "type": "string", + "tags": [], + "label": "version", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/decode_version.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.encodeHitVersion", + "type": "Function", + "tags": [], + "label": "encodeHitVersion", + "description": [ + "\nHelper for encoding a version from a \"hit\" (hits.hits[#] from _search) or\n\"doc\" (body from GET, update, etc) object" + ], + "signature": [ + "(response: { _seq_no?: number | undefined; _primary_term?: number | undefined; }) => string" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/encode_hit_version.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.encodeHitVersion.$1", + "type": "Object", + "tags": [], + "label": "response", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/encode_hit_version.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.encodeHitVersion.$1._seq_no", + "type": "number", + "tags": [], + "label": "_seq_no", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/encode_hit_version.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.encodeHitVersion.$1._primary_term", + "type": "number", + "tags": [], + "label": "_primary_term", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/encode_hit_version.ts", + "deprecated": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.encodeVersion", + "type": "Function", + "tags": [], + "label": "encodeVersion", + "description": [ + "\nEncode the sequence params into an \"opaque\" version string\nthat can be used in the saved object API in place of numeric\nversion numbers" + ], + "signature": [ + "(seqNo: number | undefined, primaryTerm: number | undefined) => string" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/encode_version.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.encodeVersion.$1", + "type": "number", + "tags": [], + "label": "seqNo", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/encode_version.ts", + "deprecated": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.encodeVersion.$2", + "type": "number", + "tags": [], + "label": "primaryTerm", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/version/encode_version.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getProperty", + "type": "Function", + "tags": [], + "label": "getProperty", + "description": [], + "signature": [ + "(mappings: ", + "SavedObjectsFieldMapping", + " | ", + "IndexMapping", + ", path: string | string[]) => ", + "SavedObjectsFieldMapping", + " | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_property.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getProperty.$1", + "type": "CompoundType", + "tags": [], + "label": "mappings", + "description": [], + "signature": [ + "SavedObjectsFieldMapping", + " | ", + "IndexMapping" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_property.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getProperty.$2", + "type": "CompoundType", + "tags": [], + "label": "path", + "description": [], + "signature": [ + "string | string[]" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_property.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getRootProperties", + "type": "Function", + "tags": [], + "label": "getRootProperties", + "description": [ + "\n Get the property mappings for the root type in the EsMappingsDsl\n\n If the mappings don't have a root type, or the root type is not\n an object type (it's a keyword or something) this function will\n throw an error.\n\n EsPropertyMappings objects have the root property names as their\n first level keys which map to the mappings object for each property.\n If the property is of type object it too could have a `properties`\n key whose value follows the same format.\n\n This data can be found at `{indexName}.mappings.{typeName}.properties`\n in the es indices.get() response." + ], + "signature": [ + "(mapping: ", + "IndexMapping", + ") => ", + "SavedObjectsMappingProperties" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_root_properties.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getRootProperties.$1", + "type": "Object", + "tags": [], + "label": "mapping", + "description": [], + "signature": [ + "IndexMapping" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_root_properties.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getRootPropertiesObjects", + "type": "Function", + "tags": [], + "label": "getRootPropertiesObjects", + "description": [], + "signature": [ + "(mappings: ", + "IndexMapping", + ") => ", + "SavedObjectsMappingProperties" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_root_properties_objects.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getRootPropertiesObjects.$1", + "type": "Object", + "tags": [], + "label": "mappings", + "description": [], + "signature": [ + "IndexMapping" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_root_properties_objects.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getTypes", + "type": "Function", + "tags": [], + "label": "getTypes", + "description": [ + "\n Get the names of the types defined in the EsMappingsDsl" + ], + "signature": [ + "(mappings: ", + "IndexMapping", + ") => string[]" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.getTypes.$1", + "type": "Object", + "tags": [], + "label": "mappings", + "description": [], + "signature": [ + "IndexMapping" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/mappings/lib/get_types.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectsConfigType", + "type": "Type", + "tags": [], + "label": "SavedObjectsConfigType", + "description": [], + "signature": [ + "{ readonly maxImportPayloadBytes: ", + "ByteSizeValue", + "; readonly maxImportExportSize: number; }" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.SavedObjectsMigrationConfigType", + "type": "Type", + "tags": [], + "label": "SavedObjectsMigrationConfigType", + "description": [], + "signature": [ + "{ readonly discardUnknownObjects?: string | undefined; readonly discardCorruptObjects?: string | undefined; readonly pollInterval: number; readonly skip: boolean; readonly batchSize: number; readonly maxBatchSizeBytes: ", + "ByteSizeValue", + "; readonly scrollDuration: string; readonly retryAttempts: number; }" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "initialIsOpen": false + } + ], + "objects": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.savedObjectsConfig", + "type": "Object", + "tags": [], + "label": "savedObjectsConfig", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.savedObjectsConfig.path", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.savedObjectsConfig.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [], + "signature": [ + "ObjectType", + "<{ maxImportPayloadBytes: ", + "Type", + "<", + "ByteSizeValue", + ">; maxImportExportSize: ", + "Type", + "; }>" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.savedObjectsMigrationConfig", + "type": "Object", + "tags": [], + "label": "savedObjectsMigrationConfig", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.savedObjectsMigrationConfig.path", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-internal", + "id": "def-server.savedObjectsMigrationConfig.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [], + "signature": [ + "ObjectType", + "<{ batchSize: ", + "Type", + "; maxBatchSizeBytes: ", + "Type", + "<", + "ByteSizeValue", + ">; discardUnknownObjects: ", + "Type", + "; discardCorruptObjects: ", + "Type", + "; scrollDuration: ", + "Type", + "; pollInterval: ", + "Type", + "; skip: ", + "Type", + "; retryAttempts: ", + "Type", + "; }>" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts", + "deprecated": false + } + ], + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx new file mode 100644 index 0000000000000..9db42c2419566 --- /dev/null +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -0,0 +1,39 @@ +--- +#### +#### 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. +#### +id: kibKbnCoreSavedObjectsBaseServerInternalPluginApi +slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal +title: "@kbn/core-saved-objects-base-server-internal" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/core-saved-objects-base-server-internal plugin +date: 2022-08-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] +--- +import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_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 | +|-------------------|-----------|------------------------|-----------------| +| 35 | 0 | 29 | 1 | + +## Server + +### Objects + + +### Functions + + +### Classes + + +### Consts, variables and types + + diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.devdocs.json b/api_docs/kbn_core_saved_objects_base_server_mocks.devdocs.json new file mode 100644 index 0000000000000..cab8d6394bd14 --- /dev/null +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.devdocs.json @@ -0,0 +1,90 @@ +{ + "id": "@kbn/core-saved-objects-base-server-mocks", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-mocks", + "id": "def-server.serializerMock", + "type": "Object", + "tags": [], + "label": "serializerMock", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-mocks/src/serializer.mock.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-mocks", + "id": "def-server.serializerMock.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => jest.Mocked<", + "ISavedObjectsSerializer", + ">" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-mocks/src/serializer.mock.ts", + "deprecated": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-base-server-mocks", + "id": "def-server.typeRegistryMock", + "type": "Object", + "tags": [], + "label": "typeRegistryMock", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-base-server-mocks/src/saved_objects_type_registry.mock.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-base-server-mocks", + "id": "def-server.typeRegistryMock.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => jest.Mocked<", + "ISavedObjectTypeRegistry", + " & Pick<", + "SavedObjectTypeRegistry", + ", \"registerType\">>" + ], + "path": "packages/core/saved-objects/core-saved-objects-base-server-mocks/src/saved_objects_type_registry.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_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx new file mode 100644 index 0000000000000..ac44b8eb0e6e5 --- /dev/null +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -0,0 +1,30 @@ +--- +#### +#### 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. +#### +id: kibKbnCoreSavedObjectsBaseServerMocksPluginApi +slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks +title: "@kbn/core-saved-objects-base-server-mocks" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin +date: 2022-08-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] +--- +import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_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 | +|-------------------|-----------|------------------------|-----------------| +| 4 | 0 | 4 | 0 | + +## Server + +### Objects + + diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 8087c874029cd..5ce2261379262 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 3ba8459cfe797..e7d98cac1e0b5 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 82bb5388e16be..32f1e9fee5ec8 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index e83d2b7e021fc..bc5c204a26e5e 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index c71468f34f370..8802b1caa8897 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.devdocs.json b/api_docs/kbn_core_saved_objects_utils_server.devdocs.json new file mode 100644 index 0000000000000..c8f93a8055235 --- /dev/null +++ b/api_docs/kbn_core_saved_objects_utils_server.devdocs.json @@ -0,0 +1,1836 @@ +{ + "id": "@kbn/core-saved-objects-utils-server", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers", + "type": "Class", + "tags": [], + "label": "SavedObjectsErrorHelpers", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isSavedObjectsClientError", + "type": "Function", + "tags": [], + "label": "isSavedObjectsClientError", + "description": [], + "signature": [ + "(error: any) => error is ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isSavedObjectsClientError.$1", + "type": "Any", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "any" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError", + "type": "Function", + "tags": [], + "label": "decorateBadRequestError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateBadRequestError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createBadRequestError", + "type": "Function", + "tags": [], + "label": "createBadRequestError", + "description": [], + "signature": [ + "(reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createBadRequestError.$1", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createUnsupportedTypeError", + "type": "Function", + "tags": [], + "label": "createUnsupportedTypeError", + "description": [], + "signature": [ + "(type: string) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createUnsupportedTypeError.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isBadRequestError", + "type": "Function", + "tags": [], + "label": "isBadRequestError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isBadRequestError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createInvalidVersionError", + "type": "Function", + "tags": [], + "label": "createInvalidVersionError", + "description": [], + "signature": [ + "(versionInput?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createInvalidVersionError.$1", + "type": "string", + "tags": [], + "label": "versionInput", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isInvalidVersionError", + "type": "Function", + "tags": [], + "label": "isInvalidVersionError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isInvalidVersionError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError", + "type": "Function", + "tags": [], + "label": "decorateNotAuthorizedError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateNotAuthorizedError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isNotAuthorizedError", + "type": "Function", + "tags": [], + "label": "isNotAuthorizedError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isNotAuthorizedError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError", + "type": "Function", + "tags": [], + "label": "decorateForbiddenError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateForbiddenError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isForbiddenError", + "type": "Function", + "tags": [], + "label": "isForbiddenError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isForbiddenError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError", + "type": "Function", + "tags": [], + "label": "decorateRequestEntityTooLargeError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateRequestEntityTooLargeError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isRequestEntityTooLargeError", + "type": "Function", + "tags": [], + "label": "isRequestEntityTooLargeError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isRequestEntityTooLargeError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError", + "type": "Function", + "tags": [], + "label": "createGenericNotFoundError", + "description": [], + "signature": [ + "(type?: string | null, id?: string | null) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError.$1", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | null" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundError.$2", + "type": "CompoundType", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | null" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createIndexAliasNotFoundError", + "type": "Function", + "tags": [], + "label": "createIndexAliasNotFoundError", + "description": [], + "signature": [ + "(alias: string) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createIndexAliasNotFoundError.$1", + "type": "string", + "tags": [], + "label": "alias", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError", + "type": "Function", + "tags": [], + "label": "decorateIndexAliasNotFoundError", + "description": [], + "signature": [ + "(error: Error, alias: string) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateIndexAliasNotFoundError.$2", + "type": "string", + "tags": [], + "label": "alias", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isNotFoundError", + "type": "Function", + "tags": [], + "label": "isNotFoundError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isNotFoundError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError", + "type": "Function", + "tags": [], + "label": "decorateConflictError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateConflictError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError", + "type": "Function", + "tags": [], + "label": "createConflictError", + "description": [], + "signature": [ + "(type: string, id: string, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$2", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createConflictError.$3", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isConflictError", + "type": "Function", + "tags": [], + "label": "isConflictError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isConflictError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError", + "type": "Function", + "tags": [], + "label": "decorateTooManyRequestsError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateTooManyRequestsError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError", + "type": "Function", + "tags": [], + "label": "createTooManyRequestsError", + "description": [], + "signature": [ + "(type: string, id: string) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createTooManyRequestsError.$2", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isTooManyRequestsError", + "type": "Function", + "tags": [], + "label": "isTooManyRequestsError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isTooManyRequestsError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError", + "type": "Function", + "tags": [], + "label": "decorateEsCannotExecuteScriptError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsCannotExecuteScriptError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isEsCannotExecuteScriptError", + "type": "Function", + "tags": [], + "label": "isEsCannotExecuteScriptError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isEsCannotExecuteScriptError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError", + "type": "Function", + "tags": [], + "label": "decorateEsUnavailableError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateEsUnavailableError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isEsUnavailableError", + "type": "Function", + "tags": [], + "label": "isEsUnavailableError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isEsUnavailableError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError", + "type": "Function", + "tags": [], + "label": "decorateGeneralError", + "description": [], + "signature": [ + "(error: Error, reason?: string | undefined) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError.$1", + "type": "Object", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.decorateGeneralError.$2", + "type": "string", + "tags": [], + "label": "reason", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isGeneralError", + "type": "Function", + "tags": [], + "label": "isGeneralError", + "description": [], + "signature": [ + "(error: Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + ") => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.isGeneralError.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "Error | ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError", + "type": "Function", + "tags": [], + "label": "createGenericNotFoundEsUnavailableError", + "description": [], + "signature": [ + "(type?: string | null, id?: string | null) => ", + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError.$1", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | null" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError.$2", + "type": "CompoundType", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | null" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils", + "type": "Class", + "tags": [], + "label": "SavedObjectsUtils", + "description": [], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.namespaceIdToString", + "type": "Function", + "tags": [], + "label": "namespaceIdToString", + "description": [ + "\nConverts a given saved object namespace ID to its string representation. All namespace IDs have an identical string representation, with\nthe exception of the `undefined` namespace ID (which has a namespace string of `'default'`).\n" + ], + "signature": [ + "(namespace?: string | undefined) => string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.namespaceIdToString.$1", + "type": "string", + "tags": [], + "label": "namespace", + "description": [ + "The namespace ID, which must be either a non-empty string or `undefined`." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.namespaceStringToId", + "type": "Function", + "tags": [], + "label": "namespaceStringToId", + "description": [ + "\nConverts a given saved object namespace string to its ID representation. All namespace strings have an identical ID representation, with\nthe exception of the `'default'` namespace string (which has a namespace ID of `undefined`).\n" + ], + "signature": [ + "(namespace: string) => string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.namespaceStringToId.$1", + "type": "string", + "tags": [], + "label": "namespace", + "description": [ + "The namespace string, which must be non-empty." + ], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.createEmptyFindResponse", + "type": "Function", + "tags": [], + "label": "createEmptyFindResponse", + "description": [ + "\nCreates an empty response for a find operation. This is only intended to be used by saved objects client wrappers." + ], + "signature": [ + "({ page, perPage, }: ", + "SavedObjectsFindOptions", + ") => ", + "SavedObjectsFindResponse", + "" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.createEmptyFindResponse.$1", + "type": "Object", + "tags": [], + "label": "{\n page = FIND_DEFAULT_PAGE,\n perPage = FIND_DEFAULT_PER_PAGE,\n }", + "description": [], + "signature": [ + "SavedObjectsFindOptions" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.generateId", + "type": "Function", + "tags": [], + "label": "generateId", + "description": [ + "\nGenerates a random ID for a saved objects." + ], + "signature": [ + "() => string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.isRandomId", + "type": "Function", + "tags": [ + "todo" + ], + "label": "isRandomId", + "description": [ + "\nValidates that a saved object ID has been randomly generated.\n" + ], + "signature": [ + "(id: string | undefined) => boolean" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.isRandomId.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "The ID of a saved object." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId", + "type": "Function", + "tags": [], + "label": "getConvertedObjectId", + "description": [ + "\nUses a single-namespace object's \"legacy ID\" to determine what its new ID will be after it is converted to a multi-namespace type.\n" + ], + "signature": [ + "(namespace: string | undefined, type: string, id: string) => string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$1", + "type": "string", + "tags": [], + "label": "namespace", + "description": [ + "The namespace of the saved object before it is converted." + ], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$2", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "The type of the saved object before it is converted." + ], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.SavedObjectsUtils.getConvertedObjectId.$3", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "The ID of the saved object before it is converted." + ], + "signature": [ + "string" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [ + "The ID of the saved object after it is converted." + ] + } + ], + "initialIsOpen": false + } + ], + "functions": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.mergeSavedObjectMigrationMaps", + "type": "Function", + "tags": [], + "label": "mergeSavedObjectMigrationMaps", + "description": [ + "\nMerges two saved object migration maps.\n\nIf there is a migration for a given version on only one of the maps,\nthat migration function will be used:\n\nmergeSavedObjectMigrationMaps({ '1.2.3': f }, { '4.5.6': g }) -> { '1.2.3': f, '4.5.6': g }\n\nIf there is a migration for a given version on both maps, the migrations will be composed:\n\nmergeSavedObjectMigrationMaps({ '1.2.3': f }, { '1.2.3': g }) -> { '1.2.3': (doc, context) => f(g(doc, context), context) }\n" + ], + "signature": [ + "(map1: ", + "SavedObjectMigrationMap", + ", map2: ", + "SavedObjectMigrationMap", + ") => ", + "SavedObjectMigrationMap" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/merge_migration_maps.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.mergeSavedObjectMigrationMaps.$1", + "type": "Object", + "tags": [], + "label": "map1", + "description": [], + "signature": [ + "SavedObjectMigrationMap" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/merge_migration_maps.ts", + "deprecated": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.mergeSavedObjectMigrationMaps.$2", + "type": "Object", + "tags": [], + "label": "map2", + "description": [], + "signature": [ + "SavedObjectMigrationMap" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/merge_migration_maps.ts", + "deprecated": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.DecoratedError", + "type": "Interface", + "tags": [], + "label": "DecoratedError", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-utils-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsUtilsServerPluginApi", + "section": "def-server.DecoratedError", + "text": "DecoratedError" + }, + " extends ", + "Boom", + "" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.DecoratedError.code", + "type": "string", + "tags": [], + "label": "[code]", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_error_helpers.ts", + "deprecated": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.ALL_NAMESPACES_STRING", + "type": "string", + "tags": [], + "label": "ALL_NAMESPACES_STRING", + "description": [], + "signature": [ + "\"*\"" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.DEFAULT_NAMESPACE_STRING", + "type": "string", + "tags": [], + "label": "DEFAULT_NAMESPACE_STRING", + "description": [], + "signature": [ + "\"default\"" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.FIND_DEFAULT_PAGE", + "type": "number", + "tags": [], + "label": "FIND_DEFAULT_PAGE", + "description": [], + "signature": [ + "1" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.ts", + "deprecated": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-utils-server", + "id": "def-server.FIND_DEFAULT_PER_PAGE", + "type": "number", + "tags": [], + "label": "FIND_DEFAULT_PER_PAGE", + "description": [], + "signature": [ + "20" + ], + "path": "packages/core/saved-objects/core-saved-objects-utils-server/src/saved_objects_utils.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_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx new file mode 100644 index 0000000000000..ffa68015f2a8e --- /dev/null +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -0,0 +1,39 @@ +--- +#### +#### 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. +#### +id: kibKbnCoreSavedObjectsUtilsServerPluginApi +slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server +title: "@kbn/core-saved-objects-utils-server" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/core-saved-objects-utils-server plugin +date: 2022-08-23 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] +--- +import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 99 | 1 | 86 | 0 | + +## Server + +### Functions + + +### Classes + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 6d4f10f877f04..cd3f7ee02014f 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index d4e895dcdb7c4..466ca1484cef0 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 3ceef5f2ae980..d7903f7837eaa 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index f129db97a0ee1..1d2a9dc1d6a41 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 4ab1c0d6d197b..12dbdf608ba9c 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index ff772b30e2800..9b247776c7b41 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 7e9505349b993..4e65247c886f2 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 11e9573e6c278..acbb6dbd2aa5f 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index 46254f0b1bf88..cac3fb30f7879 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index a4d25e4a8b4c8..b8534d4cd5f03 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 408632e20e955..234d021982b6c 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index ee1c7e6da162d..1af482c90aa3a 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 631777f17b197..88b37840c6333 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 5a6ad81b8429f..cee1223ae0c4d 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 11fd31b384525..dd117fd11fea1 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 0b6849df60e53..5d47e4db459e1 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index e74eb3586fedd..9e71753495ee4 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 9d1b0938ee6d6..11d35f8211dc4 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 39e29add11f4f..c166c297078d2 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 788c2df268e17..af504b4d3fd3f 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 77a248212ec42..5f09abd07fcb8 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index a8fd39203679c..224b244ed5d03 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 058e9ecc01944..c0dec7ef569bb 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 7ad02c8a4e21f..82d71c69148da 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index c36a31b3f3b1b..2006c9b1374ae 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 3693f9483dad8..11cf62f072861 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_get_repo_files.mdx b/api_docs/kbn_get_repo_files.mdx index 30029d0ee9a86..905bd22577b02 100644 --- a/api_docs/kbn_get_repo_files.mdx +++ b/api_docs/kbn_get_repo_files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-get-repo-files title: "@kbn/get-repo-files" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/get-repo-files plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/get-repo-files'] --- import kbnGetRepoFilesObj from './kbn_get_repo_files.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 72e64e4308db3..6786dfe63fe83 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index f93a8dde44505..294bec3d803ea 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 85c912e2ed9bb..117b9c8cf4811 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index b2087c8fb2dec..e253257c48576 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index adcf719e448d0..93d499185343e 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index dce6cdc231d25..0f2ca6a0d292b 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index e9d43c221a946..ee831bb9aacf5 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index a2f38e4ff55b9..2140abbfe24f0 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 18110d36bb618..9b23301793cec 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_parser.mdx b/api_docs/kbn_kibana_manifest_parser.mdx index 23a8d98b75658..3b722b407667f 100644 --- a/api_docs/kbn_kibana_manifest_parser.mdx +++ b/api_docs/kbn_kibana_manifest_parser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-parser title: "@kbn/kibana-manifest-parser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-parser plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-parser'] --- import kbnKibanaManifestParserObj from './kbn_kibana_manifest_parser.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 4b2c19e02107b..f3cd5025f58c0 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 398abe38c8108..7f7731f3a1a6f 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index e94ecfd698cd0..73892bcdc0f26 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index e3beeafc537f3..f62b52199eee4 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index c79bec946fc29..4866ae9a6c8e2 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index c7c5da659639a..19e96ece2e666 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 7401adc69b2d3..be237c485aef5 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index a8afb7fccc9b0..9f20330ae1c82 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 14b455dacc247..a22806a7c48f3 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 93f1843422007..48a6e16b60147 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index a8f9f5b35d016..4271f565698ff 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index a5308ba6c163b..4d5edfeb689b7 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 28beacfc3f693..156876b51ce01 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 7beb778393c92..f739cbb87bdac 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 9b5d69a2a3fc9..dcd05fd6dd2b8 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index ab394175f6a0f..b0f4bfcad8fc6 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 0891519c809c3..7998b7126cc1a 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 03a3328c1e9f0..27ce322f9de31 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index d141725ac9a0c..9a0d2e0532fcb 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index ba328a7473dce..522dea862a690 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 24e94179a47e3..acc55514cc7da 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,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 description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 3a34e61699c34..46951fcb3c8e3 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,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 description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 4ff0ce7e6062c..9c59ecccfacdf 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 6eaadbb34e667..7a2d51225de14 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index a0b5b4884014b..a5368983a9037 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index 8540740dae243..a24dc3fdcfac7 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index e618ef74ac24a..e27861b3dca99 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 4d23c1929544d..cc48e0eae5762 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index a69e09a1ec284..766fffe7c6984 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index f3b95a89820d7..3b9e2f5a0c157 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 3e61673969d88..5161d40720335 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index da59db637dad9..7152c8babccbe 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 7ad5dbbabc86d..3306936f182c8 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 5198f1177290e..7912c2f146a1c 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 87751ce4f2b75..1067fe9472d69 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 5658adf14ad4c..5e9a63e81c31a 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.devdocs.json b/api_docs/kbn_shared_ux_card_no_data.devdocs.json index 480849c369f6b..37fb7c13e4e9d 100644 --- a/api_docs/kbn_shared_ux_card_no_data.devdocs.json +++ b/api_docs/kbn_shared_ux_card_no_data.devdocs.json @@ -178,7 +178,7 @@ "signature": [ "{ children?: React.ReactNode; onError?: React.ReactEventHandler | undefined; hidden?: boolean | undefined; icon?: React.ReactElement<", "EuiIconProps", - ", string | React.JSXElementConstructor> | null | undefined; image?: string | React.ReactElement> | undefined; className?: string | undefined; title?: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | undefined; onChange?: React.FormEventHandler | undefined; onKeyDown?: React.KeyboardEventHandler | undefined; onClick?: React.MouseEventHandler | undefined; id?: string | undefined; description?: React.ReactNode; security?: string | undefined; defaultValue?: string | number | readonly string[] | undefined; lang?: string | undefined; category?: string | undefined; defaultChecked?: boolean | undefined; suppressContentEditableWarning?: boolean | undefined; suppressHydrationWarning?: boolean | undefined; accessKey?: string | undefined; contentEditable?: \"inherit\" | Booleanish | undefined; contextMenu?: string | undefined; dir?: string | undefined; draggable?: Booleanish | undefined; placeholder?: string | undefined; slot?: string | undefined; spellCheck?: Booleanish | undefined; style?: React.CSSProperties | undefined; tabIndex?: number | undefined; translate?: \"no\" | \"yes\" | undefined; radioGroup?: string | undefined; role?: React.AriaRole | undefined; about?: string | undefined; datatype?: string | undefined; inlist?: any; prefix?: string | undefined; property?: string | undefined; resource?: string | undefined; typeof?: string | undefined; vocab?: string | undefined; autoCapitalize?: string | undefined; autoCorrect?: string | undefined; autoSave?: string | undefined; itemProp?: string | undefined; itemScope?: boolean | undefined; itemType?: string | undefined; itemID?: string | undefined; itemRef?: string | undefined; results?: number | undefined; unselectable?: \"on\" | \"off\" | undefined; inputMode?: \"none\" | \"email\" | \"search\" | \"text\" | \"tel\" | \"url\" | \"numeric\" | \"decimal\" | undefined; is?: string | undefined; 'aria-activedescendant'?: string | undefined; 'aria-atomic'?: boolean | \"false\" | \"true\" | undefined; 'aria-autocomplete'?: \"none\" | \"list\" | \"inline\" | \"both\" | undefined; 'aria-busy'?: boolean | \"false\" | \"true\" | undefined; 'aria-checked'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-colcount'?: number | undefined; 'aria-colindex'?: number | undefined; 'aria-colspan'?: number | undefined; 'aria-controls'?: string | undefined; 'aria-current'?: boolean | \"date\" | \"location\" | \"time\" | \"page\" | \"false\" | \"true\" | \"step\" | undefined; 'aria-describedby'?: string | undefined; 'aria-details'?: string | undefined; 'aria-disabled'?: boolean | \"false\" | \"true\" | undefined; 'aria-dropeffect'?: \"none\" | \"copy\" | \"link\" | \"execute\" | \"move\" | \"popup\" | undefined; 'aria-errormessage'?: string | undefined; 'aria-expanded'?: boolean | \"false\" | \"true\" | undefined; 'aria-flowto'?: string | undefined; 'aria-grabbed'?: boolean | \"false\" | \"true\" | undefined; 'aria-haspopup'?: boolean | \"grid\" | \"menu\" | \"false\" | \"true\" | \"dialog\" | \"listbox\" | \"tree\" | undefined; 'aria-hidden'?: boolean | \"false\" | \"true\" | undefined; 'aria-invalid'?: boolean | \"false\" | \"true\" | \"grammar\" | \"spelling\" | undefined; 'aria-keyshortcuts'?: string | undefined; 'aria-label'?: string | undefined; 'aria-labelledby'?: string | undefined; 'aria-level'?: number | undefined; 'aria-live'?: \"off\" | \"assertive\" | \"polite\" | undefined; 'aria-modal'?: boolean | \"false\" | \"true\" | undefined; 'aria-multiline'?: boolean | \"false\" | \"true\" | undefined; 'aria-multiselectable'?: boolean | \"false\" | \"true\" | undefined; 'aria-orientation'?: \"horizontal\" | \"vertical\" | undefined; 'aria-owns'?: string | undefined; 'aria-placeholder'?: string | undefined; 'aria-posinset'?: number | undefined; 'aria-pressed'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-readonly'?: boolean | \"false\" | \"true\" | undefined; 'aria-relevant'?: \"all\" | \"text\" | \"additions\" | \"additions removals\" | \"additions text\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined; 'aria-required'?: boolean | \"false\" | \"true\" | undefined; 'aria-roledescription'?: string | undefined; 'aria-rowcount'?: number | undefined; 'aria-rowindex'?: number | undefined; 'aria-rowspan'?: number | undefined; 'aria-selected'?: boolean | \"false\" | \"true\" | undefined; 'aria-setsize'?: number | undefined; 'aria-sort'?: \"none\" | \"other\" | \"ascending\" | \"descending\" | undefined; 'aria-valuemax'?: number | undefined; 'aria-valuemin'?: number | undefined; 'aria-valuenow'?: number | undefined; 'aria-valuetext'?: string | undefined; dangerouslySetInnerHTML?: { __html: string; } | undefined; onCopy?: React.ClipboardEventHandler | undefined; onCopyCapture?: React.ClipboardEventHandler | undefined; onCut?: React.ClipboardEventHandler | undefined; onCutCapture?: React.ClipboardEventHandler | undefined; onPaste?: React.ClipboardEventHandler | undefined; onPasteCapture?: React.ClipboardEventHandler | undefined; onCompositionEnd?: React.CompositionEventHandler | undefined; onCompositionEndCapture?: React.CompositionEventHandler | undefined; onCompositionStart?: React.CompositionEventHandler | undefined; onCompositionStartCapture?: React.CompositionEventHandler | undefined; onCompositionUpdate?: React.CompositionEventHandler | undefined; onCompositionUpdateCapture?: React.CompositionEventHandler | undefined; onFocus?: React.FocusEventHandler | undefined; onFocusCapture?: React.FocusEventHandler | undefined; onBlur?: React.FocusEventHandler | undefined; onBlurCapture?: React.FocusEventHandler | undefined; onChangeCapture?: React.FormEventHandler | undefined; onBeforeInput?: React.FormEventHandler | undefined; onBeforeInputCapture?: React.FormEventHandler | undefined; onInput?: React.FormEventHandler | undefined; onInputCapture?: React.FormEventHandler | undefined; onReset?: React.FormEventHandler | undefined; onResetCapture?: React.FormEventHandler | undefined; onSubmit?: React.FormEventHandler | undefined; onSubmitCapture?: React.FormEventHandler | undefined; onInvalid?: React.FormEventHandler | undefined; onInvalidCapture?: React.FormEventHandler | undefined; onLoad?: React.ReactEventHandler | undefined; onLoadCapture?: React.ReactEventHandler | undefined; onErrorCapture?: React.ReactEventHandler | undefined; onKeyDownCapture?: React.KeyboardEventHandler | undefined; onKeyPress?: React.KeyboardEventHandler | undefined; onKeyPressCapture?: React.KeyboardEventHandler | undefined; onKeyUp?: React.KeyboardEventHandler | undefined; onKeyUpCapture?: React.KeyboardEventHandler | undefined; onAbort?: React.ReactEventHandler | undefined; onAbortCapture?: React.ReactEventHandler | undefined; onCanPlay?: React.ReactEventHandler | undefined; onCanPlayCapture?: React.ReactEventHandler | undefined; onCanPlayThrough?: React.ReactEventHandler | undefined; onCanPlayThroughCapture?: React.ReactEventHandler | undefined; onDurationChange?: React.ReactEventHandler | undefined; onDurationChangeCapture?: React.ReactEventHandler | undefined; onEmptied?: React.ReactEventHandler | undefined; onEmptiedCapture?: React.ReactEventHandler | undefined; onEncrypted?: React.ReactEventHandler | undefined; onEncryptedCapture?: React.ReactEventHandler | undefined; onEnded?: React.ReactEventHandler | undefined; onEndedCapture?: React.ReactEventHandler | undefined; onLoadedData?: React.ReactEventHandler | undefined; onLoadedDataCapture?: React.ReactEventHandler | undefined; onLoadedMetadata?: React.ReactEventHandler | undefined; onLoadedMetadataCapture?: React.ReactEventHandler | undefined; onLoadStart?: React.ReactEventHandler | undefined; onLoadStartCapture?: React.ReactEventHandler | undefined; onPause?: React.ReactEventHandler | undefined; onPauseCapture?: React.ReactEventHandler | undefined; onPlay?: React.ReactEventHandler | undefined; onPlayCapture?: React.ReactEventHandler | undefined; onPlaying?: React.ReactEventHandler | undefined; onPlayingCapture?: React.ReactEventHandler | undefined; onProgress?: React.ReactEventHandler | undefined; onProgressCapture?: React.ReactEventHandler | undefined; onRateChange?: React.ReactEventHandler | undefined; onRateChangeCapture?: React.ReactEventHandler | undefined; onSeeked?: React.ReactEventHandler | undefined; onSeekedCapture?: React.ReactEventHandler | undefined; onSeeking?: React.ReactEventHandler | undefined; onSeekingCapture?: React.ReactEventHandler | undefined; onStalled?: React.ReactEventHandler | undefined; onStalledCapture?: React.ReactEventHandler | undefined; onSuspend?: React.ReactEventHandler | undefined; onSuspendCapture?: React.ReactEventHandler | undefined; onTimeUpdate?: React.ReactEventHandler | undefined; onTimeUpdateCapture?: React.ReactEventHandler | undefined; onVolumeChange?: React.ReactEventHandler | undefined; onVolumeChangeCapture?: React.ReactEventHandler | undefined; onWaiting?: React.ReactEventHandler | undefined; onWaitingCapture?: React.ReactEventHandler | undefined; onAuxClick?: React.MouseEventHandler | undefined; onAuxClickCapture?: React.MouseEventHandler | undefined; onClickCapture?: React.MouseEventHandler | undefined; onContextMenu?: React.MouseEventHandler | undefined; onContextMenuCapture?: React.MouseEventHandler | undefined; onDoubleClick?: React.MouseEventHandler | undefined; onDoubleClickCapture?: React.MouseEventHandler | undefined; onDrag?: React.DragEventHandler | undefined; onDragCapture?: React.DragEventHandler | undefined; onDragEnd?: React.DragEventHandler | undefined; onDragEndCapture?: React.DragEventHandler | undefined; onDragEnter?: React.DragEventHandler | undefined; onDragEnterCapture?: React.DragEventHandler | undefined; onDragExit?: React.DragEventHandler | undefined; onDragExitCapture?: React.DragEventHandler | undefined; onDragLeave?: React.DragEventHandler | undefined; onDragLeaveCapture?: React.DragEventHandler | undefined; onDragOver?: React.DragEventHandler | undefined; onDragOverCapture?: React.DragEventHandler | undefined; onDragStart?: React.DragEventHandler | undefined; onDragStartCapture?: React.DragEventHandler | undefined; onDrop?: React.DragEventHandler | undefined; onDropCapture?: React.DragEventHandler | undefined; onMouseDown?: React.MouseEventHandler | undefined; onMouseDownCapture?: React.MouseEventHandler | undefined; onMouseEnter?: React.MouseEventHandler | undefined; onMouseLeave?: React.MouseEventHandler | undefined; onMouseMove?: React.MouseEventHandler | undefined; onMouseMoveCapture?: React.MouseEventHandler | undefined; onMouseOut?: React.MouseEventHandler | undefined; onMouseOutCapture?: React.MouseEventHandler | undefined; onMouseOver?: React.MouseEventHandler | undefined; onMouseOverCapture?: React.MouseEventHandler | undefined; onMouseUp?: React.MouseEventHandler | undefined; onMouseUpCapture?: React.MouseEventHandler | undefined; onSelect?: React.ReactEventHandler | undefined; onSelectCapture?: React.ReactEventHandler | undefined; onTouchCancel?: React.TouchEventHandler | undefined; onTouchCancelCapture?: React.TouchEventHandler | undefined; onTouchEnd?: React.TouchEventHandler | undefined; onTouchEndCapture?: React.TouchEventHandler | undefined; onTouchMove?: React.TouchEventHandler | undefined; onTouchMoveCapture?: React.TouchEventHandler | undefined; onTouchStart?: React.TouchEventHandler | undefined; onTouchStartCapture?: React.TouchEventHandler | undefined; onPointerDown?: React.PointerEventHandler | undefined; onPointerDownCapture?: React.PointerEventHandler | undefined; onPointerMove?: React.PointerEventHandler | undefined; onPointerMoveCapture?: React.PointerEventHandler | undefined; onPointerUp?: React.PointerEventHandler | undefined; onPointerUpCapture?: React.PointerEventHandler | undefined; onPointerCancel?: React.PointerEventHandler | undefined; onPointerCancelCapture?: React.PointerEventHandler | undefined; onPointerEnter?: React.PointerEventHandler | undefined; onPointerEnterCapture?: React.PointerEventHandler | undefined; onPointerLeave?: React.PointerEventHandler | undefined; onPointerLeaveCapture?: React.PointerEventHandler | undefined; onPointerOver?: React.PointerEventHandler | undefined; onPointerOverCapture?: React.PointerEventHandler | undefined; onPointerOut?: React.PointerEventHandler | undefined; onPointerOutCapture?: React.PointerEventHandler | undefined; onGotPointerCapture?: React.PointerEventHandler | undefined; onGotPointerCaptureCapture?: React.PointerEventHandler | undefined; onLostPointerCapture?: React.PointerEventHandler | undefined; onLostPointerCaptureCapture?: React.PointerEventHandler | undefined; onScroll?: React.UIEventHandler | undefined; onScrollCapture?: React.UIEventHandler | undefined; onWheel?: React.WheelEventHandler | undefined; onWheelCapture?: React.WheelEventHandler | undefined; onAnimationStart?: React.AnimationEventHandler | undefined; onAnimationStartCapture?: React.AnimationEventHandler | undefined; onAnimationEnd?: React.AnimationEventHandler | undefined; onAnimationEndCapture?: React.AnimationEventHandler | undefined; onAnimationIteration?: React.AnimationEventHandler | undefined; onAnimationIterationCapture?: React.AnimationEventHandler | undefined; onTransitionEnd?: React.TransitionEventHandler | undefined; onTransitionEndCapture?: React.TransitionEventHandler | undefined; 'data-test-subj'?: string | undefined; href?: string | undefined; rel?: string | undefined; target?: string | undefined; paddingSize?: \"none\" | \"m\" | \"s\" | \"xs\" | \"l\" | \"xl\" | undefined; button?: React.ReactNode; footer?: React.ReactNode; hasBorder?: boolean | undefined; textAlign?: CardAlignment | undefined; titleElement?: \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"span\" | undefined; titleSize?: \"s\" | \"xs\" | undefined; betaBadgeProps?: Partial<(", + ", string | React.JSXElementConstructor> | null | undefined; image?: string | React.ReactElement> | undefined; className?: string | undefined; title?: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | undefined; onChange?: React.FormEventHandler | undefined; onKeyDown?: React.KeyboardEventHandler | undefined; onClick?: React.MouseEventHandler | undefined; id?: string | undefined; description?: React.ReactNode; security?: string | undefined; defaultValue?: string | number | readonly string[] | undefined; lang?: string | undefined; category?: string | undefined; defaultChecked?: boolean | undefined; suppressContentEditableWarning?: boolean | undefined; suppressHydrationWarning?: boolean | undefined; accessKey?: string | undefined; contentEditable?: \"inherit\" | Booleanish | undefined; contextMenu?: string | undefined; dir?: string | undefined; draggable?: Booleanish | undefined; placeholder?: string | undefined; slot?: string | undefined; spellCheck?: Booleanish | undefined; style?: React.CSSProperties | undefined; tabIndex?: number | undefined; translate?: \"no\" | \"yes\" | undefined; radioGroup?: string | undefined; role?: React.AriaRole | undefined; about?: string | undefined; datatype?: string | undefined; inlist?: any; prefix?: string | undefined; property?: string | undefined; resource?: string | undefined; typeof?: string | undefined; vocab?: string | undefined; autoCapitalize?: string | undefined; autoCorrect?: string | undefined; autoSave?: string | undefined; itemProp?: string | undefined; itemScope?: boolean | undefined; itemType?: string | undefined; itemID?: string | undefined; itemRef?: string | undefined; results?: number | undefined; unselectable?: \"on\" | \"off\" | undefined; inputMode?: \"none\" | \"email\" | \"search\" | \"text\" | \"tel\" | \"url\" | \"numeric\" | \"decimal\" | undefined; is?: string | undefined; 'aria-activedescendant'?: string | undefined; 'aria-atomic'?: Booleanish | undefined; 'aria-autocomplete'?: \"none\" | \"list\" | \"inline\" | \"both\" | undefined; 'aria-busy'?: Booleanish | undefined; 'aria-checked'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-colcount'?: number | undefined; 'aria-colindex'?: number | undefined; 'aria-colspan'?: number | undefined; 'aria-controls'?: string | undefined; 'aria-current'?: boolean | \"date\" | \"location\" | \"time\" | \"page\" | \"false\" | \"true\" | \"step\" | undefined; 'aria-describedby'?: string | undefined; 'aria-details'?: string | undefined; 'aria-disabled'?: Booleanish | undefined; 'aria-dropeffect'?: \"none\" | \"copy\" | \"link\" | \"execute\" | \"move\" | \"popup\" | undefined; 'aria-errormessage'?: string | undefined; 'aria-expanded'?: Booleanish | undefined; 'aria-flowto'?: string | undefined; 'aria-grabbed'?: Booleanish | undefined; 'aria-haspopup'?: boolean | \"grid\" | \"menu\" | \"false\" | \"true\" | \"dialog\" | \"listbox\" | \"tree\" | undefined; 'aria-hidden'?: Booleanish | undefined; 'aria-invalid'?: boolean | \"false\" | \"true\" | \"grammar\" | \"spelling\" | undefined; 'aria-keyshortcuts'?: string | undefined; 'aria-label'?: string | undefined; 'aria-labelledby'?: string | undefined; 'aria-level'?: number | undefined; 'aria-live'?: \"off\" | \"assertive\" | \"polite\" | undefined; 'aria-modal'?: Booleanish | undefined; 'aria-multiline'?: Booleanish | undefined; 'aria-multiselectable'?: Booleanish | undefined; 'aria-orientation'?: \"horizontal\" | \"vertical\" | undefined; 'aria-owns'?: string | undefined; 'aria-placeholder'?: string | undefined; 'aria-posinset'?: number | undefined; 'aria-pressed'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-readonly'?: Booleanish | undefined; 'aria-relevant'?: \"all\" | \"text\" | \"additions\" | \"additions removals\" | \"additions text\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined; 'aria-required'?: Booleanish | undefined; 'aria-roledescription'?: string | undefined; 'aria-rowcount'?: number | undefined; 'aria-rowindex'?: number | undefined; 'aria-rowspan'?: number | undefined; 'aria-selected'?: Booleanish | undefined; 'aria-setsize'?: number | undefined; 'aria-sort'?: \"none\" | \"other\" | \"ascending\" | \"descending\" | undefined; 'aria-valuemax'?: number | undefined; 'aria-valuemin'?: number | undefined; 'aria-valuenow'?: number | undefined; 'aria-valuetext'?: string | undefined; dangerouslySetInnerHTML?: { __html: string; } | undefined; onCopy?: React.ClipboardEventHandler | undefined; onCopyCapture?: React.ClipboardEventHandler | undefined; onCut?: React.ClipboardEventHandler | undefined; onCutCapture?: React.ClipboardEventHandler | undefined; onPaste?: React.ClipboardEventHandler | undefined; onPasteCapture?: React.ClipboardEventHandler | undefined; onCompositionEnd?: React.CompositionEventHandler | undefined; onCompositionEndCapture?: React.CompositionEventHandler | undefined; onCompositionStart?: React.CompositionEventHandler | undefined; onCompositionStartCapture?: React.CompositionEventHandler | undefined; onCompositionUpdate?: React.CompositionEventHandler | undefined; onCompositionUpdateCapture?: React.CompositionEventHandler | undefined; onFocus?: React.FocusEventHandler | undefined; onFocusCapture?: React.FocusEventHandler | undefined; onBlur?: React.FocusEventHandler | undefined; onBlurCapture?: React.FocusEventHandler | undefined; onChangeCapture?: React.FormEventHandler | undefined; onBeforeInput?: React.FormEventHandler | undefined; onBeforeInputCapture?: React.FormEventHandler | undefined; onInput?: React.FormEventHandler | undefined; onInputCapture?: React.FormEventHandler | undefined; onReset?: React.FormEventHandler | undefined; onResetCapture?: React.FormEventHandler | undefined; onSubmit?: React.FormEventHandler | undefined; onSubmitCapture?: React.FormEventHandler | undefined; onInvalid?: React.FormEventHandler | undefined; onInvalidCapture?: React.FormEventHandler | undefined; onLoad?: React.ReactEventHandler | undefined; onLoadCapture?: React.ReactEventHandler | undefined; onErrorCapture?: React.ReactEventHandler | undefined; onKeyDownCapture?: React.KeyboardEventHandler | undefined; onKeyPress?: React.KeyboardEventHandler | undefined; onKeyPressCapture?: React.KeyboardEventHandler | undefined; onKeyUp?: React.KeyboardEventHandler | undefined; onKeyUpCapture?: React.KeyboardEventHandler | undefined; onAbort?: React.ReactEventHandler | undefined; onAbortCapture?: React.ReactEventHandler | undefined; onCanPlay?: React.ReactEventHandler | undefined; onCanPlayCapture?: React.ReactEventHandler | undefined; onCanPlayThrough?: React.ReactEventHandler | undefined; onCanPlayThroughCapture?: React.ReactEventHandler | undefined; onDurationChange?: React.ReactEventHandler | undefined; onDurationChangeCapture?: React.ReactEventHandler | undefined; onEmptied?: React.ReactEventHandler | undefined; onEmptiedCapture?: React.ReactEventHandler | undefined; onEncrypted?: React.ReactEventHandler | undefined; onEncryptedCapture?: React.ReactEventHandler | undefined; onEnded?: React.ReactEventHandler | undefined; onEndedCapture?: React.ReactEventHandler | undefined; onLoadedData?: React.ReactEventHandler | undefined; onLoadedDataCapture?: React.ReactEventHandler | undefined; onLoadedMetadata?: React.ReactEventHandler | undefined; onLoadedMetadataCapture?: React.ReactEventHandler | undefined; onLoadStart?: React.ReactEventHandler | undefined; onLoadStartCapture?: React.ReactEventHandler | undefined; onPause?: React.ReactEventHandler | undefined; onPauseCapture?: React.ReactEventHandler | undefined; onPlay?: React.ReactEventHandler | undefined; onPlayCapture?: React.ReactEventHandler | undefined; onPlaying?: React.ReactEventHandler | undefined; onPlayingCapture?: React.ReactEventHandler | undefined; onProgress?: React.ReactEventHandler | undefined; onProgressCapture?: React.ReactEventHandler | undefined; onRateChange?: React.ReactEventHandler | undefined; onRateChangeCapture?: React.ReactEventHandler | undefined; onSeeked?: React.ReactEventHandler | undefined; onSeekedCapture?: React.ReactEventHandler | undefined; onSeeking?: React.ReactEventHandler | undefined; onSeekingCapture?: React.ReactEventHandler | undefined; onStalled?: React.ReactEventHandler | undefined; onStalledCapture?: React.ReactEventHandler | undefined; onSuspend?: React.ReactEventHandler | undefined; onSuspendCapture?: React.ReactEventHandler | undefined; onTimeUpdate?: React.ReactEventHandler | undefined; onTimeUpdateCapture?: React.ReactEventHandler | undefined; onVolumeChange?: React.ReactEventHandler | undefined; onVolumeChangeCapture?: React.ReactEventHandler | undefined; onWaiting?: React.ReactEventHandler | undefined; onWaitingCapture?: React.ReactEventHandler | undefined; onAuxClick?: React.MouseEventHandler | undefined; onAuxClickCapture?: React.MouseEventHandler | undefined; onClickCapture?: React.MouseEventHandler | undefined; onContextMenu?: React.MouseEventHandler | undefined; onContextMenuCapture?: React.MouseEventHandler | undefined; onDoubleClick?: React.MouseEventHandler | undefined; onDoubleClickCapture?: React.MouseEventHandler | undefined; onDrag?: React.DragEventHandler | undefined; onDragCapture?: React.DragEventHandler | undefined; onDragEnd?: React.DragEventHandler | undefined; onDragEndCapture?: React.DragEventHandler | undefined; onDragEnter?: React.DragEventHandler | undefined; onDragEnterCapture?: React.DragEventHandler | undefined; onDragExit?: React.DragEventHandler | undefined; onDragExitCapture?: React.DragEventHandler | undefined; onDragLeave?: React.DragEventHandler | undefined; onDragLeaveCapture?: React.DragEventHandler | undefined; onDragOver?: React.DragEventHandler | undefined; onDragOverCapture?: React.DragEventHandler | undefined; onDragStart?: React.DragEventHandler | undefined; onDragStartCapture?: React.DragEventHandler | undefined; onDrop?: React.DragEventHandler | undefined; onDropCapture?: React.DragEventHandler | undefined; onMouseDown?: React.MouseEventHandler | undefined; onMouseDownCapture?: React.MouseEventHandler | undefined; onMouseEnter?: React.MouseEventHandler | undefined; onMouseLeave?: React.MouseEventHandler | undefined; onMouseMove?: React.MouseEventHandler | undefined; onMouseMoveCapture?: React.MouseEventHandler | undefined; onMouseOut?: React.MouseEventHandler | undefined; onMouseOutCapture?: React.MouseEventHandler | undefined; onMouseOver?: React.MouseEventHandler | undefined; onMouseOverCapture?: React.MouseEventHandler | undefined; onMouseUp?: React.MouseEventHandler | undefined; onMouseUpCapture?: React.MouseEventHandler | undefined; onSelect?: React.ReactEventHandler | undefined; onSelectCapture?: React.ReactEventHandler | undefined; onTouchCancel?: React.TouchEventHandler | undefined; onTouchCancelCapture?: React.TouchEventHandler | undefined; onTouchEnd?: React.TouchEventHandler | undefined; onTouchEndCapture?: React.TouchEventHandler | undefined; onTouchMove?: React.TouchEventHandler | undefined; onTouchMoveCapture?: React.TouchEventHandler | undefined; onTouchStart?: React.TouchEventHandler | undefined; onTouchStartCapture?: React.TouchEventHandler | undefined; onPointerDown?: React.PointerEventHandler | undefined; onPointerDownCapture?: React.PointerEventHandler | undefined; onPointerMove?: React.PointerEventHandler | undefined; onPointerMoveCapture?: React.PointerEventHandler | undefined; onPointerUp?: React.PointerEventHandler | undefined; onPointerUpCapture?: React.PointerEventHandler | undefined; onPointerCancel?: React.PointerEventHandler | undefined; onPointerCancelCapture?: React.PointerEventHandler | undefined; onPointerEnter?: React.PointerEventHandler | undefined; onPointerEnterCapture?: React.PointerEventHandler | undefined; onPointerLeave?: React.PointerEventHandler | undefined; onPointerLeaveCapture?: React.PointerEventHandler | undefined; onPointerOver?: React.PointerEventHandler | undefined; onPointerOverCapture?: React.PointerEventHandler | undefined; onPointerOut?: React.PointerEventHandler | undefined; onPointerOutCapture?: React.PointerEventHandler | undefined; onGotPointerCapture?: React.PointerEventHandler | undefined; onGotPointerCaptureCapture?: React.PointerEventHandler | undefined; onLostPointerCapture?: React.PointerEventHandler | undefined; onLostPointerCaptureCapture?: React.PointerEventHandler | undefined; onScroll?: React.UIEventHandler | undefined; onScrollCapture?: React.UIEventHandler | undefined; onWheel?: React.WheelEventHandler | undefined; onWheelCapture?: React.WheelEventHandler | undefined; onAnimationStart?: React.AnimationEventHandler | undefined; onAnimationStartCapture?: React.AnimationEventHandler | undefined; onAnimationEnd?: React.AnimationEventHandler | undefined; onAnimationEndCapture?: React.AnimationEventHandler | undefined; onAnimationIteration?: React.AnimationEventHandler | undefined; onAnimationIterationCapture?: React.AnimationEventHandler | undefined; onTransitionEnd?: React.TransitionEventHandler | undefined; onTransitionEndCapture?: React.TransitionEventHandler | undefined; 'data-test-subj'?: string | undefined; href?: string | undefined; rel?: string | undefined; target?: string | undefined; paddingSize?: \"none\" | \"m\" | \"s\" | \"xs\" | \"l\" | \"xl\" | undefined; button?: React.ReactNode; footer?: React.ReactNode; hasBorder?: boolean | undefined; textAlign?: CardAlignment | undefined; titleElement?: \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"span\" | undefined; titleSize?: \"s\" | \"xs\" | undefined; betaBadgeProps?: Partial<(", "CommonProps", " & ", "DisambiguateSet", diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index f3907f21f4aac..de08de5f306a8 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,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 description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 512dd0e08412c..66053a3230fab 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index c0f40ecf5083f..e3e18ac5eabc5 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; 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 ee4897f052d57..ec9c4d2d460f5 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,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 description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index eafa4b4086e5a..ada46b22952f5 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; 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 9787dd1eb9e16..6ca0ea6af35f5 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,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 description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index c66936ac53795..bde0ff05b238c 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 9d642801a41d8..6edc2ba554481 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index 5e33f8c616dbe..c3541c1869b5a 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index b827c909c6d39..33380cff2d7d5 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index 3c32b0e7d5672..45c915c5d9834 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index b498e172e6b32..02fcad4f1afb5 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index 6254e19d57a76..11eda5cd60417 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 9057266d79f40..4887ce3399ad1 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; 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 7385ebf756065..5d623d390024f 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,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 description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 945f8088d3827..ecea103b5f7a7 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index cb8c5346408ca..af568a1712ce2 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 6b98d28e80250..a9b5584afe6f4 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index aa703428e586e..a526f65364898 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index 921e9967e5435..0214de673ddd1 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-package-json plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] --- import kbnSortPackageJsonObj from './kbn_sort_package_json.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 60cb11db4c8c8..ae55721fc807c 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index 7a459ef502e73..5fdbb7cc87496 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index d2d0c0806b170..42135ba446264 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 77dfec7a8f9c4..4fabd8c35cf77 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 62ed00ec41d40..a4f8c8e997a9a 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 309b23b1a8322..3f0f7d6140f6b 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 2620756f3699f..a8db1640fcadd 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index a6e087586ec21..700c492b13237 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] --- import kbnTypeSummarizerObj from './kbn_type_summarizer.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer_core.mdx b/api_docs/kbn_type_summarizer_core.mdx index e0f873f4510ef..43650aa4d96ca 100644 --- a/api_docs/kbn_type_summarizer_core.mdx +++ b/api_docs/kbn_type_summarizer_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer-core title: "@kbn/type-summarizer-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer-core plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer-core'] --- import kbnTypeSummarizerCoreObj from './kbn_type_summarizer_core.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 9ca9e722093a3..bc6d65bdfba02 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index bcfb965ffb4fa..940ac831af7d9 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 5f892773f33c9..7f94cb018758b 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index b4c2e9d288602..ca332bd0fc7ba 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 418ea2dd0cc68..40d7aac8f7431 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index ae11cdca1f69e..40ff0c662fc01 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index db2638b3efe3b..09302217ea0e0 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 6067849d4fcdb..35a7f556afab9 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 2227c7fdaaa2c..8adb1ee646c47 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index ae889a34552e2..5f4ebd51a0e09 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 6a175c0a44c3e..94f4e73a61f44 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index ba12db930ef84..ffe68cbbc5ec4 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index c654aeabae1eb..28fa8e87c67cb 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index c7154ada6b8c7..78cab4aef2d92 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 491199d91b8f6..590e82da3c93d 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 146762491ea46..08a667c54dec7 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index a957a28e184a4..2f9de9d95d16f 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index ebbda1c5ded50..e03da0c3c940f 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 014add3958be8..192e22f20fbce 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 665201c0897bc..ae4b8f4ee0c4f 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index ac59a55daf028..cf70a077351d7 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 2768ea059fdd3..6fb26b79b8264 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index a43eeb0bba57a..6699cae40f621 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index b208b229abb87..2f3dad4987357 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 048601d55003f..704fcd389865d 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -696,9 +696,9 @@ }, " | undefined; list: () => string[]; }; selectedAlertId?: string | undefined; } & ", "CommonProps", - " & { as?: \"div\" | undefined; } & _EuiFlyoutProps & Omit, HTMLDivElement>, keyof _EuiFlyoutProps> & Omit, HTMLDivElement>, \"key\" | \"css\" | keyof React.HTMLAttributes> & { ref?: React.RefObject | ((instance: HTMLDivElement | null) => void) | null | undefined; }, \"children\" | \"onError\" | \"hidden\" | \"color\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"id\" | \"security\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"as\" | keyof ", + " & { as?: \"div\" | undefined; } & _EuiFlyoutProps & Omit, HTMLDivElement>, keyof _EuiFlyoutProps> & Omit, HTMLDivElement>, \"key\" | keyof React.HTMLAttributes | \"css\"> & { ref?: React.RefObject | ((instance: HTMLDivElement | null) => void) | null | undefined; }, \"children\" | \"onError\" | \"hidden\" | \"color\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"id\" | \"security\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"as\" | keyof ", "CommonProps", - " | keyof React.ClassAttributes | keyof _EuiFlyoutProps>, \"children\" | \"onError\" | \"hidden\" | \"color\" | \"alert\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"id\" | \"key\" | \"css\" | \"security\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"as\" | keyof ", + " | keyof React.ClassAttributes | keyof _EuiFlyoutProps>, \"children\" | \"onError\" | \"hidden\" | \"color\" | \"alert\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"id\" | \"security\" | \"key\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"as\" | \"css\" | keyof ", "CommonProps", " | \"alerts\" | keyof _EuiFlyoutProps | \"isInApp\" | \"observabilityRuleTypeRegistry\" | \"selectedAlertId\"> & { ref?: React.RefObject | ((instance: HTMLDivElement | null) => void) | null | undefined; }> & { readonly _result: ({ alert, alerts, isInApp, observabilityRuleTypeRegistry, onClose, selectedAlertId, }: AlertsFlyoutProps) => JSX.Element | null; }" ], diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 1ef626b8f7fc2..0ba96bc264095 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 0fc1e5d78f97c..d2ba0e10c241d 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 9dd9cc8c8d2e5..f0566f96ebf28 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 410 | 340 | 36 | +| 413 | 343 | 36 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 29330 | 180 | 19815 | 917 | +| 29473 | 180 | 19859 | 918 | ## Plugin Directory @@ -40,13 +40,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 29 | 0 | 24 | 0 | | | [Cloud Security Posture](https://github.com/orgs/elastic/teams/cloud-posture-security) | The cloud security posture plugin | 18 | 0 | 2 | 3 | | | [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 | 207 | 0 | 199 | 7 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2524 | 2 | 296 | 6 | +| | [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) | - | 2524 | 1 | 216 | 5 | | 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 | 102 | 0 | 83 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 146 | 0 | 141 | 12 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 52 | 0 | 51 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3114 | 34 | 2428 | 22 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3117 | 34 | 2431 | 22 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 15 | 0 | 7 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Reusable data view field editor across Kibana | 49 | 0 | 29 | 3 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data view management app | 2 | 0 | 2 | 0 | @@ -143,7 +143,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 31 | 0 | 26 | 6 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 1 | 0 | 1 | 0 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 11 | 0 | 10 | 0 | -| | [Protections Experience Team](https://github.com/orgs/elastic/teams/protections-experience) | Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats | 15 | 0 | 3 | 1 | +| | [Protections Experience Team](https://github.com/orgs/elastic/teams/protections-experience) | Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats | 16 | 0 | 4 | 2 | | | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 447 | 1 | 342 | 32 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [Kibana Localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | @@ -169,7 +169,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Registers the vega visualization. Is the elastic version of vega and vega-lite libraries. | 2 | 0 | 2 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the vislib visualizations. These are the classical area/line/bar, pie, gauge/goal and heatmap charts. We want to replace them with elastic-charts. | 26 | 0 | 25 | 1 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the new xy-axis chart using the elastic-charts library, which will eventually replace the vislib xy-axis charts including bar, area, and line. | 53 | 0 | 50 | 5 | -| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 414 | 12 | 386 | 15 | +| | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 416 | 12 | 388 | 15 | | watcher | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | ## Package Directory @@ -277,11 +277,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 6 | 0 | 6 | 0 | | | Kibana Core | - | 94 | 1 | 66 | 0 | | | Kibana Core | - | 288 | 1 | 125 | 0 | +| | [Owner missing] | - | 35 | 0 | 29 | 1 | +| | [Owner missing] | - | 4 | 0 | 4 | 0 | | | Kibana Core | - | 2 | 0 | 1 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | | | Kibana Core | - | 7 | 0 | 7 | 0 | | | Kibana Core | - | 82 | 0 | 41 | 0 | | | Kibana Core | - | 225 | 0 | 82 | 0 | +| | [Owner missing] | - | 99 | 1 | 86 | 0 | | | Kibana Core | - | 11 | 0 | 9 | 0 | | | Kibana Core | - | 5 | 0 | 5 | 0 | | | Kibana Core | - | 6 | 0 | 4 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 5c7e49d043365..3f66038b74b58 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 4e7786a4d04eb..2a656809e94f3 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index bdcbe060dfa4f..7d157d3815ceb 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index b73d9a6198099..a44c6dd8737a9 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 817429c06f914..2730111e1f844 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index f6e14a981f176..3df69f3cb6180 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 2cc5e35127c42..6b3bd8a5df41a 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_management.devdocs.json b/api_docs/saved_objects_management.devdocs.json index a0876d761e9a5..ad24e52369344 100644 --- a/api_docs/saved_objects_management.devdocs.json +++ b/api_docs/saved_objects_management.devdocs.json @@ -294,7 +294,7 @@ "section": "def-public.SavedObjectsManagementRecord", "text": "SavedObjectsManagementRecord" }, - "; defaultValue?: string | number | readonly string[] | undefined; lang?: string | undefined; defaultChecked?: boolean | undefined; suppressContentEditableWarning?: boolean | undefined; suppressHydrationWarning?: boolean | undefined; accessKey?: string | undefined; contentEditable?: \"inherit\" | Booleanish | undefined; contextMenu?: string | undefined; dir?: string | undefined; draggable?: Booleanish | undefined; placeholder?: string | undefined; slot?: string | undefined; spellCheck?: Booleanish | undefined; style?: React.CSSProperties | undefined; tabIndex?: number | undefined; translate?: \"no\" | \"yes\" | undefined; radioGroup?: string | undefined; role?: React.AriaRole | undefined; about?: string | undefined; datatype?: string | undefined; inlist?: any; prefix?: string | undefined; property?: string | undefined; resource?: string | undefined; typeof?: string | undefined; vocab?: string | undefined; autoCapitalize?: string | undefined; autoCorrect?: string | undefined; autoSave?: string | undefined; itemProp?: string | undefined; itemScope?: boolean | undefined; itemType?: string | undefined; itemID?: string | undefined; itemRef?: string | undefined; results?: number | undefined; unselectable?: \"on\" | \"off\" | undefined; inputMode?: \"none\" | \"email\" | \"search\" | \"text\" | \"tel\" | \"url\" | \"numeric\" | \"decimal\" | undefined; is?: string | undefined; 'aria-activedescendant'?: string | undefined; 'aria-atomic'?: boolean | \"false\" | \"true\" | undefined; 'aria-autocomplete'?: \"none\" | \"list\" | \"inline\" | \"both\" | undefined; 'aria-busy'?: boolean | \"false\" | \"true\" | undefined; 'aria-checked'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-colcount'?: number | undefined; 'aria-colindex'?: number | undefined; 'aria-colspan'?: number | undefined; 'aria-controls'?: string | undefined; 'aria-current'?: boolean | \"date\" | \"location\" | \"time\" | \"page\" | \"false\" | \"true\" | \"step\" | undefined; 'aria-describedby'?: string | undefined; 'aria-details'?: string | undefined; 'aria-disabled'?: boolean | \"false\" | \"true\" | undefined; 'aria-dropeffect'?: \"none\" | \"copy\" | \"link\" | \"execute\" | \"move\" | \"popup\" | undefined; 'aria-errormessage'?: string | undefined; 'aria-expanded'?: boolean | \"false\" | \"true\" | undefined; 'aria-flowto'?: string | undefined; 'aria-grabbed'?: boolean | \"false\" | \"true\" | undefined; 'aria-haspopup'?: boolean | \"grid\" | \"menu\" | \"false\" | \"true\" | \"dialog\" | \"listbox\" | \"tree\" | undefined; 'aria-hidden'?: boolean | \"false\" | \"true\" | undefined; 'aria-invalid'?: boolean | \"false\" | \"true\" | \"grammar\" | \"spelling\" | undefined; 'aria-keyshortcuts'?: string | undefined; 'aria-label'?: string | undefined; 'aria-labelledby'?: string | undefined; 'aria-level'?: number | undefined; 'aria-live'?: \"off\" | \"assertive\" | \"polite\" | undefined; 'aria-modal'?: boolean | \"false\" | \"true\" | undefined; 'aria-multiline'?: boolean | \"false\" | \"true\" | undefined; 'aria-multiselectable'?: boolean | \"false\" | \"true\" | undefined; 'aria-orientation'?: \"horizontal\" | \"vertical\" | undefined; 'aria-owns'?: string | undefined; 'aria-placeholder'?: string | undefined; 'aria-posinset'?: number | undefined; 'aria-pressed'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-readonly'?: boolean | \"false\" | \"true\" | undefined; 'aria-relevant'?: \"all\" | \"text\" | \"additions\" | \"additions removals\" | \"additions text\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined; 'aria-required'?: boolean | \"false\" | \"true\" | undefined; 'aria-roledescription'?: string | undefined; 'aria-rowcount'?: number | undefined; 'aria-rowindex'?: number | undefined; 'aria-rowspan'?: number | undefined; 'aria-selected'?: boolean | \"false\" | \"true\" | undefined; 'aria-setsize'?: number | undefined; 'aria-sort'?: \"none\" | \"other\" | \"ascending\" | \"descending\" | undefined; 'aria-valuemax'?: number | undefined; 'aria-valuemin'?: number | undefined; 'aria-valuenow'?: number | undefined; 'aria-valuetext'?: string | undefined; dangerouslySetInnerHTML?: { __html: string; } | undefined; onCopy?: React.ClipboardEventHandler | undefined; onCopyCapture?: React.ClipboardEventHandler | undefined; onCut?: React.ClipboardEventHandler | undefined; onCutCapture?: React.ClipboardEventHandler | undefined; onPaste?: React.ClipboardEventHandler | undefined; onPasteCapture?: React.ClipboardEventHandler | undefined; onCompositionEnd?: React.CompositionEventHandler | undefined; onCompositionEndCapture?: React.CompositionEventHandler | undefined; onCompositionStart?: React.CompositionEventHandler | undefined; onCompositionStartCapture?: React.CompositionEventHandler | undefined; onCompositionUpdate?: React.CompositionEventHandler | undefined; onCompositionUpdateCapture?: React.CompositionEventHandler | undefined; onFocus?: React.FocusEventHandler | undefined; onFocusCapture?: React.FocusEventHandler | undefined; onBlur?: React.FocusEventHandler | undefined; onBlurCapture?: React.FocusEventHandler | undefined; onChangeCapture?: React.FormEventHandler | undefined; onBeforeInput?: React.FormEventHandler | undefined; onBeforeInputCapture?: React.FormEventHandler | undefined; onInput?: React.FormEventHandler | undefined; onInputCapture?: React.FormEventHandler | undefined; onReset?: React.FormEventHandler | undefined; onResetCapture?: React.FormEventHandler | undefined; onSubmit?: React.FormEventHandler | undefined; onSubmitCapture?: React.FormEventHandler | undefined; onInvalid?: React.FormEventHandler | undefined; onInvalidCapture?: React.FormEventHandler | undefined; onLoad?: React.ReactEventHandler | undefined; onLoadCapture?: React.ReactEventHandler | undefined; onErrorCapture?: React.ReactEventHandler | undefined; onKeyDownCapture?: React.KeyboardEventHandler | undefined; onKeyPress?: React.KeyboardEventHandler | undefined; onKeyPressCapture?: React.KeyboardEventHandler | undefined; onKeyUp?: React.KeyboardEventHandler | undefined; onKeyUpCapture?: React.KeyboardEventHandler | undefined; onAbort?: React.ReactEventHandler | undefined; onAbortCapture?: React.ReactEventHandler | undefined; onCanPlay?: React.ReactEventHandler | undefined; onCanPlayCapture?: React.ReactEventHandler | undefined; onCanPlayThrough?: React.ReactEventHandler | undefined; onCanPlayThroughCapture?: React.ReactEventHandler | undefined; onDurationChange?: React.ReactEventHandler | undefined; onDurationChangeCapture?: React.ReactEventHandler | undefined; onEmptied?: React.ReactEventHandler | undefined; onEmptiedCapture?: React.ReactEventHandler | undefined; onEncrypted?: React.ReactEventHandler | undefined; onEncryptedCapture?: React.ReactEventHandler | undefined; onEnded?: React.ReactEventHandler | undefined; onEndedCapture?: React.ReactEventHandler | undefined; onLoadedData?: React.ReactEventHandler | undefined; onLoadedDataCapture?: React.ReactEventHandler | undefined; onLoadedMetadata?: React.ReactEventHandler | undefined; onLoadedMetadataCapture?: React.ReactEventHandler | undefined; onLoadStart?: React.ReactEventHandler | undefined; onLoadStartCapture?: React.ReactEventHandler | undefined; onPause?: React.ReactEventHandler | undefined; onPauseCapture?: React.ReactEventHandler | undefined; onPlay?: React.ReactEventHandler | undefined; onPlayCapture?: React.ReactEventHandler | undefined; onPlaying?: React.ReactEventHandler | undefined; onPlayingCapture?: React.ReactEventHandler | undefined; onProgress?: React.ReactEventHandler | undefined; onProgressCapture?: React.ReactEventHandler | undefined; onRateChange?: React.ReactEventHandler | undefined; onRateChangeCapture?: React.ReactEventHandler | undefined; onSeeked?: React.ReactEventHandler | undefined; onSeekedCapture?: React.ReactEventHandler | undefined; onSeeking?: React.ReactEventHandler | undefined; onSeekingCapture?: React.ReactEventHandler | undefined; onStalled?: React.ReactEventHandler | undefined; onStalledCapture?: React.ReactEventHandler | undefined; onSuspend?: React.ReactEventHandler | undefined; onSuspendCapture?: React.ReactEventHandler | undefined; onTimeUpdate?: React.ReactEventHandler | undefined; onTimeUpdateCapture?: React.ReactEventHandler | undefined; onVolumeChange?: React.ReactEventHandler | undefined; onVolumeChangeCapture?: React.ReactEventHandler | undefined; onWaiting?: React.ReactEventHandler | undefined; onWaitingCapture?: React.ReactEventHandler | undefined; onAuxClick?: React.MouseEventHandler | undefined; onAuxClickCapture?: React.MouseEventHandler | undefined; onClickCapture?: React.MouseEventHandler | undefined; onContextMenu?: React.MouseEventHandler | undefined; onContextMenuCapture?: React.MouseEventHandler | undefined; onDoubleClick?: React.MouseEventHandler | undefined; onDoubleClickCapture?: React.MouseEventHandler | undefined; onDrag?: React.DragEventHandler | undefined; onDragCapture?: React.DragEventHandler | undefined; onDragEnd?: React.DragEventHandler | undefined; onDragEndCapture?: React.DragEventHandler | undefined; onDragEnter?: React.DragEventHandler | undefined; onDragEnterCapture?: React.DragEventHandler | undefined; onDragExit?: React.DragEventHandler | undefined; onDragExitCapture?: React.DragEventHandler | undefined; onDragLeave?: React.DragEventHandler | undefined; onDragLeaveCapture?: React.DragEventHandler | undefined; onDragOver?: React.DragEventHandler | undefined; onDragOverCapture?: React.DragEventHandler | undefined; onDragStart?: React.DragEventHandler | undefined; onDragStartCapture?: React.DragEventHandler | undefined; onDrop?: React.DragEventHandler | undefined; onDropCapture?: React.DragEventHandler | undefined; onMouseDown?: React.MouseEventHandler | undefined; onMouseDownCapture?: React.MouseEventHandler | undefined; onMouseEnter?: React.MouseEventHandler | undefined; onMouseLeave?: React.MouseEventHandler | undefined; onMouseMove?: React.MouseEventHandler | undefined; onMouseMoveCapture?: React.MouseEventHandler | undefined; onMouseOut?: React.MouseEventHandler | undefined; onMouseOutCapture?: React.MouseEventHandler | undefined; onMouseOver?: React.MouseEventHandler | undefined; onMouseOverCapture?: React.MouseEventHandler | undefined; onMouseUp?: React.MouseEventHandler | undefined; onMouseUpCapture?: React.MouseEventHandler | undefined; onSelect?: React.ReactEventHandler | undefined; onSelectCapture?: React.ReactEventHandler | undefined; onTouchCancel?: React.TouchEventHandler | undefined; onTouchCancelCapture?: React.TouchEventHandler | undefined; onTouchEnd?: React.TouchEventHandler | undefined; onTouchEndCapture?: React.TouchEventHandler | undefined; onTouchMove?: React.TouchEventHandler | undefined; onTouchMoveCapture?: React.TouchEventHandler | undefined; onTouchStart?: React.TouchEventHandler | undefined; onTouchStartCapture?: React.TouchEventHandler | undefined; onPointerDown?: React.PointerEventHandler | undefined; onPointerDownCapture?: React.PointerEventHandler | undefined; onPointerMove?: React.PointerEventHandler | undefined; onPointerMoveCapture?: React.PointerEventHandler | undefined; onPointerUp?: React.PointerEventHandler | undefined; onPointerUpCapture?: React.PointerEventHandler | undefined; onPointerCancel?: React.PointerEventHandler | undefined; onPointerCancelCapture?: React.PointerEventHandler | undefined; onPointerEnter?: React.PointerEventHandler | undefined; onPointerEnterCapture?: React.PointerEventHandler | undefined; onPointerLeave?: React.PointerEventHandler | undefined; onPointerLeaveCapture?: React.PointerEventHandler | undefined; onPointerOver?: React.PointerEventHandler | undefined; onPointerOverCapture?: React.PointerEventHandler | undefined; onPointerOut?: React.PointerEventHandler | undefined; onPointerOutCapture?: React.PointerEventHandler | undefined; onGotPointerCapture?: React.PointerEventHandler | undefined; onGotPointerCaptureCapture?: React.PointerEventHandler | undefined; onLostPointerCapture?: React.PointerEventHandler | undefined; onLostPointerCaptureCapture?: React.PointerEventHandler | undefined; onScroll?: React.UIEventHandler | undefined; onScrollCapture?: React.UIEventHandler | undefined; onWheel?: React.WheelEventHandler | undefined; onWheelCapture?: React.WheelEventHandler | undefined; onAnimationStart?: React.AnimationEventHandler | undefined; onAnimationStartCapture?: React.AnimationEventHandler | undefined; onAnimationEnd?: React.AnimationEventHandler | undefined; onAnimationEndCapture?: React.AnimationEventHandler | undefined; onAnimationIteration?: React.AnimationEventHandler | undefined; onAnimationIterationCapture?: React.AnimationEventHandler | undefined; onTransitionEnd?: React.TransitionEventHandler | undefined; onTransitionEndCapture?: React.TransitionEventHandler | undefined; 'data-test-subj'?: string | undefined; height?: string | number | undefined; width?: string | undefined; readOnly?: boolean | undefined; align?: ", + "; defaultValue?: string | number | readonly string[] | undefined; lang?: string | undefined; defaultChecked?: boolean | undefined; suppressContentEditableWarning?: boolean | undefined; suppressHydrationWarning?: boolean | undefined; accessKey?: string | undefined; contentEditable?: \"inherit\" | Booleanish | undefined; contextMenu?: string | undefined; dir?: string | undefined; draggable?: Booleanish | undefined; placeholder?: string | undefined; slot?: string | undefined; spellCheck?: Booleanish | undefined; style?: React.CSSProperties | undefined; tabIndex?: number | undefined; translate?: \"no\" | \"yes\" | undefined; radioGroup?: string | undefined; role?: React.AriaRole | undefined; about?: string | undefined; datatype?: string | undefined; inlist?: any; prefix?: string | undefined; property?: string | undefined; resource?: string | undefined; typeof?: string | undefined; vocab?: string | undefined; autoCapitalize?: string | undefined; autoCorrect?: string | undefined; autoSave?: string | undefined; itemProp?: string | undefined; itemScope?: boolean | undefined; itemType?: string | undefined; itemID?: string | undefined; itemRef?: string | undefined; results?: number | undefined; unselectable?: \"on\" | \"off\" | undefined; inputMode?: \"none\" | \"email\" | \"search\" | \"text\" | \"tel\" | \"url\" | \"numeric\" | \"decimal\" | undefined; is?: string | undefined; 'aria-activedescendant'?: string | undefined; 'aria-atomic'?: Booleanish | undefined; 'aria-autocomplete'?: \"none\" | \"list\" | \"inline\" | \"both\" | undefined; 'aria-busy'?: Booleanish | undefined; 'aria-checked'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-colcount'?: number | undefined; 'aria-colindex'?: number | undefined; 'aria-colspan'?: number | undefined; 'aria-controls'?: string | undefined; 'aria-current'?: boolean | \"date\" | \"location\" | \"time\" | \"page\" | \"false\" | \"true\" | \"step\" | undefined; 'aria-describedby'?: string | undefined; 'aria-details'?: string | undefined; 'aria-disabled'?: Booleanish | undefined; 'aria-dropeffect'?: \"none\" | \"copy\" | \"link\" | \"execute\" | \"move\" | \"popup\" | undefined; 'aria-errormessage'?: string | undefined; 'aria-expanded'?: Booleanish | undefined; 'aria-flowto'?: string | undefined; 'aria-grabbed'?: Booleanish | undefined; 'aria-haspopup'?: boolean | \"grid\" | \"menu\" | \"false\" | \"true\" | \"dialog\" | \"listbox\" | \"tree\" | undefined; 'aria-hidden'?: Booleanish | undefined; 'aria-invalid'?: boolean | \"false\" | \"true\" | \"grammar\" | \"spelling\" | undefined; 'aria-keyshortcuts'?: string | undefined; 'aria-label'?: string | undefined; 'aria-labelledby'?: string | undefined; 'aria-level'?: number | undefined; 'aria-live'?: \"off\" | \"assertive\" | \"polite\" | undefined; 'aria-modal'?: Booleanish | undefined; 'aria-multiline'?: Booleanish | undefined; 'aria-multiselectable'?: Booleanish | undefined; 'aria-orientation'?: \"horizontal\" | \"vertical\" | undefined; 'aria-owns'?: string | undefined; 'aria-placeholder'?: string | undefined; 'aria-posinset'?: number | undefined; 'aria-pressed'?: boolean | \"mixed\" | \"false\" | \"true\" | undefined; 'aria-readonly'?: Booleanish | undefined; 'aria-relevant'?: \"all\" | \"text\" | \"additions\" | \"additions removals\" | \"additions text\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined; 'aria-required'?: Booleanish | undefined; 'aria-roledescription'?: string | undefined; 'aria-rowcount'?: number | undefined; 'aria-rowindex'?: number | undefined; 'aria-rowspan'?: number | undefined; 'aria-selected'?: Booleanish | undefined; 'aria-setsize'?: number | undefined; 'aria-sort'?: \"none\" | \"other\" | \"ascending\" | \"descending\" | undefined; 'aria-valuemax'?: number | undefined; 'aria-valuemin'?: number | undefined; 'aria-valuenow'?: number | undefined; 'aria-valuetext'?: string | undefined; dangerouslySetInnerHTML?: { __html: string; } | undefined; onCopy?: React.ClipboardEventHandler | undefined; onCopyCapture?: React.ClipboardEventHandler | undefined; onCut?: React.ClipboardEventHandler | undefined; onCutCapture?: React.ClipboardEventHandler | undefined; onPaste?: React.ClipboardEventHandler | undefined; onPasteCapture?: React.ClipboardEventHandler | undefined; onCompositionEnd?: React.CompositionEventHandler | undefined; onCompositionEndCapture?: React.CompositionEventHandler | undefined; onCompositionStart?: React.CompositionEventHandler | undefined; onCompositionStartCapture?: React.CompositionEventHandler | undefined; onCompositionUpdate?: React.CompositionEventHandler | undefined; onCompositionUpdateCapture?: React.CompositionEventHandler | undefined; onFocus?: React.FocusEventHandler | undefined; onFocusCapture?: React.FocusEventHandler | undefined; onBlur?: React.FocusEventHandler | undefined; onBlurCapture?: React.FocusEventHandler | undefined; onChangeCapture?: React.FormEventHandler | undefined; onBeforeInput?: React.FormEventHandler | undefined; onBeforeInputCapture?: React.FormEventHandler | undefined; onInput?: React.FormEventHandler | undefined; onInputCapture?: React.FormEventHandler | undefined; onReset?: React.FormEventHandler | undefined; onResetCapture?: React.FormEventHandler | undefined; onSubmit?: React.FormEventHandler | undefined; onSubmitCapture?: React.FormEventHandler | undefined; onInvalid?: React.FormEventHandler | undefined; onInvalidCapture?: React.FormEventHandler | undefined; onLoad?: React.ReactEventHandler | undefined; onLoadCapture?: React.ReactEventHandler | undefined; onErrorCapture?: React.ReactEventHandler | undefined; onKeyDownCapture?: React.KeyboardEventHandler | undefined; onKeyPress?: React.KeyboardEventHandler | undefined; onKeyPressCapture?: React.KeyboardEventHandler | undefined; onKeyUp?: React.KeyboardEventHandler | undefined; onKeyUpCapture?: React.KeyboardEventHandler | undefined; onAbort?: React.ReactEventHandler | undefined; onAbortCapture?: React.ReactEventHandler | undefined; onCanPlay?: React.ReactEventHandler | undefined; onCanPlayCapture?: React.ReactEventHandler | undefined; onCanPlayThrough?: React.ReactEventHandler | undefined; onCanPlayThroughCapture?: React.ReactEventHandler | undefined; onDurationChange?: React.ReactEventHandler | undefined; onDurationChangeCapture?: React.ReactEventHandler | undefined; onEmptied?: React.ReactEventHandler | undefined; onEmptiedCapture?: React.ReactEventHandler | undefined; onEncrypted?: React.ReactEventHandler | undefined; onEncryptedCapture?: React.ReactEventHandler | undefined; onEnded?: React.ReactEventHandler | undefined; onEndedCapture?: React.ReactEventHandler | undefined; onLoadedData?: React.ReactEventHandler | undefined; onLoadedDataCapture?: React.ReactEventHandler | undefined; onLoadedMetadata?: React.ReactEventHandler | undefined; onLoadedMetadataCapture?: React.ReactEventHandler | undefined; onLoadStart?: React.ReactEventHandler | undefined; onLoadStartCapture?: React.ReactEventHandler | undefined; onPause?: React.ReactEventHandler | undefined; onPauseCapture?: React.ReactEventHandler | undefined; onPlay?: React.ReactEventHandler | undefined; onPlayCapture?: React.ReactEventHandler | undefined; onPlaying?: React.ReactEventHandler | undefined; onPlayingCapture?: React.ReactEventHandler | undefined; onProgress?: React.ReactEventHandler | undefined; onProgressCapture?: React.ReactEventHandler | undefined; onRateChange?: React.ReactEventHandler | undefined; onRateChangeCapture?: React.ReactEventHandler | undefined; onSeeked?: React.ReactEventHandler | undefined; onSeekedCapture?: React.ReactEventHandler | undefined; onSeeking?: React.ReactEventHandler | undefined; onSeekingCapture?: React.ReactEventHandler | undefined; onStalled?: React.ReactEventHandler | undefined; onStalledCapture?: React.ReactEventHandler | undefined; onSuspend?: React.ReactEventHandler | undefined; onSuspendCapture?: React.ReactEventHandler | undefined; onTimeUpdate?: React.ReactEventHandler | undefined; onTimeUpdateCapture?: React.ReactEventHandler | undefined; onVolumeChange?: React.ReactEventHandler | undefined; onVolumeChangeCapture?: React.ReactEventHandler | undefined; onWaiting?: React.ReactEventHandler | undefined; onWaitingCapture?: React.ReactEventHandler | undefined; onAuxClick?: React.MouseEventHandler | undefined; onAuxClickCapture?: React.MouseEventHandler | undefined; onClickCapture?: React.MouseEventHandler | undefined; onContextMenu?: React.MouseEventHandler | undefined; onContextMenuCapture?: React.MouseEventHandler | undefined; onDoubleClick?: React.MouseEventHandler | undefined; onDoubleClickCapture?: React.MouseEventHandler | undefined; onDrag?: React.DragEventHandler | undefined; onDragCapture?: React.DragEventHandler | undefined; onDragEnd?: React.DragEventHandler | undefined; onDragEndCapture?: React.DragEventHandler | undefined; onDragEnter?: React.DragEventHandler | undefined; onDragEnterCapture?: React.DragEventHandler | undefined; onDragExit?: React.DragEventHandler | undefined; onDragExitCapture?: React.DragEventHandler | undefined; onDragLeave?: React.DragEventHandler | undefined; onDragLeaveCapture?: React.DragEventHandler | undefined; onDragOver?: React.DragEventHandler | undefined; onDragOverCapture?: React.DragEventHandler | undefined; onDragStart?: React.DragEventHandler | undefined; onDragStartCapture?: React.DragEventHandler | undefined; onDrop?: React.DragEventHandler | undefined; onDropCapture?: React.DragEventHandler | undefined; onMouseDown?: React.MouseEventHandler | undefined; onMouseDownCapture?: React.MouseEventHandler | undefined; onMouseEnter?: React.MouseEventHandler | undefined; onMouseLeave?: React.MouseEventHandler | undefined; onMouseMove?: React.MouseEventHandler | undefined; onMouseMoveCapture?: React.MouseEventHandler | undefined; onMouseOut?: React.MouseEventHandler | undefined; onMouseOutCapture?: React.MouseEventHandler | undefined; onMouseOver?: React.MouseEventHandler | undefined; onMouseOverCapture?: React.MouseEventHandler | undefined; onMouseUp?: React.MouseEventHandler | undefined; onMouseUpCapture?: React.MouseEventHandler | undefined; onSelect?: React.ReactEventHandler | undefined; onSelectCapture?: React.ReactEventHandler | undefined; onTouchCancel?: React.TouchEventHandler | undefined; onTouchCancelCapture?: React.TouchEventHandler | undefined; onTouchEnd?: React.TouchEventHandler | undefined; onTouchEndCapture?: React.TouchEventHandler | undefined; onTouchMove?: React.TouchEventHandler | undefined; onTouchMoveCapture?: React.TouchEventHandler | undefined; onTouchStart?: React.TouchEventHandler | undefined; onTouchStartCapture?: React.TouchEventHandler | undefined; onPointerDown?: React.PointerEventHandler | undefined; onPointerDownCapture?: React.PointerEventHandler | undefined; onPointerMove?: React.PointerEventHandler | undefined; onPointerMoveCapture?: React.PointerEventHandler | undefined; onPointerUp?: React.PointerEventHandler | undefined; onPointerUpCapture?: React.PointerEventHandler | undefined; onPointerCancel?: React.PointerEventHandler | undefined; onPointerCancelCapture?: React.PointerEventHandler | undefined; onPointerEnter?: React.PointerEventHandler | undefined; onPointerEnterCapture?: React.PointerEventHandler | undefined; onPointerLeave?: React.PointerEventHandler | undefined; onPointerLeaveCapture?: React.PointerEventHandler | undefined; onPointerOver?: React.PointerEventHandler | undefined; onPointerOverCapture?: React.PointerEventHandler | undefined; onPointerOut?: React.PointerEventHandler | undefined; onPointerOutCapture?: React.PointerEventHandler | undefined; onGotPointerCapture?: React.PointerEventHandler | undefined; onGotPointerCaptureCapture?: React.PointerEventHandler | undefined; onLostPointerCapture?: React.PointerEventHandler | undefined; onLostPointerCaptureCapture?: React.PointerEventHandler | undefined; onScroll?: React.UIEventHandler | undefined; onScrollCapture?: React.UIEventHandler | undefined; onWheel?: React.WheelEventHandler | undefined; onWheelCapture?: React.WheelEventHandler | undefined; onAnimationStart?: React.AnimationEventHandler | undefined; onAnimationStartCapture?: React.AnimationEventHandler | undefined; onAnimationEnd?: React.AnimationEventHandler | undefined; onAnimationEndCapture?: React.AnimationEventHandler | undefined; onAnimationIteration?: React.AnimationEventHandler | undefined; onAnimationIterationCapture?: React.AnimationEventHandler | undefined; onTransitionEnd?: React.TransitionEventHandler | undefined; onTransitionEndCapture?: React.TransitionEventHandler | undefined; 'data-test-subj'?: string | undefined; height?: string | number | undefined; width?: string | undefined; readOnly?: boolean | undefined; align?: ", "HorizontalAlignment", " | undefined; abbr?: string | undefined; footer?: string | React.ReactElement> | ((props: ", "EuiTableFooterProps", diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 29d91d20cf02b..eba0b351cf94b 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 2c33fd3715fab..bd705560dbc0b 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 6c061694de3e2..e6e194f01a620 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index f4c21e0a52ea2..a31365834c59a 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 98da263297266..a2241ec00fa20 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index 2860839da32dd..5413d3758f25c 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 37faaa1366ca3..cadb6596d17d4 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index b9a7017fba830..92bf59787afc9 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index a320d389f9018..f2e6f2ee5f2b5 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index fb374a526cb8c..d90c34dadbb6d 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 4e17deb78c52e..6154f66889c80 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 946e1220ffea2..e997e576cb621 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 55cdcac9ab284..11e7a1347ad53 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 94964f824327b..ea654495c377d 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 4a8f0134cfcde..8d087a165237e 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 87dfbce21f830..5e62d1ce2cc7f 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index d7c1b6a63da36..6ee8f33cf9ce5 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 45f696e98e0d6..43447eed379f6 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.devdocs.json b/api_docs/threat_intelligence.devdocs.json index 380afebb238bf..cc29bb3584111 100644 --- a/api_docs/threat_intelligence.devdocs.json +++ b/api_docs/threat_intelligence.devdocs.json @@ -132,6 +132,66 @@ } ], "interfaces": [ + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext", + "type": "Interface", + "tags": [], + "label": "SecuritySolutionPluginContext", + "description": [ + "\nMethods exposed from the security solution to the threat intelligence application." + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false, + "children": [ + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.getFiltersGlobalComponent", + "type": "Function", + "tags": [], + "label": "getFiltersGlobalComponent", + "description": [ + "\nGets the `FiltersGlobal` component for embedding a filter bar in the security solution application." + ], + "signature": [ + "() => React.ComponentType<{ children: React.ReactNode; }>" + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.licenseService", + "type": "Object", + "tags": [], + "label": "licenseService", + "description": [ + "\nGet the user's license to drive the Threat Intelligence plugin's visibility." + ], + "signature": [ + "LicenseAware" + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false + }, + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.sourcererDataView", + "type": "Object", + "tags": [], + "label": "sourcererDataView", + "description": [], + "signature": [ + "SourcererDataView" + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "threatIntelligence", "id": "def-public.ThreatIntelligencePluginSetup", @@ -167,8 +227,8 @@ "pluginId": "threatIntelligence", "scope": "public", "docId": "kibThreatIntelligencePluginApi", - "section": "def-public.ThreatIntelligenceSecuritySolutionContext", - "text": "ThreatIntelligenceSecuritySolutionContext" + "section": "def-public.SecuritySolutionPluginContext", + "text": "SecuritySolutionPluginContext" }, "; }) => React.ReactElement>" ], @@ -179,53 +239,6 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "threatIntelligence", - "id": "def-public.ThreatIntelligenceSecuritySolutionContext", - "type": "Interface", - "tags": [], - "label": "ThreatIntelligenceSecuritySolutionContext", - "description": [ - "\nMethods exposed from the security solution to the threat intelligence application." - ], - "path": "x-pack/plugins/threat_intelligence/public/types.ts", - "deprecated": false, - "children": [ - { - "parentPluginId": "threatIntelligence", - "id": "def-public.ThreatIntelligenceSecuritySolutionContext.getFiltersGlobalComponent", - "type": "Function", - "tags": [], - "label": "getFiltersGlobalComponent", - "description": [ - "\nGets the `FiltersGlobal` component for embedding a filter bar in the security solution application." - ], - "signature": [ - "() => React.ComponentType<{ children: React.ReactNode; }>" - ], - "path": "x-pack/plugins/threat_intelligence/public/types.ts", - "deprecated": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "threatIntelligence", - "id": "def-public.ThreatIntelligenceSecuritySolutionContext.licenseService", - "type": "Object", - "tags": [], - "label": "licenseService", - "description": [ - "\nGet the user's license to drive the Threat Intelligence plugin's visibility." - ], - "signature": [ - "LicenseAware" - ], - "path": "x-pack/plugins/threat_intelligence/public/types.ts", - "deprecated": false - } - ], - "initialIsOpen": false } ], "enums": [], diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 7846b7583c6ef..acc6772f224d6 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Protections Experience Team](https://github.com/orgs/elastic/teams/prot | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 15 | 0 | 3 | 1 | +| 16 | 0 | 4 | 2 | ## Client diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index c8e373f2e9f61..da1215c0693e2 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 06540db67aba9..e5fe712b5b489 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 9c5644e43758a..8a9b20c2a05ce 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 3344aedd4590a..9ea4163fe785f 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index 503cd435c1a62..7a3f7450c8baa 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 64f0d6ae8d7ce..6e3cb31272fc9 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index ba1c3c375e317..59e01e601153b 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 86c118c1c8db7..fcaf32592b753 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index f807def63b4a7..3c02fa62b3a67 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 50b3264a3818d..11caefeca80a4 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 9b58b7dbfb92a..6ba49f66004f9 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 2b78f7f5bd11d..843fd83cfe35e 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 51a8f40a7aac4..9bcfb92ec93cb 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index da4917cdfe030..e48151d177425 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 840f586427643..849e3c38b7f3e 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 6b73405739b4b..9bafd8cb97de8 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index 3f6284c0d0c29..b628dc6f57e31 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 1c42f4125d7c6..7ab92e676f3ba 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index 25fcfb9665a95..f2b331492f7d2 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index e311b30da528e..69079cebb44cf 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index c706825202fd6..15691cacaad28 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -99,6 +99,14 @@ "section": "def-common.VisParams", "text": "VisParams" }, + " | undefined, timeRange?: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, " | undefined) => Promise<", { "pluginId": "visualizations", @@ -2870,7 +2878,7 @@ "label": "configuration", "description": [], "signature": [ - "{ fill: string | number; legend: { isVisible: boolean; position: string; shouldTruncate: boolean; maxLines: number; showSingleSeries: boolean; }; gridLinesVisibility: { x: boolean; yLeft: boolean; yRight: boolean; }; extents: { yLeftExtent: AxisExtents; yRightExtent: AxisExtents; }; }" + "{ fill: string | number; legend: { isVisible: boolean; position: string; shouldTruncate: boolean; maxLines: number; showSingleSeries: boolean; }; gridLinesVisibility: { x: boolean; yLeft: boolean; yRight: boolean; }; tickLabelsVisibility?: { x: boolean; yLeft: boolean; yRight: boolean; } | undefined; axisTitlesVisibility?: { x: boolean; yLeft: boolean; yRight: boolean; } | undefined; valueLabels?: boolean | undefined; extents?: { yLeftExtent: AxisExtents; yRightExtent: AxisExtents; } | undefined; }" ], "path": "src/plugins/visualizations/public/vis_types/types.ts", "deprecated": false @@ -4308,6 +4316,14 @@ "section": "def-common.VisParams", "text": "VisParams" }, + " | undefined, timeRange?: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, " | undefined) => Promise<", { "pluginId": "visualizations", @@ -4341,6 +4357,27 @@ "path": "src/plugins/visualizations/public/vis_types/types.ts", "deprecated": false, "isRequired": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisTypeDefinition.navigateToLens.$2", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "src/plugins/visualizations/public/vis_types/types.ts", + "deprecated": false, + "isRequired": false } ], "returnComment": [] @@ -5139,10 +5176,23 @@ }, { "parentPluginId": "visualizations", - "id": "def-public.VisualizeEditorLayersContext.timeFieldName", + "id": "def-public.VisualizeEditorLayersContext.xFieldName", + "type": "string", + "tags": [], + "label": "xFieldName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/visualizations/public/vis_types/types.ts", + "deprecated": false + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizeEditorLayersContext.xMode", "type": "string", "tags": [], - "label": "timeFieldName", + "label": "xMode", "description": [], "signature": [ "string | undefined" diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 1a28d8bd40a47..c2caf3af66c98 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2022-08-22 +date: 2022-08-23 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 414 | 12 | 386 | 15 | +| 416 | 12 | 388 | 15 | ## Client From b1059317bcc717d8059625d34b3ae8173a0ca015 Mon Sep 17 00:00:00 2001 From: Miriam <31922082+MiriamAparicio@users.noreply.github.com> Date: Tue, 23 Aug 2022 08:53:37 +0100 Subject: [PATCH 05/41] Hide infrastructure tab for services running in client (#139192) --- .../apm_service_template/index.test.tsx | 40 ++++++++++++++++++- .../templates/apm_service_template/index.tsx | 16 ++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.test.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.test.tsx index 763d4cf0717a1..c8ab3acd1a0af 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.test.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.test.tsx @@ -4,7 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { isMetricsTabHidden, isMetricsJVMsTabHidden } from '.'; +import { + isMetricsTabHidden, + isMetricsJVMsTabHidden, + isInfraTabHidden, +} from '.'; describe('APM service template', () => { describe('isMetricsTabHidden', () => { @@ -71,4 +75,38 @@ describe('APM service template', () => { }); }); }); + describe('isInfraTabHidden', () => { + describe('hides infra tab', () => { + [ + { agentName: undefined }, + { agentName: 'js-base' }, + { agentName: 'rum-js' }, + { agentName: 'opentelemetry/webjs' }, + { agentName: 'ios/swift' }, + { runtimeName: 'aws_lambda' }, + ].map((input) => { + it(`when input ${JSON.stringify(input)}`, () => { + expect(isInfraTabHidden(input)).toBeTruthy(); + }); + }); + }); + describe('shows infra tab', () => { + [ + { agentName: 'ruby', runtimeName: 'ruby' }, + { agentName: 'ruby', runtimeName: 'jruby' }, + { agentName: 'ruby' }, + { agentName: 'dotnet' }, + { agentName: 'go' }, + { agentName: 'nodejs' }, + { agentName: 'php' }, + { agentName: 'python' }, + { agentName: 'java' }, + { agentName: 'opentelemetry/java' }, + ].map((input) => { + it(`when input ${JSON.stringify(input)}`, () => { + expect(isInfraTabHidden(input)).toBeFalsy(); + }); + }); + }); + }); }); diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index c6c4c405d11af..2abfdba6f4124 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -167,6 +167,21 @@ export function isMetricsJVMsTabHidden({ ); } +export function isInfraTabHidden({ + agentName, + runtimeName, +}: { + agentName?: string; + runtimeName?: string; +}) { + return ( + !agentName || + isRumAgentName(agentName) || + isMobileAgentName(agentName) || + isServerlessAgent(runtimeName) + ); +} + function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { const { agentName, runtimeName } = useApmServiceContext(); const { config, core, plugins } = useApmPluginContext(); @@ -266,6 +281,7 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { label: i18n.translate('xpack.apm.home.infraTabLabel', { defaultMessage: 'Infrastructure', }), + hidden: isInfraTabHidden({ agentName, runtimeName }), }, { key: 'service-map', From 3605607ff9fe8119e5f97fa6a3e489083c546867 Mon Sep 17 00:00:00 2001 From: Ashokaditya <1849116+ashokaditya@users.noreply.github.com> Date: Tue, 23 Aug 2022 09:57:16 +0200 Subject: [PATCH 06/41] [Security Solution][Endpoint][Response Actions] Action type filter for action log (#138982) * Add action type filter fixes elastic/security-team/issues/4723 * normalize action lables in the filter fixes elastic/security-team/issues/4723 * Update prop type (single line shift) Doing this in a new commit so that the actual delta for working filter is not muddled because of changes here due to line shift fixes elastic/security-team/issues/4723 * move super refresh button to the end of the row fixes elastic/security-team/issues/4723 * Add a clear all button to filters fixes elastic/security-team/issues/4723 * update search placeholder text fixes elastic/security-team/issues/4723 * refactor clear all button fixes elastic/security-team/issues/4723 * tests fixes elastic/security-team/issues/4723 * review changes fixes elastic/security-team/issues/472 * update test ids review change --- .../endpoint_responder/action_log_button.tsx | 4 +- ....tsx => actions_log_date_range_picker.tsx} | 22 +- .../components/actions_log_filter.tsx | 103 ++++ .../components/actions_log_filter_popover.tsx | 79 +++ .../components/actions_log_filters.tsx | 83 +++ .../components/clear_all_button.tsx | 38 ++ .../components/hooks.tsx | 33 +- .../response_actions_list.tsx | 547 ----------------- ...test.tsx => response_actions_log.test.tsx} | 53 +- .../response_actions_log.tsx | 556 ++++++++++++++++++ .../translations.tsx | 18 + .../view/details/endpoint_details.tsx | 4 +- .../view/response_actions_list_page.tsx | 4 +- 13 files changed, 964 insertions(+), 580 deletions(-) rename x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/{action_list_date_range_picker.tsx => actions_log_date_range_picker.tsx} (79%) create mode 100644 x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter.tsx create mode 100644 x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter_popover.tsx create mode 100644 x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filters.tsx create mode 100644 x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/clear_all_button.tsx delete mode 100644 x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_list.tsx rename x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/{response_actions_list.test.tsx => response_actions_log.test.tsx} (88%) create mode 100644 x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_log.tsx diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx index bdfd987af131b..85a5f2655dd68 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/action_log_button.tsx @@ -9,7 +9,7 @@ import React, { memo, useCallback, useState } from 'react'; import { EuiButton, EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { EndpointResponderExtensionComponentProps } from './types'; -import { ResponseActionsList } from '../endpoint_response_actions_list/response_actions_list'; +import { ResponseActionsLog } from '../endpoint_response_actions_list/response_actions_log'; import { UX_MESSAGES } from '../endpoint_response_actions_list/translations'; export const ActionLogButton = memo((props) => { @@ -46,7 +46,7 @@ export const ActionLogButton = memo((p - + )} diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_list_date_range_picker.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_date_range_picker.tsx similarity index 79% rename from x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_list_date_range_picker.tsx rename to x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_date_range_picker.tsx index cf453e2070705..015fd3a501621 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/action_list_date_range_picker.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_date_range_picker.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import React, { useCallback, memo, useState } from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiSuperDatePicker, EuiSuperUpdateButton } from '@elastic/eui'; +import React, { memo, useState } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSuperDatePicker } from '@elastic/eui'; import type { IDataPluginServices } from '@kbn/data-plugin/public'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import type { EuiSuperDatePickerRecentRange } from '@elastic/eui'; @@ -16,7 +16,7 @@ import type { OnRefreshChangeProps, } from '@elastic/eui/src/components/date_picker/types'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; -import type { useGetEndpointActionList } from '../../../hooks'; + import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; export interface DateRangePickerValues { @@ -33,21 +33,19 @@ const DatePickerWrapper = euiStyled.div` padding-bottom: ${(props) => `${props.theme.eui.euiCodeBlockPaddingModifiers.paddingLarge}`}; `; -export const ActionListDateRangePicker = memo( +export const ActionLogDateRangePicker = memo( ({ dateRangePickerState, isDataLoading, onRefresh, onRefreshChange, onTimeChange, - onClick, }: { dateRangePickerState: DateRangePickerValues; isDataLoading: boolean; onRefresh: () => void; onRefreshChange: (evt: OnRefreshChangeProps) => void; onTimeChange: ({ start, end }: DurationRange) => void; - onClick: ReturnType['refetch']; }) => { const getTestId = useTestIdGenerator('response-actions-list'); const kibana = useKibana(); @@ -65,7 +63,6 @@ export const ActionListDateRangePicker = memo( }) ?? [] ); }); - const onClickCallback = useCallback(() => onClick(), [onClick]); return ( @@ -88,19 +85,10 @@ export const ActionListDateRangePicker = memo( width="auto" /> - - - ); } ); -ActionListDateRangePicker.displayName = 'ActionListDateRangePicker'; +ActionLogDateRangePicker.displayName = 'ActionLogDateRangePicker'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter.tsx new file mode 100644 index 0000000000000..1f89233a24ce7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter.tsx @@ -0,0 +1,103 @@ +/* + * 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, { memo, useCallback } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiSelectable, EuiPopoverTitle } from '@elastic/eui'; +import { ActionsLogFilterPopover } from './actions_log_filter_popover'; +import { type FilterItems, type FilterName, useActionsLogFilter } from './hooks'; +import { ClearAllButton } from './clear_all_button'; +import { UX_MESSAGES } from '../translations'; +import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; + +export const ActionsLogFilter = memo( + ({ + filterName, + onChangeCommandsFilter, + }: { + filterName: FilterName; + onChangeCommandsFilter: (selectedCommands: string[]) => void; + }) => { + const getTestId = useTestIdGenerator('response-actions-list'); + const { items, setItems, hasActiveFilters, numActiveFilters, numFilters } = + useActionsLogFilter(); + + const onChange = useCallback( + (newOptions: FilterItems) => { + setItems(newOptions.map((e) => e)); + + // update selected filter state + const selectedItems = newOptions.reduce((acc, curr) => { + if (curr.checked === 'on') { + acc.push(curr.key); + } + return acc; + }, []); + + // update query state + onChangeCommandsFilter(selectedItems); + }, + [onChangeCommandsFilter, setItems] + ); + + // clear all selected options + const onClearAll = useCallback(() => { + setItems( + items.map((e) => { + e.checked = undefined; + return e; + }) + ); + onChangeCommandsFilter([]); + }, [items, setItems, onChangeCommandsFilter]); + + return ( + + + {(list, search) => ( +
+ + {search} + + {list} + + + + + +
+ )} +
+
+ ); + } +); + +ActionsLogFilter.displayName = 'ActionsLogFilter'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter_popover.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter_popover.tsx new file mode 100644 index 0000000000000..9d2aada871707 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filter_popover.tsx @@ -0,0 +1,79 @@ +/* + * 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, { memo, useState, useCallback, useMemo } from 'react'; +import { EuiPopover, EuiFilterButton, useGeneratedHtmlId } from '@elastic/eui'; +import { FILTER_NAMES } from '../translations'; +import type { FilterName } from './hooks'; +import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; + +export const ActionsLogFilterPopover = memo( + ({ + children, + filterName, + hasActiveFilters, + numActiveFilters, + numFilters, + }: { + children: React.ReactNode; + filterName: FilterName; + hasActiveFilters: boolean; + numActiveFilters: number; + numFilters: number; + }) => { + const getTestId = useTestIdGenerator('response-actions-list'); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const onButtonClick = useCallback(() => { + setIsPopoverOpen(!isPopoverOpen); + }, [setIsPopoverOpen, isPopoverOpen]); + const closePopover = useCallback(() => { + setIsPopoverOpen(false); + }, [setIsPopoverOpen]); + const filterGroupPopoverId = useGeneratedHtmlId({ + prefix: 'filterGroupPopover', + }); + + const button = useMemo( + () => ( + + {FILTER_NAMES[filterName]} + + ), + [ + filterName, + getTestId, + hasActiveFilters, + isPopoverOpen, + numActiveFilters, + numFilters, + onButtonClick, + ] + ); + + return ( + + {children} + + ); + } +); + +ActionsLogFilterPopover.displayName = 'ActionsLogFilterPopover'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filters.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filters.tsx new file mode 100644 index 0000000000000..3f28d552276a2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_filters.tsx @@ -0,0 +1,83 @@ +/* + * 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, { memo, useCallback, useMemo } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiFilterGroup, EuiSuperUpdateButton } from '@elastic/eui'; +import type { + DurationRange, + OnRefreshChangeProps, +} from '@elastic/eui/src/components/date_picker/types'; +import type { useGetEndpointActionList } from '../../../hooks'; +import { + type DateRangePickerValues, + ActionLogDateRangePicker, +} from './actions_log_date_range_picker'; +import { ActionsLogFilter } from './actions_log_filter'; +import type { FilterName } from './hooks'; +import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; + +export const ActionsLogFilters = memo( + ({ + dateRangePickerState, + isDataLoading, + onClick, + onChangeCommandsFilter, + onRefresh, + onRefreshChange, + onTimeChange, + }: { + dateRangePickerState: DateRangePickerValues; + isDataLoading: boolean; + onChangeCommandsFilter: (selectedCommands: string[]) => void; + onRefresh: () => void; + onRefreshChange: (evt: OnRefreshChangeProps) => void; + onTimeChange: ({ start, end }: DurationRange) => void; + onClick: ReturnType['refetch']; + }) => { + const getTestId = useTestIdGenerator('response-actions-list'); + const filters = useMemo(() => { + // TODO: add more filter names here (users, hosts, statuses) + const filterNames: FilterName[] = ['actions']; + return filterNames.map((filterName) => ( + + )); + }, [onChangeCommandsFilter]); + + const onClickRefreshButton = useCallback(() => onClick(), [onClick]); + + return ( + + + + + + {filters} + + + + + + ); + } +); + +ActionsLogFilters.displayName = 'ActionsLogFilters'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/clear_all_button.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/clear_all_button.tsx new file mode 100644 index 0000000000000..96fd1dcc757aa --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/clear_all_button.tsx @@ -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 React, { memo } from 'react'; +import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { EuiButtonEmpty } from '@elastic/eui'; +import { UX_MESSAGES } from '../translations'; + +const StyledEuiButtonEmpty = euiStyled(EuiButtonEmpty).attrs({ + iconType: 'crossInACircleFilled', + color: 'danger', +})` + border-top: ${(props) => `${props.theme.eui.euiBorderThin}`}; + border-radius : 0; +`; +export const ClearAllButton = memo( + ({ + 'data-test-subj': dataTestSubj, + isDisabled, + onClick, + }: { + 'data-test-subj'?: string; + isDisabled: boolean; + onClick: () => void; + }) => { + return ( + + {UX_MESSAGES.filterClearAll} + + ); + } +); + +ClearAllButton.displayName = 'ClearAllButton'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx index 5ea37b444dad1..304e77c655751 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/hooks.tsx @@ -5,12 +5,14 @@ * 2.0. */ -import { useCallback, useState } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import type { DurationRange, OnRefreshChangeProps, } from '@elastic/eui/src/components/date_picker/types'; -import type { DateRangePickerValues } from './action_list_date_range_picker'; +import type { DateRangePickerValues } from './actions_log_date_range_picker'; +import { RESPONSE_ACTION_COMMANDS } from '../../../../../common/endpoint/types'; +import type { FILTER_NAMES } from '../translations'; const defaultDateRangeOptions = Object.freeze({ autoRefreshOptions: { @@ -85,3 +87,30 @@ export const useDateRangePicker = () => { return { dateRangePickerState, onRefreshChange, onTimeChange }; }; + +export type FilterItems = Array<{ + key: string; + label: string; + checked: 'on' | undefined; +}>; + +// TODO: add more filter names here +export type FilterName = keyof typeof FILTER_NAMES; +export const useActionsLogFilter = () => { + const [items, setItems] = useState( + RESPONSE_ACTION_COMMANDS.slice().map((filter) => ({ + key: filter, + label: filter === 'unisolate' ? 'release' : filter, + checked: undefined, + })) + ); + + const hasActiveFilters = useMemo(() => !!items.find((item) => item.checked === 'on'), [items]); + const numActiveFilters = useMemo( + () => items.filter((item) => item.checked === 'on').length, + [items] + ); + const numFilters = useMemo(() => items.filter((item) => item.checked !== 'on').length, [items]); + + return { items, setItems, hasActiveFilters, numActiveFilters, numFilters }; +}; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_list.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_list.tsx deleted file mode 100644 index 169128a373976..0000000000000 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_list.tsx +++ /dev/null @@ -1,547 +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 { - EuiAvatar, - EuiBadge, - EuiBasicTable, - EuiButtonIcon, - EuiDescriptionList, - EuiEmptyPrompt, - EuiFacetButton, - EuiFlexGroup, - EuiFlexItem, - EuiHorizontalRule, - EuiScreenReaderOnly, - EuiI18nNumber, - EuiText, - EuiCodeBlock, - EuiToolTip, - RIGHT_ALIGNMENT, -} from '@elastic/eui'; -import { euiStyled, css } from '@kbn/kibana-react-plugin/common'; - -import type { HorizontalAlignment, CriteriaWithPagination } from '@elastic/eui'; -import React, { memo, useCallback, useMemo, useState } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { getEmptyValue } from '../../../common/components/empty_value'; -import { FormattedDate } from '../../../common/components/formatted_date'; -import type { ActionDetails } from '../../../../common/endpoint/types'; -import type { EndpointActionListRequestQuery } from '../../../../common/endpoint/schema/actions'; -import { ManagementEmptyStateWrapper } from '../management_empty_state_wrapper'; -import { useGetEndpointActionList } from '../../hooks'; -import { OUTPUT_MESSAGES, TABLE_COLUMN_NAMES, UX_MESSAGES } from './translations'; -import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../common/constants'; -import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; -import { ActionListDateRangePicker } from './components/action_list_date_range_picker'; -import { useDateRangePicker } from './components/hooks'; - -const emptyValue = getEmptyValue(); - -const getCommand = ( - command: ActionDetails['command'] -): Exclude | 'release' => - command === 'unisolate' ? 'release' : command; - -// Truncated usernames -const StyledFacetButton = euiStyled(EuiFacetButton)` - .euiText { - margin-top: 0.38rem; - overflow-y: visible !important; - } -`; - -const customDescriptionListCss = css` - &.euiDescriptionList { - > .euiDescriptionList__title { - color: ${(props) => props.theme.eui.euiColorDarkShade}; - font-size: ${(props) => props.theme.eui.euiFontSizeXS}; - margin-top: ${(props) => props.theme.eui.euiSizeS}; - } - - > .euiDescriptionList__description { - font-weight: ${(props) => props.theme.eui.euiFontWeightSemiBold}; - margin-top: ${(props) => props.theme.eui.euiSizeS}; - } - } -`; - -const StyledDescriptionList = euiStyled(EuiDescriptionList).attrs({ - compressed: true, - type: 'column', -})` - ${customDescriptionListCss} -`; - -// output section styles -const topSpacingCss = css` - ${(props) => `${props.theme.eui.euiCodeBlockPaddingModifiers.paddingMedium} 0`} -`; -const dashedBorderCss = css` - ${(props) => `1px dashed ${props.theme.eui.euiColorDisabled}`}; -`; -const StyledDescriptionListOutput = euiStyled(EuiDescriptionList).attrs({ compressed: true })` - ${customDescriptionListCss} - dd { - margin: ${topSpacingCss}; - padding: ${topSpacingCss}; - border-top: ${dashedBorderCss}; - border-bottom: ${dashedBorderCss}; - } -`; - -// code block styles -const StyledEuiCodeBlock = euiStyled(EuiCodeBlock).attrs({ - transparentBackground: true, - paddingSize: 'none', -})` - code { - color: ${(props) => props.theme.eui.euiColorDarkShade} !important; - } -`; - -export const ResponseActionsList = memo< - Pick ->(({ agentIds, commands, userIds }) => { - const getTestId = useTestIdGenerator('response-actions-list'); - const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<{ - [k: ActionDetails['id']]: React.ReactNode; - }>({}); - - const [queryParams, setQueryParams] = useState({ - page: 1, - pageSize: 10, - agentIds, - commands, - userIds, - }); - - // date range picker state and handlers - const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker(); - - // initial fetch of list data - const { - error, - data: actionList, - isFetching, - isFetched, - refetch: reFetchEndpointActionList, - } = useGetEndpointActionList({ - ...queryParams, - startDate: dateRangePickerState.startDate, - endDate: dateRangePickerState.endDate, - }); - - // handle auto refresh data - const onRefresh = useCallback(() => { - if (dateRangePickerState.autoRefreshOptions.enabled) { - reFetchEndpointActionList(); - } - }, [dateRangePickerState.autoRefreshOptions.enabled, reFetchEndpointActionList]); - - // total actions - const totalItemCount = useMemo(() => actionList?.total ?? 0, [actionList]); - - // expanded tray contents - const toggleDetails = useCallback( - (item: ActionDetails) => { - const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap }; - if (itemIdToExpandedRowMapValues[item.id]) { - delete itemIdToExpandedRowMapValues[item.id]; - } else { - const { - startedAt, - completedAt, - isCompleted, - wasSuccessful, - isExpired, - command: _command, - parameters, - } = item; - - const parametersList = parameters - ? Object.entries(parameters).map(([key, value]) => { - return `${key}:${value}`; - }) - : undefined; - - const command = getCommand(_command); - const dataList = [ - { - title: OUTPUT_MESSAGES.expandSection.placedAt, - description: `${startedAt}`, - }, - { - title: OUTPUT_MESSAGES.expandSection.startedAt, - description: `${startedAt}`, - }, - { - title: OUTPUT_MESSAGES.expandSection.completedAt, - description: `${completedAt ?? emptyValue}`, - }, - { - title: OUTPUT_MESSAGES.expandSection.input, - description: `${command}`, - }, - { - title: OUTPUT_MESSAGES.expandSection.parameters, - description: parametersList ? parametersList : emptyValue, - }, - ].map(({ title, description }) => { - return { - title: {title}, - description: {description}, - }; - }); - - const outputList = [ - { - title: ( - {`${OUTPUT_MESSAGES.expandSection.output}:`} - ), - description: ( - // codeblock for output - - {isExpired - ? OUTPUT_MESSAGES.hasExpired(command) - : isCompleted - ? wasSuccessful - ? OUTPUT_MESSAGES.wasSuccessful(command) - : OUTPUT_MESSAGES.hasFailed(command) - : OUTPUT_MESSAGES.isPending(command)} - - ), - }, - ]; - - itemIdToExpandedRowMapValues[item.id] = ( - <> - - - - - - - - - - ); - } - setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); - }, - [getTestId, itemIdToExpandedRowMap] - ); - // memoized callback for toggleDetails - const onClickCallback = useCallback( - (data: ActionDetails) => () => toggleDetails(data), - [toggleDetails] - ); - - // table column - const responseActionListColumns = useMemo(() => { - const hideHostColumn = typeof agentIds === 'string'; - - const columns = [ - { - field: 'startedAt', - name: TABLE_COLUMN_NAMES.time, - width: hideHostColumn ? '21%' : '15%', - truncateText: true, - render: (startedAt: ActionDetails['startedAt']) => { - return ( - - ); - }, - }, - { - field: 'command', - name: TABLE_COLUMN_NAMES.command, - width: hideHostColumn ? '21%' : '10%', - truncateText: true, - render: (_command: ActionDetails['command']) => { - const command = getCommand(_command); - return ( - - - - ); - }, - }, - { - field: 'createdBy', - name: TABLE_COLUMN_NAMES.user, - width: hideHostColumn ? '21%' : '14%', - truncateText: true, - render: (userId: ActionDetails['createdBy']) => { - return ( - - } - > - - - {userId} - - - - ); - }, - }, - // conditional hostname column - { - field: 'agents', - name: TABLE_COLUMN_NAMES.host, - width: '20%', - truncateText: true, - render: (agents: ActionDetails['agents']) => { - // TODO: compute host names later with hostMetadata? (using agent Ids for now) - const hostname = agents?.[0] ?? ''; - return ( - - - {hostname} - - - ); - }, - }, - { - field: 'comment', - name: TABLE_COLUMN_NAMES.comments, - width: hideHostColumn ? '21%' : '30%', - truncateText: true, - render: (comment: ActionDetails['comment']) => { - return ( - - - {comment ?? emptyValue} - - - ); - }, - }, - { - field: 'isCompleted', - name: TABLE_COLUMN_NAMES.status, - width: hideHostColumn ? '15%' : '10%', - render: (isCompleted: ActionDetails['isCompleted'], data: ActionDetails) => { - const status = data.isExpired - ? UX_MESSAGES.badge.failed - : isCompleted - ? data.wasSuccessful - ? UX_MESSAGES.badge.completed - : UX_MESSAGES.badge.failed - : UX_MESSAGES.badge.pending; - - return ( - - - - - - ); - }, - }, - { - field: '', - align: RIGHT_ALIGNMENT as HorizontalAlignment, - width: '40px', - isExpander: true, - name: ( - - {UX_MESSAGES.screenReaderExpand} - - ), - render: (data: ActionDetails) => { - return ( - - ); - }, - }, - ]; - // filter out the host column - if (hideHostColumn) { - return columns.filter((column) => column.field !== 'agents'); - } - return columns; - }, [agentIds, getTestId, itemIdToExpandedRowMap, onClickCallback]); - - // table pagination - const tablePagination = useMemo(() => { - return { - // this controls the table UI page - // to match 0-based table paging - pageIndex: (queryParams.page || 1) - 1, - pageSize: queryParams.pageSize || 10, - totalItemCount, - pageSizeOptions: MANAGEMENT_PAGE_SIZE_OPTIONS as number[], - }; - }, [queryParams, totalItemCount]); - - // handle onChange - const handleTableOnChange = useCallback( - ({ page: _page }: CriteriaWithPagination) => { - // table paging is 0 based - const { index, size } = _page; - setQueryParams((prevState) => ({ - ...prevState, - // adjust the page to conform to - // 1-based API page - page: index + 1, - pageSize: size, - })); - reFetchEndpointActionList(); - }, - [reFetchEndpointActionList, setQueryParams] - ); - - // compute record ranges - const pagedResultsCount = useMemo(() => { - const page = queryParams.page ?? 1; - const perPage = queryParams?.pageSize ?? 10; - - const totalPages = Math.ceil(totalItemCount / perPage); - const fromCount = perPage * page - perPage + 1; - const toCount = - page === totalPages || totalPages === 1 ? totalItemCount : fromCount + perPage - 1; - return { fromCount, toCount }; - }, [queryParams.page, queryParams.pageSize, totalItemCount]); - - // create range label to display - const recordRangeLabel = useMemo( - () => ( - - - - {'-'} - - - ), - total: , - recordsLabel: {UX_MESSAGES.recordsLabel(totalItemCount)}, - }} - /> - - ), - [getTestId, pagedResultsCount.fromCount, pagedResultsCount.toCount, totalItemCount] - ); - - return ( - <> - - {isFetched && !totalItemCount ? ( - - - - - - } - body={ -

- -

- } - data-test-subj="responseActions-empty" - /> -
-
- ) : ( - <> - {recordRangeLabel} - - - - )} - - ); -}); - -ResponseActionsList.displayName = 'ResponseActionsList'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_list.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_log.test.tsx similarity index 88% rename from x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_list.test.tsx rename to x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_log.test.tsx index 57cbfff15790b..a731bf784f2e9 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_list.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_log.test.tsx @@ -12,7 +12,7 @@ import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import type { AppContextTestRender } from '../../../common/mock/endpoint'; import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; -import { ResponseActionsList } from './response_actions_list'; +import { ResponseActionsLog } from './response_actions_log'; import type { ActionDetails, ActionListApiResponse } from '../../../../common/endpoint/types'; import { MANAGEMENT_PATH } from '../../../../common/constants'; import { EndpointActionGenerator } from '../../../../common/endpoint/data_generators/endpoint_action_generator'; @@ -106,11 +106,11 @@ jest.mock('@kbn/kibana-react-plugin/public', () => { }; }); -describe('Response Actions List', () => { +describe('Response Actions Log', () => { const testPrefix = 'response-actions-list'; let render: ( - props?: React.ComponentProps + props?: React.ComponentProps ) => ReturnType; let renderResult: ReturnType; let history: AppContextTestRender['history']; @@ -127,8 +127,8 @@ describe('Response Actions List', () => { beforeEach(async () => { mockedContext = createAppRootMockRenderer(); ({ history } = mockedContext); - render = (props?: React.ComponentProps) => - (renderResult = mockedContext.render()); + render = (props?: React.ComponentProps) => + (renderResult = mockedContext.render()); reactTestingLibrary.act(() => { history.push(`${MANAGEMENT_PATH}/response_actions`); }); @@ -152,6 +152,11 @@ describe('Response Actions List', () => { expect(renderResult.getByTestId(`${testPrefix}-super-date-picker`)).toBeTruthy(); }); + it('should show actions filter', () => { + render(); + expect(renderResult.getByTestId(`${testPrefix}-actions-filter-popoverButton`)).toBeTruthy(); + }); + it('should show empty state when there is no data', async () => { mockUseGetEndpointActionList = { ...baseMockedActionList, @@ -282,9 +287,7 @@ describe('Response Actions List', () => { it('should refresh data when super date picker refresh button is clicked', async () => { render(); - const superRefreshButton = renderResult.getByTestId( - `${testPrefix}-super-date-picker-refresh-button` - ); + const superRefreshButton = renderResult.getByTestId(`${testPrefix}-super-refresh-button`); userEvent.click(superRefreshButton); expect(refetchFunction).toHaveBeenCalledTimes(1); }); @@ -414,6 +417,40 @@ describe('Response Actions List', () => { ).toEqual(['Time', 'Command', 'User', 'Host', 'Comments', 'Status']); }); }); + + describe('Actions filter', () => { + const filterPrefix = '-actions-filter'; + + it('should have a search bar', () => { + render(); + userEvent.click(renderResult.getByTestId(`${testPrefix}${filterPrefix}-popoverButton`)); + const searchBar = renderResult.getByTestId(`${testPrefix}${filterPrefix}-search`); + expect(searchBar).toBeTruthy(); + expect(searchBar.querySelector('input')?.getAttribute('placeholder')).toEqual( + 'Search actions' + ); + }); + + it('should show a list of actions when opened', () => { + render(); + userEvent.click(renderResult.getByTestId(`${testPrefix}${filterPrefix}-popoverButton`)); + const filterList = renderResult.getByTestId(`${testPrefix}${filterPrefix}-popoverList`); + expect(filterList).toBeTruthy(); + expect(filterList.querySelectorAll('ul>li').length).toEqual(5); + expect( + Array.from(filterList.querySelectorAll('ul>li')).map((option) => option.textContent) + ).toEqual(['isolate', 'release', 'kill-process', 'suspend-process', 'running-processes']); + }); + + it('should have `clear all` button `disabled` when no selected values', () => { + render(); + userEvent.click(renderResult.getByTestId(`${testPrefix}${filterPrefix}-popoverButton`)); + const clearAllButton = renderResult.getByTestId( + `${testPrefix}${filterPrefix}-clearAllButton` + ); + expect(clearAllButton.hasAttribute('disabled')).toBeTruthy(); + }); + }); }); // mock API response diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_log.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_log.tsx new file mode 100644 index 0000000000000..7afb5ce81f4cf --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/response_actions_log.tsx @@ -0,0 +1,556 @@ +/* + * 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 { + EuiAvatar, + EuiBadge, + EuiBasicTable, + EuiButtonIcon, + EuiDescriptionList, + EuiEmptyPrompt, + EuiFacetButton, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiScreenReaderOnly, + EuiI18nNumber, + EuiText, + EuiCodeBlock, + EuiToolTip, + RIGHT_ALIGNMENT, +} from '@elastic/eui'; +import { euiStyled, css } from '@kbn/kibana-react-plugin/common'; + +import type { HorizontalAlignment, CriteriaWithPagination } from '@elastic/eui'; +import React, { memo, useCallback, useMemo, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { getEmptyValue } from '../../../common/components/empty_value'; +import { FormattedDate } from '../../../common/components/formatted_date'; +import type { ActionDetails } from '../../../../common/endpoint/types'; +import type { EndpointActionListRequestQuery } from '../../../../common/endpoint/schema/actions'; +import { ManagementEmptyStateWrapper } from '../management_empty_state_wrapper'; +import { useGetEndpointActionList } from '../../hooks'; +import { OUTPUT_MESSAGES, TABLE_COLUMN_NAMES, UX_MESSAGES } from './translations'; +import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../common/constants'; +import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; +import { ActionsLogFilters } from './components/actions_log_filters'; +import { useDateRangePicker } from './components/hooks'; + +const emptyValue = getEmptyValue(); + +const getCommand = ( + command: ActionDetails['command'] +): Exclude | 'release' => + command === 'unisolate' ? 'release' : command; + +// Truncated usernames +const StyledFacetButton = euiStyled(EuiFacetButton)` + .euiText { + margin-top: 0.38rem; + overflow-y: visible !important; + } +`; + +const customDescriptionListCss = css` + &.euiDescriptionList { + > .euiDescriptionList__title { + color: ${(props) => props.theme.eui.euiColorDarkShade}; + font-size: ${(props) => props.theme.eui.euiFontSizeXS}; + margin-top: ${(props) => props.theme.eui.euiSizeS}; + } + + > .euiDescriptionList__description { + font-weight: ${(props) => props.theme.eui.euiFontWeightSemiBold}; + margin-top: ${(props) => props.theme.eui.euiSizeS}; + } + } +`; + +const StyledDescriptionList = euiStyled(EuiDescriptionList).attrs({ + compressed: true, + type: 'column', +})` + ${customDescriptionListCss} +`; + +// output section styles +const topSpacingCss = css` + ${(props) => `${props.theme.eui.euiCodeBlockPaddingModifiers.paddingMedium} 0`} +`; +const dashedBorderCss = css` + ${(props) => `1px dashed ${props.theme.eui.euiColorDisabled}`}; +`; +const StyledDescriptionListOutput = euiStyled(EuiDescriptionList).attrs({ compressed: true })` + ${customDescriptionListCss} + dd { + margin: ${topSpacingCss}; + padding: ${topSpacingCss}; + border-top: ${dashedBorderCss}; + border-bottom: ${dashedBorderCss}; + } +`; + +// code block styles +const StyledEuiCodeBlock = euiStyled(EuiCodeBlock).attrs({ + transparentBackground: true, + paddingSize: 'none', +})` + code { + color: ${(props) => props.theme.eui.euiColorDarkShade} !important; + } +`; + +export const ResponseActionsLog = memo>( + ({ agentIds }) => { + const getTestId = useTestIdGenerator('response-actions-list'); + const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState<{ + [k: ActionDetails['id']]: React.ReactNode; + }>({}); + + const [queryParams, setQueryParams] = useState({ + page: 1, + pageSize: 10, + agentIds, + commands: [], + userIds: [], + }); + + // date range picker state and handlers + const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker(); + + // initial fetch of list data + const { + error, + data: actionList, + isFetching, + isFetched, + refetch: reFetchEndpointActionList, + } = useGetEndpointActionList({ + ...queryParams, + startDate: dateRangePickerState.startDate, + endDate: dateRangePickerState.endDate, + }); + + // handle auto refresh data + const onRefresh = useCallback(() => { + if (dateRangePickerState.autoRefreshOptions.enabled) { + reFetchEndpointActionList(); + } + }, [dateRangePickerState.autoRefreshOptions.enabled, reFetchEndpointActionList]); + + // handle on change actions filter + const onChangeCommandsFilter = useCallback( + (selectedCommands: string[]) => { + setQueryParams((prevState) => ({ ...prevState, commands: selectedCommands })); + }, + [setQueryParams] + ); + + // total actions + const totalItemCount = useMemo(() => actionList?.total ?? 0, [actionList]); + + // expanded tray contents + const toggleDetails = useCallback( + (item: ActionDetails) => { + const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap }; + if (itemIdToExpandedRowMapValues[item.id]) { + delete itemIdToExpandedRowMapValues[item.id]; + } else { + const { + startedAt, + completedAt, + isCompleted, + wasSuccessful, + isExpired, + command: _command, + parameters, + } = item; + + const parametersList = parameters + ? Object.entries(parameters).map(([key, value]) => { + return `${key}:${value}`; + }) + : undefined; + + const command = getCommand(_command); + const dataList = [ + { + title: OUTPUT_MESSAGES.expandSection.placedAt, + description: `${startedAt}`, + }, + { + title: OUTPUT_MESSAGES.expandSection.startedAt, + description: `${startedAt}`, + }, + { + title: OUTPUT_MESSAGES.expandSection.completedAt, + description: `${completedAt ?? emptyValue}`, + }, + { + title: OUTPUT_MESSAGES.expandSection.input, + description: `${command}`, + }, + { + title: OUTPUT_MESSAGES.expandSection.parameters, + description: parametersList ? parametersList : emptyValue, + }, + ].map(({ title, description }) => { + return { + title: {title}, + description: {description}, + }; + }); + + const outputList = [ + { + title: ( + {`${OUTPUT_MESSAGES.expandSection.output}:`} + ), + description: ( + // codeblock for output + + {isExpired + ? OUTPUT_MESSAGES.hasExpired(command) + : isCompleted + ? wasSuccessful + ? OUTPUT_MESSAGES.wasSuccessful(command) + : OUTPUT_MESSAGES.hasFailed(command) + : OUTPUT_MESSAGES.isPending(command)} + + ), + }, + ]; + + itemIdToExpandedRowMapValues[item.id] = ( + <> + + + + + + + + + + ); + } + setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); + }, + [getTestId, itemIdToExpandedRowMap] + ); + // memoized callback for toggleDetails + const onClickCallback = useCallback( + (data: ActionDetails) => () => toggleDetails(data), + [toggleDetails] + ); + + // table column + const responseActionListColumns = useMemo(() => { + const hideHostColumn = typeof agentIds === 'string'; + + const columns = [ + { + field: 'startedAt', + name: TABLE_COLUMN_NAMES.time, + width: hideHostColumn ? '21%' : '15%', + truncateText: true, + render: (startedAt: ActionDetails['startedAt']) => { + return ( + + ); + }, + }, + { + field: 'command', + name: TABLE_COLUMN_NAMES.command, + width: hideHostColumn ? '21%' : '10%', + truncateText: true, + render: (_command: ActionDetails['command']) => { + const command = getCommand(_command); + return ( + + + + ); + }, + }, + { + field: 'createdBy', + name: TABLE_COLUMN_NAMES.user, + width: hideHostColumn ? '21%' : '14%', + truncateText: true, + render: (userId: ActionDetails['createdBy']) => { + return ( + + } + > + + + {userId} + + + + ); + }, + }, + // conditional hostname column + { + field: 'agents', + name: TABLE_COLUMN_NAMES.host, + width: '20%', + truncateText: true, + render: (agents: ActionDetails['agents']) => { + // TODO: compute host names later with hostMetadata? (using agent Ids for now) + const hostname = agents?.[0] ?? ''; + return ( + + + {hostname} + + + ); + }, + }, + { + field: 'comment', + name: TABLE_COLUMN_NAMES.comments, + width: hideHostColumn ? '21%' : '30%', + truncateText: true, + render: (comment: ActionDetails['comment']) => { + return ( + + + {comment ?? emptyValue} + + + ); + }, + }, + { + field: 'isCompleted', + name: TABLE_COLUMN_NAMES.status, + width: hideHostColumn ? '15%' : '10%', + render: (isCompleted: ActionDetails['isCompleted'], data: ActionDetails) => { + const status = data.isExpired + ? UX_MESSAGES.badge.failed + : isCompleted + ? data.wasSuccessful + ? UX_MESSAGES.badge.completed + : UX_MESSAGES.badge.failed + : UX_MESSAGES.badge.pending; + + return ( + + + + + + ); + }, + }, + { + field: '', + align: RIGHT_ALIGNMENT as HorizontalAlignment, + width: '40px', + isExpander: true, + name: ( + + {UX_MESSAGES.screenReaderExpand} + + ), + render: (data: ActionDetails) => { + return ( + + ); + }, + }, + ]; + // filter out the host column + if (hideHostColumn) { + return columns.filter((column) => column.field !== 'agents'); + } + return columns; + }, [agentIds, getTestId, itemIdToExpandedRowMap, onClickCallback]); + + // table pagination + const tablePagination = useMemo(() => { + return { + // this controls the table UI page + // to match 0-based table paging + pageIndex: (queryParams.page || 1) - 1, + pageSize: queryParams.pageSize || 10, + totalItemCount, + pageSizeOptions: MANAGEMENT_PAGE_SIZE_OPTIONS as number[], + }; + }, [queryParams, totalItemCount]); + + // handle onChange + const handleTableOnChange = useCallback( + ({ page: _page }: CriteriaWithPagination) => { + // table paging is 0 based + const { index, size } = _page; + setQueryParams((prevState) => ({ + ...prevState, + // adjust the page to conform to + // 1-based API page + page: index + 1, + pageSize: size, + })); + reFetchEndpointActionList(); + }, + [reFetchEndpointActionList, setQueryParams] + ); + + // compute record ranges + const pagedResultsCount = useMemo(() => { + const page = queryParams.page ?? 1; + const perPage = queryParams?.pageSize ?? 10; + + const totalPages = Math.ceil(totalItemCount / perPage); + const fromCount = perPage * page - perPage + 1; + const toCount = + page === totalPages || totalPages === 1 ? totalItemCount : fromCount + perPage - 1; + return { fromCount, toCount }; + }, [queryParams.page, queryParams.pageSize, totalItemCount]); + + // create range label to display + const recordRangeLabel = useMemo( + () => ( + + + + {'-'} + + + ), + total: , + recordsLabel: {UX_MESSAGES.recordsLabel(totalItemCount)}, + }} + /> + + ), + [getTestId, pagedResultsCount.fromCount, pagedResultsCount.toCount, totalItemCount] + ); + + return ( + <> + + {isFetched && !totalItemCount ? ( + + + + + + } + body={ +

+ +

+ } + data-test-subj="responseActions-empty" + /> +
+
+ ) : ( + <> + {recordRangeLabel} + + + + )} + + ); + } +); + +ResponseActionsLog.displayName = 'ResponseActionsLog'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx index 04255a9ceaf53..fe3d368e8aec7 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/translations.tsx @@ -101,6 +101,17 @@ export const UX_MESSAGES = Object.freeze({ fetchError: i18n.translate('xpack.securitySolution.responseActionsList.list.errorMessage', { defaultMessage: 'Error while retrieving response actions', }), + filterClearAll: i18n.translate( + 'xpack.securitySolution.responseActionsList.list.filter.clearAll', + { + defaultMessage: 'Clear all', + } + ), + filterSearchPlaceholder: (filterName: string) => + i18n.translate('xpack.securitySolution.responseActionsList.list.filter.searchPlaceholder', { + defaultMessage: 'Search {filterName}', + values: { filterName }, + }), badge: { completed: i18n.translate( 'xpack.securitySolution.responseActionsList.list.item.badge.completed', @@ -129,3 +140,10 @@ export const UX_MESSAGES = Object.freeze({ }, }), }); + +// TODO: Add more filter names here (hosts, statuses) etc +export const FILTER_NAMES = Object.freeze({ + actions: i18n.translate('xpack.securitySolution.responseActionsList.list.filter.actions', { + defaultMessage: 'Actions', + }), +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx index a8f343290677e..3a15b6b3873a5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx @@ -7,7 +7,7 @@ import { EuiFlyoutBody, EuiFlyoutFooter, EuiLoadingContent, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { memo, useCallback, useEffect, useMemo } from 'react'; -import { ResponseActionsList } from '../../../../components/endpoint_response_actions_list/response_actions_list'; +import { ResponseActionsLog } from '../../../../components/endpoint_response_actions_list/response_actions_log'; import { PolicyResponseWrapper } from '../../../../components/policy_response'; import type { HostMetadata } from '../../../../../../common/endpoint/types'; import { useToasts } from '../../../../../common/lib/kibana'; @@ -82,7 +82,7 @@ export const EndpointDetails = memo(() => { name: 'endpointActivityLog', selected_endpoint: id, }), - content: , + content: , }, ], [ContentLoadingMarkup, hostDetails, policyInfo, hostStatus, queryParams] diff --git a/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.tsx b/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.tsx index cb1c7d53e05a6..c72e69023af77 100644 --- a/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.tsx @@ -7,13 +7,13 @@ import React from 'react'; import { AdministrationListPage } from '../../../components/administration_list_page'; -import { ResponseActionsList } from '../../../components/endpoint_response_actions_list/response_actions_list'; +import { ResponseActionsLog } from '../../../components/endpoint_response_actions_list/response_actions_log'; import { UX_MESSAGES } from '../../../components/endpoint_response_actions_list/translations'; export const ResponseActionsListPage = () => { return ( - + ); }; From 47b69298a5ccbf1d064e64f72dfbc50baa4f8c78 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 23 Aug 2022 10:08:37 +0200 Subject: [PATCH 07/41] [UnifiedFieldList] Move Field Stats from Lens to UnifiedFieldList plugin (#136328) * [UnifiedFieldList] Bootstrap a new unifiedFieldList plugin * [UnifiedFieldList] Move backend API for field stats from Lens to UnifiedFieldList plugin * [CI] Auto-commit changed files from 'node scripts/build_plugin_list_docs' * [Discover] Address CI checks * [UnifiedFieldList] Move field stats UI from Lens to UnifiedFieldList plugin * [Discover] Integrate FieldStats into Discover field popover * [Discover] Show both views side to side * [Discover] Allow for some customization * [Discover] Allow for more customization * [UnifiedFieldList] Remove temporary code * [UnifiedFieldList] Extract styles * [UnifiedFieldList] Fix after merge * [UnifiedFieldList] Extend i18n * [UnifiedFieldList] Migrate stats API from server to public * [UnifiedFieldList] Update types * [UnifiedFieldList] Update Lens tests * [UnifiedFieldList] Update Lens tests * [UnifiedFieldList] Before merging * [UnifiedFieldList] After merging * [UnifiedFieldList] Refactor localization keys * [UnifiedFieldList] Update types * [UnifiedFieldList] Reintroduce server API for field stats and refactor integration tests * [UnifiedFieldList] Update limits * [UnifiedFieldList] Rename the component * [UnifiedFieldList] Improve types * [UnifiedFieldList] Add AbortController * [UnifiedFieldList] Render counts in PopoverFooter in Lens * [UnifiedFieldList] Hide new stats from Discover for now * [UnifiedFieldList] Fix tests * [UnifiedFieldList] Rename to loadFieldStats * [UnifiedFieldList] Rearrange utils * [UnifiedFieldList] Fix types * [UnifiedFieldList] Fix references * [UnifiedFieldList] Use emotion css * [UnifiedFieldList] Increase limits * [UnifiedFieldList] Add first tests * [UnifiedFieldList] Add more tests * [UnifiedFieldList] Refactor interface to accept services object * [UnifiedFieldList] Update types * [UnifiedFieldList] Add docs * [CI] Auto-commit changed files from 'node scripts/build_plugin_list_docs' * [UnifiedFieldList] Add missing references * [UnifiedFieldList] Tmp * [UnifiedFieldList] Revert changes from Discover for now * [Discover] Add again new translation keys * [UnifiedFieldList] Remove old translation keys * [UnifiedFieldList] Update tests * [UnifiedFieldList] Update data test subj prop * Update src/plugins/unified_field_list/public/services/field_stats.ts Co-authored-by: Davis McPhee * [UnifiedFieldList] Lazy load FieldStats component * [UnifiedFieldList] Lazy load loadFieldStats function * [UnifiedFieldList] Fix tests * [UnifiedFieldList] Remove newly added translations Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Davis McPhee --- .github/CODEOWNERS | 5 + .i18nrc.json | 3 +- docs/developer/plugin-list.asciidoc | 4 + packages/kbn-optimizer/limits.yml | 1 + .../components/sidebar/discover_field.tsx | 3 + src/plugins/unified_field_list/README.md | 21 + .../unified_field_list/common/constants.ts | 10 + .../unified_field_list/common/index.ts | 9 + .../unified_field_list/common/types/index.ts | 14 + .../unified_field_list/common/types/stats.ts | 5 +- .../common/utils/field_stats_utils.ts | 256 ++++---- src/plugins/unified_field_list/jest.config.js | 16 + src/plugins/unified_field_list/kibana.json | 15 + .../field_stats/field_stats.test.tsx | 543 ++++++++++++++++ .../components/field_stats/field_stats.tsx | 595 ++++++++++++++++++ .../public/components/field_stats/index.tsx | 22 + .../unified_field_list/public/index.ts | 26 + .../unified_field_list/public/plugin.ts | 25 + .../public/services/field_stats/index.tsx | 14 + .../services/field_stats/load_field_stats.ts | 98 +++ .../unified_field_list/public/types.ts | 13 + .../unified_field_list/server/index.ts | 24 + .../unified_field_list/server/plugin.ts | 41 ++ .../server/routes/field_stats.ts | 104 +++ .../unified_field_list/server/routes/index.ts | 15 + .../unified_field_list/server/types.ts | 22 + src/plugins/unified_field_list/tsconfig.json | 23 + test/api_integration/apis/index.ts | 1 + .../apis/unified_field_list}/field_stats.ts | 48 +- .../apis/unified_field_list/index.ts | 15 + tsconfig.base.json | 2 + x-pack/plugins/lens/common/index.ts | 1 - x-pack/plugins/lens/kibana.json | 3 +- .../lens/public/app_plugin/mounter.tsx | 1 + .../plugins/lens/public/app_plugin/types.ts | 2 + .../indexpattern_datasource/field_item.scss | 17 - .../field_item.test.tsx | 188 +++--- .../indexpattern_datasource/field_item.tsx | 532 +++------------- .../indexpattern_datasource/indexpattern.tsx | 41 +- .../operations/definitions/index.ts | 2 + .../definitions/terms/helpers.test.ts | 46 +- .../operations/definitions/terms/helpers.ts | 43 +- .../definitions/terms/terms.test.tsx | 48 +- .../operations/layer_helpers.test.ts | 18 +- .../operations/layer_helpers.ts | 6 +- .../lens/public/mocks/services_mock.tsx | 2 + x-pack/plugins/lens/server/routes/index.ts | 2 - x-pack/plugins/lens/tsconfig.json | 3 +- .../translations/translations/fr-FR.json | 11 - .../translations/translations/ja-JP.json | 11 - .../translations/translations/zh-CN.json | 11 - .../test/api_integration/apis/lens/index.ts | 1 - 52 files changed, 2143 insertions(+), 839 deletions(-) create mode 100755 src/plugins/unified_field_list/README.md create mode 100644 src/plugins/unified_field_list/common/constants.ts create mode 100755 src/plugins/unified_field_list/common/index.ts create mode 100755 src/plugins/unified_field_list/common/types/index.ts rename x-pack/plugins/lens/common/api.ts => src/plugins/unified_field_list/common/types/stats.ts (84%) rename x-pack/plugins/lens/server/routes/field_stats.ts => src/plugins/unified_field_list/common/utils/field_stats_utils.ts (52%) create mode 100644 src/plugins/unified_field_list/jest.config.js create mode 100755 src/plugins/unified_field_list/kibana.json create mode 100644 src/plugins/unified_field_list/public/components/field_stats/field_stats.test.tsx create mode 100755 src/plugins/unified_field_list/public/components/field_stats/field_stats.tsx create mode 100755 src/plugins/unified_field_list/public/components/field_stats/index.tsx create mode 100755 src/plugins/unified_field_list/public/index.ts create mode 100755 src/plugins/unified_field_list/public/plugin.ts create mode 100755 src/plugins/unified_field_list/public/services/field_stats/index.tsx create mode 100644 src/plugins/unified_field_list/public/services/field_stats/load_field_stats.ts create mode 100755 src/plugins/unified_field_list/public/types.ts create mode 100644 src/plugins/unified_field_list/server/index.ts create mode 100644 src/plugins/unified_field_list/server/plugin.ts create mode 100644 src/plugins/unified_field_list/server/routes/field_stats.ts create mode 100644 src/plugins/unified_field_list/server/routes/index.ts create mode 100644 src/plugins/unified_field_list/server/types.ts create mode 100644 src/plugins/unified_field_list/tsconfig.json rename {x-pack/test/api_integration/apis/lens => test/api_integration/apis/unified_field_list}/field_stats.ts (92%) create mode 100644 test/api_integration/apis/unified_field_list/index.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d1080cea722e2..e7f0933161b66 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,8 +13,10 @@ /src/plugins/saved_search/ @elastic/kibana-data-discovery /x-pack/plugins/discover_enhanced/ @elastic/kibana-data-discovery /test/functional/apps/discover/ @elastic/kibana-data-discovery +/test/api_integration/apis/unified_field_list/ @elastic/kibana-data-discovery /x-pack/plugins/graph/ @elastic/kibana-data-discovery /x-pack/test/functional/apps/graph @elastic/kibana-data-discovery +/src/plugins/unified_field_list/ @elastic/kibana-data-discovery # Vis Editors /x-pack/plugins/lens/ @elastic/kibana-vis-editors @@ -41,7 +43,10 @@ /src/plugins/url_forwarding/ @elastic/kibana-vis-editors /packages/kbn-tinymath/ @elastic/kibana-vis-editors /x-pack/test/functional/apps/lens @elastic/kibana-vis-editors +/x-pack/test/api_integration/apis/lens/ @elastic/kibana-vis-editors /test/functional/apps/visualize/ @elastic/kibana-vis-editors +/src/plugins/unified_field_list/ @elastic/kibana-vis-editors +/test/api_integration/apis/unified_field_list/ @elastic/kibana-vis-editors # Application Services /examples/bfetch_explorer/ @elastic/kibana-app-services diff --git a/.i18nrc.json b/.i18nrc.json index 28986568d5bf3..2a301de5e7edf 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -91,7 +91,8 @@ "visTypeVislib": "src/plugins/vis_types/vislib", "visTypeXy": "src/plugins/vis_types/xy", "visualizations": "src/plugins/visualizations", - "unifiedSearch": "src/plugins/unified_search" + "unifiedSearch": "src/plugins/unified_search", + "unifiedFieldList": "src/plugins/unified_field_list" }, "translations": [] } diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 00f0bc517f5a5..e4bda1d283444 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -299,6 +299,10 @@ In general this plugin provides: |Registers commercially licensed generic actions like per panel time range and contains some code that supports drilldown work. +|{kib-repo}blob/{branch}/src/plugins/unified_field_list/README.md[unifiedFieldList] +|This Kibana plugin contains components and services for field list UI (as in fields sidebar on Discover and Lens pages). + + |{kib-repo}blob/{branch}/src/plugins/unified_search/README.md[unifiedSearch] |Contains all the components of Kibana's unified search experience. Specifically: diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 6c95efdba7330..d41a5356af082 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -125,6 +125,7 @@ pageLoadAssetSize: cloudSecurityPosture: 19109 visTypeGauge: 24113 unifiedSearch: 71059 + unifiedFieldList: 65500 data: 454087 eventAnnotation: 19334 screenshotting: 22870 diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx index 6fbeca677bc63..743e0005ec756 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx @@ -397,6 +397,9 @@ function DiscoverFieldComponent({ const renderPopover = () => { const details = getDetails(field); + + // TODO: integrate + return ( <> {showFieldStats && ( diff --git a/src/plugins/unified_field_list/README.md b/src/plugins/unified_field_list/README.md new file mode 100755 index 0000000000000..657523aad9c1b --- /dev/null +++ b/src/plugins/unified_field_list/README.md @@ -0,0 +1,21 @@ +# unifiedFieldList + +This Kibana plugin contains components and services for field list UI (as in fields sidebar on Discover and Lens pages). + +--- + +## Components + +* `` - loads and renders stats (Top values, Histogram) for a data view field. + +## Public Services + +* `loadStats(...)` - returns the loaded field stats (can also work with Ad-hoc data views) + +## Server APIs + +* `/api/unified_field_list/field_stats` - returns the loaded field stats (except for Ad-hoc data views) + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment. diff --git a/src/plugins/unified_field_list/common/constants.ts b/src/plugins/unified_field_list/common/constants.ts new file mode 100644 index 0000000000000..ef8a01b2705ff --- /dev/null +++ b/src/plugins/unified_field_list/common/constants.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 const BASE_API_PATH = '/api/unified_field_list'; +export const FIELD_STATS_API_PATH = `${BASE_API_PATH}/field_stats`; diff --git a/src/plugins/unified_field_list/common/index.ts b/src/plugins/unified_field_list/common/index.ts new file mode 100755 index 0000000000000..747db7a56bbae --- /dev/null +++ b/src/plugins/unified_field_list/common/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 const PLUGIN_ID = 'unifiedFieldList'; diff --git a/src/plugins/unified_field_list/common/types/index.ts b/src/plugins/unified_field_list/common/types/index.ts new file mode 100755 index 0000000000000..78dbc548406c0 --- /dev/null +++ b/src/plugins/unified_field_list/common/types/index.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 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 { + FieldStatsResponse, + NumberStatsResult, + TopValuesResult, + BucketedAggregation, +} from './stats'; diff --git a/x-pack/plugins/lens/common/api.ts b/src/plugins/unified_field_list/common/types/stats.ts similarity index 84% rename from x-pack/plugins/lens/common/api.ts rename to src/plugins/unified_field_list/common/types/stats.ts index 026f540cdb67b..71d75db1aaaa3 100644 --- a/x-pack/plugins/lens/common/api.ts +++ b/src/plugins/unified_field_list/common/types/stats.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ export interface BucketedAggregation { diff --git a/x-pack/plugins/lens/server/routes/field_stats.ts b/src/plugins/unified_field_list/common/utils/field_stats_utils.ts similarity index 52% rename from x-pack/plugins/lens/server/routes/field_stats.ts rename to src/plugins/unified_field_list/common/utils/field_stats_utils.ts index 35a15ea44be67..9cf33961d76b6 100644 --- a/x-pack/plugins/lens/server/routes/field_stats.ts +++ b/src/plugins/unified_field_list/common/utils/field_stats_utils.ts @@ -1,149 +1,119 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ -import { errors } from '@elastic/elasticsearch'; + import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import DateMath from '@kbn/datemath'; -import { schema } from '@kbn/config-schema'; -import { CoreSetup } from '@kbn/core/server'; -import type { DataViewField } from '@kbn/data-views-plugin/common'; -import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; import { ESSearchResponse } from '@kbn/core/types/elasticsearch'; -import { FieldStatsResponse, BASE_API_URL } from '../../common'; -import { PluginStartContract } from '../plugin'; +import type { DataViewFieldBase } from '@kbn/es-query'; +import type { FieldStatsResponse } from '../types'; -const SHARD_SIZE = 5000; +export type SearchHandler = ( + aggs: Record +) => Promise>; -export async function initFieldsRoute(setup: CoreSetup) { - const router = setup.http.createRouter(); - router.post( - { - path: `${BASE_API_URL}/index_stats/{indexPatternId}/field`, - validate: { - params: schema.object({ - indexPatternId: schema.string(), - }), - body: schema.object( - { - dslQuery: schema.object({}, { unknowns: 'allow' }), - fromDate: schema.string(), - toDate: schema.string(), - fieldName: schema.string(), - size: schema.maybe(schema.number()), +const SHARD_SIZE = 5000; +const DEFAULT_TOP_VALUES_SIZE = 10; + +export function buildSearchParams({ + dataViewPattern, + timeFieldName, + fromDate, + toDate, + dslQuery, + runtimeMappings, + aggs, +}: { + dataViewPattern: string; + timeFieldName?: string; + fromDate: string; + toDate: string; + dslQuery: object; + runtimeMappings: estypes.MappingRuntimeFields; + aggs: Record; +}) { + const filter = timeFieldName + ? [ + { + range: { + [timeFieldName]: { + gte: fromDate, + lte: toDate, + }, }, - { unknowns: 'allow' } - ), - }, + }, + dslQuery, + ] + : [dslQuery]; + + const query = { + bool: { + filter, }, - async (context, req, res) => { - const requestClient = (await context.core).elasticsearch.client.asCurrentUser; - const { fromDate, toDate, fieldName, dslQuery, size } = req.body; - - const [{ savedObjects, elasticsearch }, { dataViews }] = await setup.getStartServices(); - const savedObjectsClient = savedObjects.getScopedClient(req); - const esClient = elasticsearch.client.asScoped(req).asCurrentUser; - const indexPatternsService = await dataViews.dataViewsServiceFactory( - savedObjectsClient, - esClient - ); - - try { - const indexPattern = await indexPatternsService.get(req.params.indexPatternId); - - const timeFieldName = indexPattern.timeFieldName; - const field = indexPattern.fields.find((f) => f.name === fieldName); - - if (!field) { - throw new Error(`Field {fieldName} not found in data view ${indexPattern.title}`); - } - - const filter = timeFieldName - ? [ - { - range: { - [timeFieldName]: { - gte: fromDate, - lte: toDate, - }, - }, - }, - dslQuery, - ] - : [dslQuery]; - - const query = { - bool: { - filter, - }, - }; + }; - const runtimeMappings = indexPattern.getRuntimeMappings(); + return { + index: dataViewPattern, + body: { + query, + aggs, + runtime_mappings: runtimeMappings, + }, + track_total_hits: true, + size: 0, + }; +} - const search = async (aggs: Record) => { - const result = await requestClient.search({ - index: indexPattern.title, - track_total_hits: true, - body: { - query, - aggs, - runtime_mappings: runtimeMappings, - }, - size: 0, - }); - return result; - }; +export async function fetchAndCalculateFieldStats({ + searchHandler, + field, + fromDate, + toDate, + size, +}: { + searchHandler: SearchHandler; + field: DataViewFieldBase; + fromDate: string; + toDate: string; + size?: number; +}) { + if (!canProvideStatsForField(field)) { + return {}; + } - if (field.type.includes('range')) { - return res.ok({ body: {} }); - } - - if (field.type === 'histogram') { - return res.ok({ - body: await getNumberHistogram(search, field, false), - }); - } else if (field.type === 'number') { - return res.ok({ - body: await getNumberHistogram(search, field), - }); - } else if (field.type === 'date') { - return res.ok({ - body: await getDateHistogram(search, field, { fromDate, toDate }), - }); - } - - return res.ok({ - body: await getStringSamples(search, field, size), - }); - } catch (e) { - if (e instanceof SavedObjectNotFound) { - return res.notFound(); - } - if (e instanceof errors.ResponseError && e.statusCode === 404) { - return res.notFound(); - } - if (e.isBoom) { - if (e.output.statusCode === 404) { - return res.notFound(); - } - throw new Error(e.output.message); - } else { - throw e; - } - } - } + if (field.type === 'histogram') { + return await getNumberHistogram(searchHandler, field, false); + } + + if (field.type === 'number') { + return await getNumberHistogram(searchHandler, field); + } + + if (field.type === 'date') { + return await getDateHistogram(searchHandler, field, { fromDate, toDate }); + } + + return await getStringSamples(searchHandler, field, size); +} + +export function canProvideStatsForField(field: DataViewFieldBase): boolean { + return !( + field.type === 'document' || + field.type.includes('range') || + field.type === 'geo_point' || + field.type === 'geo_shape' ); } export async function getNumberHistogram( - aggSearchWithBody: ( - aggs: Record - ) => Promise, - field: DataViewField, + aggSearchWithBody: SearchHandler, + field: DataViewFieldBase, useTopHits = true -): Promise { +): Promise> { const fieldRef = getFieldRef(field); const baseAggs = { @@ -167,7 +137,7 @@ export async function getNumberHistogram( aggs: { ...baseAggs, top_values: { - terms: { ...fieldRef, size: 10 }, + terms: { ...fieldRef, size: DEFAULT_TOP_VALUES_SIZE }, }, }, }, @@ -203,7 +173,7 @@ export async function getNumberHistogram( if (histogramInterval === 0) { return { - totalDocuments: minMaxResult.hits.total.value, + totalDocuments: getHitsTotal(minMaxResult), sampledValues: minMaxResult.aggregations!.sample.sample_count.value!, sampledDocuments: minMaxResult.aggregations!.sample.doc_count, topValues: topValuesBuckets, @@ -211,7 +181,7 @@ export async function getNumberHistogram( ? { buckets: [] } : { // Insert a fake bucket for a single-value histogram - buckets: [{ count: minMaxResult.aggregations!.sample.doc_count, key: minValue }], + buckets: [{ count: minMaxResult.aggregations!.sample.doc_count, key: minValue! }], }, }; } @@ -235,7 +205,7 @@ export async function getNumberHistogram( >; return { - totalDocuments: minMaxResult.hits.total.value, + totalDocuments: getHitsTotal(minMaxResult), sampledDocuments: minMaxResult.aggregations!.sample.doc_count, sampledValues: minMaxResult.aggregations!.sample.sample_count.value!, histogram: { @@ -249,10 +219,10 @@ export async function getNumberHistogram( } export async function getStringSamples( - aggSearchWithBody: (aggs: Record) => unknown, - field: DataViewField, - size = 10 -): Promise { + aggSearchWithBody: SearchHandler, + field: DataViewFieldBase, + size = DEFAULT_TOP_VALUES_SIZE +): Promise> { const fieldRef = getFieldRef(field); const topValuesBody = { @@ -275,7 +245,7 @@ export async function getStringSamples( >; return { - totalDocuments: topValuesResult.hits.total.value, + totalDocuments: getHitsTotal(topValuesResult), sampledDocuments: topValuesResult.aggregations!.sample.doc_count, sampledValues: topValuesResult.aggregations!.sample.sample_count.value!, topValues: { @@ -289,10 +259,10 @@ export async function getStringSamples( // This one is not sampled so that it returns the full date range export async function getDateHistogram( - aggSearchWithBody: (aggs: Record) => unknown, - field: DataViewField, + aggSearchWithBody: SearchHandler, + field: DataViewFieldBase, range: { fromDate: string; toDate: string } -): Promise { +): Promise> { const fromDate = DateMath.parse(range.fromDate); const toDate = DateMath.parse(range.toDate); if (!fromDate) { @@ -322,7 +292,7 @@ export async function getDateHistogram( >; return { - totalDocuments: results.hits.total.value, + totalDocuments: getHitsTotal(results), histogram: { buckets: results.aggregations!.histo.buckets.map((bucket) => ({ count: bucket.doc_count, @@ -332,7 +302,7 @@ export async function getDateHistogram( }; } -function getFieldRef(field: DataViewField) { +function getFieldRef(field: DataViewFieldBase) { return field.scripted ? { script: { @@ -342,3 +312,7 @@ function getFieldRef(field: DataViewField) { } : { field: field.name }; } + +const getHitsTotal = (body: estypes.SearchResponse): number => { + return (body.hits.total as estypes.SearchTotalHits).value ?? body.hits.total ?? 0; +}; diff --git a/src/plugins/unified_field_list/jest.config.js b/src/plugins/unified_field_list/jest.config.js new file mode 100644 index 0000000000000..a1782360c93b9 --- /dev/null +++ b/src/plugins/unified_field_list/jest.config.js @@ -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 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: ['/src/plugins/unified_field_list'], + coverageDirectory: '/target/kibana-coverage/jest/src/plugins/unified_field_list', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['/src/plugins/unified_field_list/public/**/*.{ts,tsx}'], +}; diff --git a/src/plugins/unified_field_list/kibana.json b/src/plugins/unified_field_list/kibana.json new file mode 100755 index 0000000000000..6785d55989cc5 --- /dev/null +++ b/src/plugins/unified_field_list/kibana.json @@ -0,0 +1,15 @@ +{ + "id": "unifiedFieldList", + "version": "1.0.0", + "kibanaVersion": "kibana", + "owner": { + "name": "Data Discovery", + "githubTeam": "kibana-data-discovery" + }, + "description": "Contains functionality for the field list which can be integrated into apps", + "server": true, + "ui": true, + "requiredPlugins": ["dataViews", "data", "fieldFormats", "charts"], + "optionalPlugins": [], + "requiredBundles": [] +} diff --git a/src/plugins/unified_field_list/public/components/field_stats/field_stats.test.tsx b/src/plugins/unified_field_list/public/components/field_stats/field_stats.test.tsx new file mode 100644 index 0000000000000..87b8b7530c839 --- /dev/null +++ b/src/plugins/unified_field_list/public/components/field_stats/field_stats.test.tsx @@ -0,0 +1,543 @@ +/* + * 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'; +import { act } from 'react-dom/test-utils'; +import { EuiLoadingSpinner, EuiProgress } from '@elastic/eui'; +import { coreMock } from '@kbn/core/public/mocks'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; +import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import type { DataViewField } from '@kbn/data-views-plugin/common'; +import { loadFieldStats } from '../../services/field_stats'; +import FieldStats from './field_stats'; +import type { FieldStatsProps } from './field_stats'; + +jest.mock('../../services/field_stats', () => ({ + loadFieldStats: jest.fn().mockResolvedValue({}), +})); + +const mockedServices = { + data: dataPluginMock.createStartContract(), + dataViews: dataViewPluginMocks.createStartContract(), + fieldFormats: fieldFormatsServiceMock.createStartContract(), + charts: chartPluginMock.createSetupContract(), + uiSettings: coreMock.createStart().uiSettings, +}; + +describe('UnifiedFieldList ', () => { + let defaultProps: FieldStatsProps; + let dataView: DataView; + + beforeEach(() => { + dataView = { + id: '1', + title: 'my-fake-index-pattern', + timeFieldName: 'timestamp', + fields: [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + { + name: 'bytes', + displayName: 'bytesLabel', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'memory', + displayName: 'memory', + type: 'number', + aggregatable: true, + searchable: true, + }, + { + name: 'unsupported', + displayName: 'unsupported', + type: 'geo', + aggregatable: true, + searchable: true, + }, + { + name: 'source', + displayName: 'source', + type: 'string', + aggregatable: true, + searchable: true, + }, + { + name: 'ip_range', + displayName: 'ip_range', + type: 'ip_range', + aggregatable: true, + searchable: true, + }, + { + name: 'machine.ram', + displayName: 'machine.ram', + type: 'number', + aggregatable: true, + searchable: true, + }, + ], + getFormatterForField: jest.fn(() => ({ + convert: jest.fn((s: unknown) => JSON.stringify(s)), + })), + } as unknown as DataView; + + defaultProps = { + services: mockedServices, + dataViewOrDataViewId: dataView, + field: { + name: 'bytes', + type: 'number', + } as unknown as DataViewField, + fromDate: 'now-7d', + toDate: 'now', + query: { query: '', language: 'lucene' }, + filters: [], + 'data-test-subj': 'testing', + }; + + (mockedServices.dataViews.get as jest.Mock).mockImplementation(() => { + return Promise.resolve(dataView); + }); + }); + + beforeEach(() => { + (loadFieldStats as jest.Mock).mockReset(); + (loadFieldStats as jest.Mock).mockImplementation(() => Promise.resolve({})); + }); + + it('should request field stats with correct params', async () => { + let resolveFunction: (arg: unknown) => void; + + (loadFieldStats as jest.Mock).mockImplementation(() => { + return new Promise((resolve) => { + resolveFunction = resolve; + }); + }); + + const wrapper = mountWithIntl( + + ); + + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalledWith({ + abortController: new AbortController(), + services: { data: mockedServices.data }, + dataView, + dslQuery: { + bool: { + must: [], + filter: [ + { + bool: { + should: [{ match_phrase: { 'geo.src': 'US' } }], + minimum_should_match: 1, + }, + }, + { + match: { phrase: { 'geo.dest': 'US' } }, + }, + ], + should: [], + must_not: [], + }, + }, + fromDate: 'now-14d', + toDate: 'now-7d', + field: defaultProps.field, + }); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(1); + + await act(async () => { + resolveFunction!({ + totalDocuments: 4633, + sampledDocuments: 4633, + sampledValues: 4633, + histogram: { + buckets: [{ count: 705, key: 0 }], + }, + topValues: { + buckets: [{ count: 147, key: 0 }], + }, + }); + }); + + await wrapper.update(); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0); + + expect(loadFieldStats).toHaveBeenCalledTimes(1); + }); + + it('should not request field stats for range fields', async () => { + const wrapper = await mountWithIntl( + + ); + + await wrapper.update(); + + expect(loadFieldStats).not.toHaveBeenCalled(); + }); + + it('should not request field stats for geo fields', async () => { + const wrapper = await mountWithIntl( + + ); + + await wrapper.update(); + + expect(loadFieldStats).not.toHaveBeenCalled(); + }); + + it('should render nothing if no data is found', async () => { + const wrapper = mountWithIntl(); + + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalled(); + + expect(wrapper.text()).toBe(''); + }); + + it('should render Top Values field stats correctly for a keyword field', async () => { + let resolveFunction: (arg: unknown) => void; + + (loadFieldStats as jest.Mock).mockImplementation(() => { + return new Promise((resolve) => { + resolveFunction = resolve; + }); + }); + + const wrapper = mountWithIntl( + + ); + + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalledWith({ + abortController: new AbortController(), + services: { data: mockedServices.data }, + dataView, + fromDate: 'now-7d', + toDate: 'now', + dslQuery: { + bool: { + must: [], + filter: [], + should: [], + must_not: [], + }, + }, + field: defaultProps.field, + }); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(1); + + await act(async () => { + resolveFunction!({ + totalDocuments: 1624, + sampledDocuments: 1624, + sampledValues: 3248, + topValues: { + buckets: [ + { + count: 1349, + key: 'success', + }, + { + count: 1206, + key: 'info', + }, + { + count: 329, + key: 'security', + }, + { + count: 164, + key: 'warning', + }, + { + count: 111, + key: 'error', + }, + { + count: 89, + key: 'login', + }, + ], + }, + }); + }); + + await wrapper.update(); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0); + expect(wrapper.find(EuiProgress)).toHaveLength(6); + + expect(loadFieldStats).toHaveBeenCalledTimes(1); + + const stats = wrapper.find('[data-test-subj="testing-topValues"]'); + const firstValue = stats.childAt(0); + + expect(stats).toHaveLength(1); + expect(firstValue.find('[data-test-subj="testing-topValues-value"]').first().text()).toBe( + '"success"' + ); + expect(firstValue.find('[data-test-subj="testing-topValues-valueCount"]').first().text()).toBe( + '41.5%' + ); + + expect(wrapper.find('[data-test-subj="testing-statsFooter"]').first().text()).toBe( + '100% of 1624 documents' + ); + + expect(wrapper.text()).toBe( + 'Top values"success"41.5%"info"37.1%"security"10.1%"warning"5.0%"error"3.4%"login"2.7%100% of 1624 documents' + ); + }); + + it('should render Histogram field stats correctly for a date field', async () => { + let resolveFunction: (arg: unknown) => void; + + (loadFieldStats as jest.Mock).mockImplementation(() => { + return new Promise((resolve) => { + resolveFunction = resolve; + }); + }); + + const wrapper = mountWithIntl( + + ); + + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalledWith({ + abortController: new AbortController(), + services: { data: mockedServices.data }, + dataView, + fromDate: 'now-1h', + toDate: 'now', + dslQuery: { + bool: { + must: [], + filter: [], + should: [], + must_not: [], + }, + }, + field: dataView.fields[0], + }); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(1); + + await act(async () => { + resolveFunction!({ + totalDocuments: 13, + histogram: { + buckets: [ + { + count: 1, + key: 1660564080000, + }, + { + count: 2, + key: 1660564440000, + }, + { + count: 3, + key: 1660564800000, + }, + { + count: 1, + key: 1660565160000, + }, + { + count: 2, + key: 1660565520000, + }, + { + count: 0, + key: 1660565880000, + }, + { + count: 1, + key: 1660566240000, + }, + { + count: 1, + key: 1660566600000, + }, + { + count: 1, + key: 1660566960000, + }, + { + count: 1, + key: 1660567320000, + }, + ], + }, + }); + }); + + await wrapper.update(); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0); + + expect(loadFieldStats).toHaveBeenCalledTimes(1); + + expect(wrapper.find('[data-test-subj="testing-topValues"]')).toHaveLength(0); + expect(wrapper.find('[data-test-subj="testing-histogram"]')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="testing-statsFooter"]').first().text()).toBe( + '13 documents' + ); + + expect(wrapper.text()).toBe('Time distribution13 documents'); + }); + + it('should render Top Values & Distribution field stats correctly for a number field', async () => { + let resolveFunction: (arg: unknown) => void; + + (loadFieldStats as jest.Mock).mockImplementation(() => { + return new Promise((resolve) => { + resolveFunction = resolve; + }); + }); + + const field = dataView.fields.find((f) => f.name === 'machine.ram')!; + + const wrapper = mountWithIntl( + + ); + + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalledWith({ + abortController: new AbortController(), + services: { data: mockedServices.data }, + dataView, + fromDate: 'now-1h', + toDate: 'now', + dslQuery: { + bool: { + must: [], + filter: [], + should: [], + must_not: [], + }, + }, + field, + }); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(1); + + await act(async () => { + resolveFunction!({ + totalDocuments: 23, + sampledDocuments: 23, + sampledValues: 23, + histogram: { + buckets: [ + { + count: 17, + key: 12, + }, + { + count: 6, + key: 13, + }, + ], + }, + topValues: { + buckets: [ + { + count: 17, + key: 12, + }, + { + count: 6, + key: 13, + }, + ], + }, + }); + }); + + await wrapper.update(); + + expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0); + + expect(loadFieldStats).toHaveBeenCalledTimes(1); + + expect(wrapper.text()).toBe( + 'Toggle either theTop valuesDistribution1273.9%1326.1%100% of 23 documents' + ); + }); +}); diff --git a/src/plugins/unified_field_list/public/components/field_stats/field_stats.tsx b/src/plugins/unified_field_list/public/components/field_stats/field_stats.tsx new file mode 100755 index 0000000000000..590451a255894 --- /dev/null +++ b/src/plugins/unified_field_list/public/components/field_stats/field_stats.tsx @@ -0,0 +1,595 @@ +/* + * 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, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { + DataView, + DataViewField, + ES_FIELD_TYPES, + getEsQueryConfig, + KBN_FIELD_TYPES, +} from '@kbn/data-plugin/common'; +import type { IUiSettingsClient } from '@kbn/core/public'; +import type { DataViewsContract } from '@kbn/data-views-plugin/public'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { ChartsPluginSetup } from '@kbn/charts-plugin/public'; +import DateMath from '@kbn/datemath'; +import { + EuiButtonGroup, + EuiFlexGroup, + EuiFlexItem, + EuiLoadingSpinner, + EuiProgress, + EuiSpacer, + EuiText, + EuiTitle, + EuiToolTip, + useEuiTheme, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { + Axis, + Chart, + HistogramBarSeries, + niceTimeFormatter, + Position, + ScaleType, + Settings, + TooltipType, +} from '@elastic/charts'; +import { i18n } from '@kbn/i18n'; +import { buildEsQuery, Query, Filter, AggregateQuery } from '@kbn/es-query'; +import type { BucketedAggregation } from '../../../common/types'; +import { canProvideStatsForField } from '../../../common/utils/field_stats_utils'; +import { loadFieldStats } from '../../services/field_stats'; + +interface State { + isLoading: boolean; + totalDocuments?: number; + sampledDocuments?: number; + sampledValues?: number; + histogram?: BucketedAggregation; + topValues?: BucketedAggregation; +} + +export interface FieldStatsServices { + uiSettings: IUiSettingsClient; + dataViews: DataViewsContract; + data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; + charts: ChartsPluginSetup; +} + +export interface FieldStatsProps { + services: FieldStatsServices; + query: Query | AggregateQuery; + filters: Filter[]; + fromDate: string; + toDate: string; + dataViewOrDataViewId: DataView | string; + field: DataViewField; + 'data-test-subj'?: string; + overrideMissingContent?: (params?: { noDataFound?: boolean }) => JSX.Element | null; + overrideFooter?: (params: { + element: JSX.Element; + totalDocuments?: number; + sampledDocuments?: number; + }) => JSX.Element; +} + +const FieldStatsComponent: React.FC = ({ + services, + query, + filters, + fromDate, + toDate, + dataViewOrDataViewId, + field, + 'data-test-subj': dataTestSubject = 'fieldStats', + overrideMissingContent, + overrideFooter, +}) => { + const { euiTheme } = useEuiTheme(); + const { fieldFormats, uiSettings, charts, dataViews, data } = services; + const [state, changeState] = useState({ + isLoading: false, + }); + const [dataView, changeDataView] = useState(null); + const abortControllerRef = useRef(null); + const isCanceledRef = useRef(false); + + const topValueStyles = useMemo( + () => css` + margin-bottom: ${euiTheme.size.s}; + + &:last-of-type { + margin-bottom: 0; + } + `, + [euiTheme] + ); + + const topValueProgressStyles = useMemo( + () => css` + background-color: ${euiTheme.colors.lightestShade}; + + &::-webkit-progress-bar { + background-color: ${euiTheme.colors.lightestShade}; + } + `, + [euiTheme] + ); + + const setState: typeof changeState = useCallback( + (nextState) => { + if (!isCanceledRef.current) { + changeState(nextState); + } + }, + [changeState, isCanceledRef] + ); + + const setDataView: typeof changeDataView = useCallback( + (nextDataView) => { + if (!isCanceledRef.current) { + changeDataView(nextDataView); + } + }, + [changeDataView, isCanceledRef] + ); + + async function fetchData() { + if (isCanceledRef.current) { + return; + } + + try { + const loadedDataView = + typeof dataViewOrDataViewId === 'string' + ? await dataViews.get(dataViewOrDataViewId) + : dataViewOrDataViewId; + + setDataView(loadedDataView); + + if (state.isLoading || !canProvideStatsForField(field)) { + return; + } + + setState((s) => ({ ...s, isLoading: true })); + + abortControllerRef.current?.abort(); + abortControllerRef.current = new AbortController(); + + const results = await loadFieldStats({ + services: { data }, + dataView: loadedDataView, + field, + fromDate, + toDate, + dslQuery: buildEsQuery(loadedDataView, query, filters, getEsQueryConfig(uiSettings)), + abortController: abortControllerRef.current, + }); + + abortControllerRef.current = null; + + setState((s) => ({ + ...s, + isLoading: false, + totalDocuments: results.totalDocuments, + sampledDocuments: results.sampledDocuments, + sampledValues: results.sampledValues, + histogram: results.histogram, + topValues: results.topValues, + })); + } catch (e) { + // console.error(e); + setState((s) => ({ ...s, isLoading: false })); + } + } + + useEffect(() => { + fetchData(); + + return () => { + isCanceledRef.current = true; + abortControllerRef.current?.abort(); + }; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + const chartTheme = charts.theme.useChartsTheme(); + const chartBaseTheme = charts.theme.useChartsBaseTheme(); + + const { isLoading, histogram, topValues, sampledValues, sampledDocuments, totalDocuments } = + state; + + let histogramDefault = !!state.histogram; + const fromDateParsed = DateMath.parse(fromDate); + const toDateParsed = DateMath.parse(toDate); + + const totalValuesCount = + topValues && topValues.buckets.reduce((prev, bucket) => bucket.count + prev, 0); + const otherCount = sampledValues && totalValuesCount ? sampledValues - totalValuesCount : 0; + + if ( + totalValuesCount && + histogram && + histogram.buckets.length && + topValues && + topValues.buckets.length + ) { + // Default to histogram when top values are less than 10% of total + histogramDefault = otherCount / totalValuesCount > 0.9; + } + + const [showingHistogram, setShowingHistogram] = useState(histogramDefault); + + if (isLoading) { + return ; + } + + if (!dataView) { + return null; + } + + const formatter = dataView.getFormatterForField(field); + let title = <>; + + if (field.type.includes('range')) { + return ( + <> + + {i18n.translate('unifiedFieldList.fieldStats.notAvailableForRangeFieldDescription', { + defaultMessage: `Summary information is not available for range type fields.`, + })} + + + ); + } + + if (field.type === 'murmur3') { + return ( + <> + + {i18n.translate('unifiedFieldList.fieldStats.notAvailableForMurmur3FieldDescription', { + defaultMessage: `Summary information is not available for murmur3 fields.`, + })} + + + ); + } + + if (field.type === 'geo_point' || field.type === 'geo_shape') { + return overrideMissingContent ? overrideMissingContent() : null; + } + + if ( + (!histogram || histogram.buckets.length === 0) && + (!topValues || topValues.buckets.length === 0) + ) { + return overrideMissingContent ? overrideMissingContent({ noDataFound: true }) : null; + } + + if (histogram && histogram.buckets.length && topValues && topValues.buckets.length) { + title = ( + { + setShowingHistogram(optionId === 'histogram'); + }} + idSelected={showingHistogram ? 'histogram' : 'topValues'} + /> + ); + } else if (field.type === 'date') { + title = ( + +
+ {i18n.translate('unifiedFieldList.fieldStats.fieldTimeDistributionLabel', { + defaultMessage: 'Time distribution', + })} +
+
+ ); + } else if (topValues && topValues.buckets.length) { + title = ( + +
+ {i18n.translate('unifiedFieldList.fieldStats.topValuesLabel', { + defaultMessage: 'Top values', + })} +
+
+ ); + } + + function combineWithTitleAndFooter(el: React.ReactElement) { + const countsElement = totalDocuments ? ( + + {sampledDocuments && ( + <> + {i18n.translate('unifiedFieldList.fieldStats.percentageOfLabel', { + defaultMessage: '{percentage}% of', + values: { + percentage: Math.round((sampledDocuments / totalDocuments) * 100), + }, + })}{' '} + + )} + + {fieldFormats + .getDefaultInstance(KBN_FIELD_TYPES.NUMBER, [ES_FIELD_TYPES.INTEGER]) + .convert(totalDocuments)} + {' '} + {i18n.translate('unifiedFieldList.fieldStats.ofDocumentsLabel', { + defaultMessage: 'documents', + })} + + ) : ( + <> + ); + + return ( + <> + {title ? title : <>} + + + + {el} + + {overrideFooter ? ( + overrideFooter?.({ element: countsElement, totalDocuments, sampledDocuments }) + ) : ( + <> + + {countsElement} + + )} + + ); + } + + if (histogram && histogram.buckets.length) { + const specId = i18n.translate('unifiedFieldList.fieldStats.countLabel', { + defaultMessage: 'Count', + }); + + if (field.type === 'date') { + return combineWithTitleAndFooter( + + + + + + + + ); + } + + if (showingHistogram || !topValues || !topValues.buckets.length) { + return combineWithTitleAndFooter( + + + + formatter.convert(d)} + /> + + + + ); + } + } + + if (topValues && topValues.buckets.length) { + const digitsRequired = topValues.buckets.some( + (topValue) => !Number.isInteger(topValue.count / sampledValues!) + ); + return combineWithTitleAndFooter( +
+ {topValues.buckets.map((topValue) => { + const formatted = formatter.convert(topValue.key); + return ( +
+ + + {formatted === '' ? ( + + + {i18n.translate('unifiedFieldList.fieldStats.emptyStringValueLabel', { + defaultMessage: 'Empty string', + })} + + + ) : ( + + + {formatted} + + + )} + + + + {(Math.round((topValue.count / sampledValues!) * 1000) / 10).toFixed( + digitsRequired ? 1 : 0 + )} + % + + + + +
+ ); + })} + {otherCount ? ( + <> + + + + {i18n.translate('unifiedFieldList.fieldStats.otherDocsLabel', { + defaultMessage: 'Other', + })} + + + + + + {(Math.round((otherCount / sampledValues!) * 1000) / 10).toFixed( + digitsRequired ? 1 : 0 + )} + % + + + + + + + ) : ( + <> + )} +
+ ); + } + + return null; +}; + +class ErrorBoundary extends React.Component<{}, { hasError: boolean }> { + constructor(props: FieldStatsProps) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError() { + return { hasError: true }; + } + + // componentDidCatch(error, errorInfo) { + // console.log(error, errorInfo); + // } + + render() { + if (this.state.hasError) { + return null; + } + + return this.props.children; + } +} + +/** + * Component which fetches and renders stats for a data view field + * @param props + * @constructor + */ +const FieldStats: React.FC = (props) => { + return ( + + + + ); +}; + +// Necessary for React.lazy +// eslint-disable-next-line import/no-default-export +export default FieldStats; diff --git a/src/plugins/unified_field_list/public/components/field_stats/index.tsx b/src/plugins/unified_field_list/public/components/field_stats/index.tsx new file mode 100755 index 0000000000000..0cfb29d4abd5f --- /dev/null +++ b/src/plugins/unified_field_list/public/components/field_stats/index.tsx @@ -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, { Fragment } from 'react'; +import type { FieldStatsProps, FieldStatsServices } from './field_stats'; + +const Fallback = () => ; + +const LazyFieldStats = React.lazy(() => import('./field_stats')); +const WrappedFieldStats: React.FC = (props) => ( + }> + + +); + +export const FieldStats = WrappedFieldStats; +export type { FieldStatsProps, FieldStatsServices }; diff --git a/src/plugins/unified_field_list/public/index.ts b/src/plugins/unified_field_list/public/index.ts new file mode 100755 index 0000000000000..f2f666dd47481 --- /dev/null +++ b/src/plugins/unified_field_list/public/index.ts @@ -0,0 +1,26 @@ +/* + * 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 { UnifiedFieldListPlugin } from './plugin'; + +export type { + FieldStatsResponse, + BucketedAggregation, + NumberStatsResult, + TopValuesResult, +} from '../common/types'; +export type { FieldStatsProps, FieldStatsServices } from './components/field_stats'; +export { FieldStats } from './components/field_stats'; +export { loadFieldStats } from './services/field_stats'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. +export function plugin() { + return new UnifiedFieldListPlugin(); +} +export type { UnifiedFieldListPluginSetup, UnifiedFieldListPluginStart } from './types'; diff --git a/src/plugins/unified_field_list/public/plugin.ts b/src/plugins/unified_field_list/public/plugin.ts new file mode 100755 index 0000000000000..009b73dd1c575 --- /dev/null +++ b/src/plugins/unified_field_list/public/plugin.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { UnifiedFieldListPluginSetup, UnifiedFieldListPluginStart } from './types'; + +export class UnifiedFieldListPlugin + implements Plugin +{ + public setup(core: CoreSetup): UnifiedFieldListPluginSetup { + // Return methods that should be available to other plugins + return {}; + } + + public start(core: CoreStart): UnifiedFieldListPluginStart { + return {}; + } + + public stop() {} +} diff --git a/src/plugins/unified_field_list/public/services/field_stats/index.tsx b/src/plugins/unified_field_list/public/services/field_stats/index.tsx new file mode 100755 index 0000000000000..644bca5a054d4 --- /dev/null +++ b/src/plugins/unified_field_list/public/services/field_stats/index.tsx @@ -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 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 { LoadFieldStatsHandler } from './load_field_stats'; + +export const loadFieldStats: LoadFieldStatsHandler = async (params) => { + const { loadFieldStats: loadFieldStatsHandler } = await import('./load_field_stats'); + return await loadFieldStatsHandler(params); +}; diff --git a/src/plugins/unified_field_list/public/services/field_stats/load_field_stats.ts b/src/plugins/unified_field_list/public/services/field_stats/load_field_stats.ts new file mode 100644 index 0000000000000..fd38cd0bfca64 --- /dev/null +++ b/src/plugins/unified_field_list/public/services/field_stats/load_field_stats.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 { lastValueFrom } from 'rxjs'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewFieldBase } from '@kbn/es-query'; +import type { FieldStatsResponse } from '../../../common/types'; +import { + fetchAndCalculateFieldStats, + SearchHandler, + buildSearchParams, +} from '../../../common/utils/field_stats_utils'; + +interface FetchFieldStatsParams { + services: { + data: DataPublicPluginStart; + }; + dataView: DataView; + field: DataViewFieldBase; + fromDate: string; + toDate: string; + dslQuery: object; + size?: number; + abortController?: AbortController; +} + +export type LoadFieldStatsHandler = ( + params: FetchFieldStatsParams +) => Promise>; + +/** + * Loads and aggregates stats data for a data view field + * @param services + * @param dataView + * @param field + * @param fromDate + * @param toDate + * @param dslQuery + * @param size + * @param abortController + */ +export const loadFieldStats: LoadFieldStatsHandler = async ({ + services, + dataView, + field, + fromDate, + toDate, + dslQuery, + size, + abortController, +}) => { + const { data } = services; + + try { + if (!dataView?.id || !field?.type) { + return {}; + } + + const searchHandler: SearchHandler = async (aggs) => { + const result = await lastValueFrom( + data.search.search( + { + params: buildSearchParams({ + dataViewPattern: dataView.title, + timeFieldName: dataView.timeFieldName, + fromDate, + toDate, + dslQuery, + runtimeMappings: dataView.getRuntimeMappings(), + aggs, + }), + }, + { + abortSignal: abortController?.signal, + } + ) + ); + return result.rawResponse; + }; + + return await fetchAndCalculateFieldStats({ + searchHandler, + field, + fromDate, + toDate, + size, + }); + } catch (error) { + // console.error(error); + throw new Error('Could not provide field stats', { cause: error }); + } +}; diff --git a/src/plugins/unified_field_list/public/types.ts b/src/plugins/unified_field_list/public/types.ts new file mode 100755 index 0000000000000..feb24509cdee5 --- /dev/null +++ b/src/plugins/unified_field_list/public/types.ts @@ -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. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface UnifiedFieldListPluginSetup {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface UnifiedFieldListPluginStart {} diff --git a/src/plugins/unified_field_list/server/index.ts b/src/plugins/unified_field_list/server/index.ts new file mode 100644 index 0000000000000..039ea0488b533 --- /dev/null +++ b/src/plugins/unified_field_list/server/index.ts @@ -0,0 +1,24 @@ +/* + * 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 { PluginInitializerContext } from '@kbn/core/server'; +import { UnifiedFieldListPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. + +export function plugin(initializerContext: PluginInitializerContext) { + return new UnifiedFieldListPlugin(initializerContext); +} + +export type { + UnifiedFieldListServerPluginSetup, + UnifiedFieldListServerPluginStart, + PluginSetup, + PluginStart, +} from './types'; diff --git a/src/plugins/unified_field_list/server/plugin.ts b/src/plugins/unified_field_list/server/plugin.ts new file mode 100644 index 0000000000000..2853afcf3d6fd --- /dev/null +++ b/src/plugins/unified_field_list/server/plugin.ts @@ -0,0 +1,41 @@ +/* + * 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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; +import { + UnifiedFieldListServerPluginSetup, + UnifiedFieldListServerPluginStart, + PluginStart, + PluginSetup, +} from './types'; +import { defineRoutes } from './routes'; + +export class UnifiedFieldListPlugin + implements Plugin +{ + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup, plugins: PluginSetup) { + this.logger.debug('unifiedFieldList: Setup'); + + defineRoutes(core); + + return {}; + } + + public start(core: CoreStart, plugins: PluginStart) { + this.logger.debug('unifiedFieldList: Started'); + return {}; + } + + public stop() {} +} diff --git a/src/plugins/unified_field_list/server/routes/field_stats.ts b/src/plugins/unified_field_list/server/routes/field_stats.ts new file mode 100644 index 0000000000000..4fc654f892210 --- /dev/null +++ b/src/plugins/unified_field_list/server/routes/field_stats.ts @@ -0,0 +1,104 @@ +/* + * 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 { errors } from '@elastic/elasticsearch'; +import { schema } from '@kbn/config-schema'; +import { CoreSetup } from '@kbn/core/server'; +import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/common'; +import { FIELD_STATS_API_PATH } from '../../common/constants'; +import type { PluginStart } from '../types'; +import { + fetchAndCalculateFieldStats, + SearchHandler, + buildSearchParams, +} from '../../common/utils/field_stats_utils'; + +export async function initFieldStatsRoute(setup: CoreSetup) { + const router = setup.http.createRouter(); + router.post( + { + path: FIELD_STATS_API_PATH, + validate: { + body: schema.object( + { + dslQuery: schema.object({}, { unknowns: 'allow' }), + fromDate: schema.string(), + toDate: schema.string(), + dataViewId: schema.string(), + fieldName: schema.string(), + size: schema.maybe(schema.number()), + }, + { unknowns: 'allow' } + ), + }, + }, + async (context, req, res) => { + const requestClient = (await context.core).elasticsearch.client.asCurrentUser; + const { fromDate, toDate, fieldName, dslQuery, size, dataViewId } = req.body; + + const [{ savedObjects, elasticsearch }, { dataViews }] = await setup.getStartServices(); + const savedObjectsClient = savedObjects.getScopedClient(req); + const esClient = elasticsearch.client.asScoped(req).asCurrentUser; + const indexPatternsService = await dataViews.dataViewsServiceFactory( + savedObjectsClient, + esClient + ); + + try { + const dataView = await indexPatternsService.get(dataViewId); + const field = dataView.fields.find((f) => f.name === fieldName); + + if (!field) { + throw new Error(`Field {fieldName} not found in data view ${dataView.title}`); + } + + const searchHandler: SearchHandler = async (aggs) => { + const result = await requestClient.search( + buildSearchParams({ + dataViewPattern: dataView.title, + timeFieldName: dataView.timeFieldName, + fromDate, + toDate, + dslQuery, + runtimeMappings: dataView.getRuntimeMappings(), + aggs, + }) + ); + return result; + }; + + const stats = await fetchAndCalculateFieldStats({ + searchHandler, + field, + fromDate, + toDate, + size, + }); + + return res.ok({ + body: stats, + }); + } catch (e) { + if (e instanceof SavedObjectNotFound) { + return res.notFound(); + } + if (e instanceof errors.ResponseError && e.statusCode === 404) { + return res.notFound(); + } + if (e.isBoom) { + if (e.output.statusCode === 404) { + return res.notFound(); + } + throw new Error(e.output.message); + } else { + throw e; + } + } + } + ); +} diff --git a/src/plugins/unified_field_list/server/routes/index.ts b/src/plugins/unified_field_list/server/routes/index.ts new file mode 100644 index 0000000000000..3558e93e4a780 --- /dev/null +++ b/src/plugins/unified_field_list/server/routes/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CoreSetup } from '@kbn/core/server'; +import { PluginStart } from '../types'; +import { initFieldStatsRoute } from './field_stats'; + +export function defineRoutes(setup: CoreSetup) { + initFieldStatsRoute(setup); +} diff --git a/src/plugins/unified_field_list/server/types.ts b/src/plugins/unified_field_list/server/types.ts new file mode 100644 index 0000000000000..56cd69a01881e --- /dev/null +++ b/src/plugins/unified_field_list/server/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 { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface UnifiedFieldListServerPluginSetup {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface UnifiedFieldListServerPluginStart {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface PluginSetup {} + +export interface PluginStart { + dataViews: DataViewsServerPluginStart; +} diff --git a/src/plugins/unified_field_list/tsconfig.json b/src/plugins/unified_field_list/tsconfig.json new file mode 100644 index 0000000000000..221729fbd2b71 --- /dev/null +++ b/src/plugins/unified_field_list/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types", + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true + }, + "include": [ + "../../typings/**/*", + "common/**/*", + "public/**/*", + "server/**/*", + ], + "references": [ + { "path": "../../core/tsconfig.json" }, + { "path": "../kibana_utils/tsconfig.json" }, + { "path": "../kibana_react/tsconfig.json" }, + { "path": "../data_views/tsconfig.json" }, + { "path": "../data/tsconfig.json" }, + { "path": "../charts/tsconfig.json" } + ] +} diff --git a/test/api_integration/apis/index.ts b/test/api_integration/apis/index.ts index f7801f4d42e71..3b8a182308e77 100644 --- a/test/api_integration/apis/index.ts +++ b/test/api_integration/apis/index.ts @@ -28,6 +28,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./stats')); loadTestFile(require.resolve('./ui_metric')); loadTestFile(require.resolve('./ui_counters')); + loadTestFile(require.resolve('./unified_field_list')); loadTestFile(require.resolve('./telemetry')); }); } diff --git a/x-pack/test/api_integration/apis/lens/field_stats.ts b/test/api_integration/apis/unified_field_list/field_stats.ts similarity index 92% rename from x-pack/test/api_integration/apis/lens/field_stats.ts rename to test/api_integration/apis/unified_field_list/field_stats.ts index 4d38b54b02252..b489dea50d740 100644 --- a/x-pack/test/api_integration/apis/lens/field_stats.ts +++ b/test/api_integration/apis/unified_field_list/field_stats.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ import expect from '@kbn/expect'; @@ -19,8 +20,9 @@ export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const supertest = getService('supertest'); + const API_PATH = '/api/unified_field_list/field_stats'; - describe('index stats apis', () => { + describe('field stats apis', () => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); }); @@ -41,13 +43,13 @@ export default ({ getService }: FtrProviderContext) => { it('should return a 404 for missing index patterns', async () => { await supertest - .post('/api/lens/index_stats/123/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: '123', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, - timeFieldName: '@timestamp', fieldName: 'bytes', }) .expect(404); @@ -55,9 +57,10 @@ export default ({ getService }: FtrProviderContext) => { it('should also work without specifying a time field', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -70,9 +73,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return an auto histogram for numbers and top values', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -177,9 +181,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return an auto histogram for dates', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -210,9 +215,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return top values for strings', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -273,9 +279,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return top values for ip fields', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -336,9 +343,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return histograms for scripted date fields', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -361,9 +369,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return top values for scripted string fields', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -388,9 +397,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return top values for index pattern runtime string fields', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -415,9 +425,10 @@ export default ({ getService }: FtrProviderContext) => { it('should apply filters and queries', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { bool: { filter: [{ match: { 'geo.src': 'US' } }], @@ -434,9 +445,10 @@ export default ({ getService }: FtrProviderContext) => { it('should allow filtering on a runtime field other than the field in use', async () => { const { body } = await supertest - .post('/api/lens/index_stats/logstash-2015.09.22/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'logstash-2015.09.22', dslQuery: { bool: { filter: [{ exists: { field: 'runtime_string_field' } }], @@ -477,9 +489,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return an auto histogram for precalculated histograms', async () => { const { body } = await supertest - .post('/api/lens/index_stats/histogram-test/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'histogram-test', dslQuery: { match_all: {} }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, @@ -545,9 +558,10 @@ export default ({ getService }: FtrProviderContext) => { it('should return a single-value histogram when filtering a precalculated histogram', async () => { const { body } = await supertest - .post('/api/lens/index_stats/histogram-test/field') + .post(API_PATH) .set(COMMON_HEADERS) .send({ + dataViewId: 'histogram-test', dslQuery: { match: { 'histogram-title': 'single value' } }, fromDate: TEST_START_TIME, toDate: TEST_END_TIME, diff --git a/test/api_integration/apis/unified_field_list/index.ts b/test/api_integration/apis/unified_field_list/index.ts new file mode 100644 index 0000000000000..da0a6098e0a42 --- /dev/null +++ b/test/api_integration/apis/unified_field_list/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export default function lensApiIntegrationTests({ loadTestFile }: FtrProviderContext) { + describe('UnifiedFieldList', () => { + loadTestFile(require.resolve('./field_stats')); + }); +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 68882faec661a..c6f6366bc3f84 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -161,6 +161,8 @@ "@kbn/ui-actions-enhanced-plugin/*": ["src/plugins/ui_actions_enhanced/*"], "@kbn/ui-actions-plugin": ["src/plugins/ui_actions"], "@kbn/ui-actions-plugin/*": ["src/plugins/ui_actions/*"], + "@kbn/unified-field-list-plugin": ["src/plugins/unified_field_list"], + "@kbn/unified-field-list-plugin/*": ["src/plugins/unified_field_list/*"], "@kbn/unified-search-plugin": ["src/plugins/unified_search"], "@kbn/unified-search-plugin/*": ["src/plugins/unified_search/*"], "@kbn/url-forwarding-plugin": ["src/plugins/url_forwarding"], diff --git a/x-pack/plugins/lens/common/index.ts b/x-pack/plugins/lens/common/index.ts index e0600bd18afc1..45dd41422b018 100644 --- a/x-pack/plugins/lens/common/index.ts +++ b/x-pack/plugins/lens/common/index.ts @@ -8,7 +8,6 @@ // TODO: https://github.com/elastic/kibana/issues/110891 /* eslint-disable @kbn/eslint/no_export_all */ -export * from './api'; export * from './constants'; export * from './types'; diff --git a/x-pack/plugins/lens/kibana.json b/x-pack/plugins/lens/kibana.json index cb208eb60daff..bff30e66a9bc8 100644 --- a/x-pack/plugins/lens/kibana.json +++ b/x-pack/plugins/lens/kibana.json @@ -26,7 +26,8 @@ "expressionMetricVis", "expressionHeatmap", "eventAnnotation", - "unifiedSearch" + "unifiedSearch", + "unifiedFieldList" ], "optionalPlugins": [ "expressionXY", diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index 34a06439473a3..8c73d826724ea 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -96,6 +96,7 @@ export async function getLensServices( dataViewEditor: startDependencies.dataViewEditor, dataViewFieldEditor: startDependencies.dataViewFieldEditor, dashboard: startDependencies.dashboard, + charts: startDependencies.charts, getOriginatingAppName: () => { return embeddableEditorIncomingState?.originatingApp ? stateTransfer?.getAppNameFromId(embeddableEditorIncomingState.originatingApp) diff --git a/x-pack/plugins/lens/public/app_plugin/types.ts b/x-pack/plugins/lens/public/app_plugin/types.ts index 6a2718fc49820..be49ca768acdc 100644 --- a/x-pack/plugins/lens/public/app_plugin/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/types.ts @@ -37,6 +37,7 @@ import { ACTION_CONVERT_TO_LENS } from '@kbn/visualizations-plugin/public'; import type { EmbeddableEditorState, EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { ChartsPluginSetup } from '@kbn/charts-plugin/public'; import type { DatasourceMap, EditorFrameInstance, @@ -140,6 +141,7 @@ export interface LensAppServices { getOriginatingAppName: () => string | undefined; presentationUtil: PresentationUtilPluginStart; spaces: SpacesApi; + charts: ChartsPluginSetup; discover?: DiscoverStart; // Temporarily required until the 'by value' paradigm is default. diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.scss b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.scss index b96a670144d37..a309e37938cda 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.scss +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.scss @@ -50,23 +50,6 @@ color: $euiColorDarkShade; } -.lnsFieldItem__topValue { - margin-bottom: $euiSizeS; - - &:last-of-type { - margin-bottom: 0; - } -} - -.lnsFieldItem__topValueProgress { - background-color: $euiColorLightestShade; - - // sass-lint:disable-block no-vendor-prefixes - &::-webkit-progress-bar { - background-color: $euiColorLightestShade; - } -} - .lnsFieldItem__fieldPanel { min-width: 260px; max-width: 300px; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx index 3c3b81cd126df..615279b71b82c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx @@ -18,18 +18,45 @@ import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { documentField } from './document_field'; import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import { loadFieldStats } from '@kbn/unified-field-list-plugin/public'; import { DOCUMENT_FIELD_NAME } from '../../common'; +jest.mock('@kbn/unified-field-list-plugin/public/services/field_stats', () => ({ + loadFieldStats: jest.fn().mockResolvedValue({}), +})); + const chartsThemeService = chartPluginMock.createSetupContract().theme; -function clickField(wrapper: ReactWrapper, field: string) { - wrapper.find(`[data-test-subj="lnsFieldListPanelField-${field}"] button`).simulate('click'); -} +const clickField = async (wrapper: ReactWrapper, field: string) => { + await act(async () => { + wrapper.find(`[data-test-subj="lnsFieldListPanelField-${field}"] button`).simulate('click'); + }); +}; + +const mockedServices = { + data: dataPluginMock.createStartContract(), + dataViews: dataViewPluginMocks.createStartContract(), + fieldFormats: fieldFormatsServiceMock.createStartContract(), + charts: chartPluginMock.createSetupContract(), + uiSettings: coreMock.createStart().uiSettings, +}; + +const InnerFieldItemWrapper: React.FC = (props) => { + return ( + + + + ); +}; describe('IndexPattern Field Item', () => { let defaultProps: FieldItemProps; let indexPattern: IndexPattern; - let core: ReturnType; + let dataView: DataView; beforeEach(() => { indexPattern = { @@ -83,8 +110,6 @@ describe('IndexPattern Field Item', () => { ], } as IndexPattern; - core = coreMock.createSetup(); - core.http.post.mockClear(); defaultProps = { indexPattern, fieldFormats: { @@ -93,7 +118,7 @@ describe('IndexPattern Field Item', () => { convert: jest.fn((s: unknown) => JSON.stringify(s)), })), } as unknown as FieldFormatsStart, - core, + core: coreMock.createStart(), highlight: '', dateRange: { fromDate: 'now-7d', @@ -116,10 +141,19 @@ describe('IndexPattern Field Item', () => { hasSuggestionForField: () => false, uiActions: uiActionsPluginMock.createStartContract(), }; + + dataView = { + ...indexPattern, + getFormatterForField: defaultProps.fieldFormats.getDefaultInstance, + } as unknown as DataView; + + (mockedServices.dataViews.get as jest.Mock).mockImplementation(() => { + return Promise.resolve(dataView); + }); }); it('should display displayName of a field', () => { - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl(); // Using .toContain over .toEqual because this element includes text from // which can't be seen, but shows in the text content @@ -128,15 +162,12 @@ describe('IndexPattern Field Item', () => { ); }); - it('should render edit field button if callback is set', () => { - core.http.post.mockImplementation(() => { - return new Promise(() => {}); - }); + it('should render edit field button if callback is set', async () => { const editFieldSpy = jest.fn(); const wrapper = mountWithIntl( - + ); - clickField(wrapper, 'bytes'); + await clickField(wrapper, 'bytes'); wrapper.update(); const popoverContent = wrapper.find(EuiPopover).prop('children'); act(() => { @@ -148,20 +179,17 @@ describe('IndexPattern Field Item', () => { expect(editFieldSpy).toHaveBeenCalledWith('bytes'); }); - it('should not render edit field button for document field', () => { - core.http.post.mockImplementation(() => { - return new Promise(() => {}); - }); + it('should not render edit field button for document field', async () => { const editFieldSpy = jest.fn(); const wrapper = mountWithIntl( - ); - clickField(wrapper, documentField.name); + await clickField(wrapper, documentField.name); wrapper.update(); const popoverContent = wrapper.find(EuiPopover).prop('children'); expect( @@ -174,30 +202,33 @@ describe('IndexPattern Field Item', () => { it('should request field stats every time the button is clicked', async () => { let resolveFunction: (arg: unknown) => void; - core.http.post.mockImplementation(() => { + (loadFieldStats as jest.Mock).mockImplementation(() => { return new Promise((resolve) => { resolveFunction = resolve; }); }); - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl(); - clickField(wrapper, 'bytes'); + await clickField(wrapper, 'bytes'); - expect(core.http.post).toHaveBeenCalledWith(`/api/lens/index_stats/1/field`, { - body: JSON.stringify({ - dslQuery: { - bool: { - must: [], - filter: [], - should: [], - must_not: [], - }, + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalledWith({ + abortController: new AbortController(), + services: { data: mockedServices.data }, + dataView, + dslQuery: { + bool: { + must: [], + filter: [], + should: [], + must_not: [], }, - fromDate: 'now-7d', - toDate: 'now', - fieldName: 'bytes', - }), + }, + fromDate: 'now-7d', + toDate: 'now', + field: defaultProps.field, }); expect(wrapper.find(EuiPopover).prop('isOpen')).toEqual(true); @@ -218,12 +249,15 @@ describe('IndexPattern Field Item', () => { }); }); - wrapper.update(); + await wrapper.update(); expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0); - clickField(wrapper, 'bytes'); - expect(core.http.post).toHaveBeenCalledTimes(1); + await clickField(wrapper, 'bytes'); + + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalledTimes(1); act(() => { const closePopover = wrapper.find(EuiPopover).prop('closePopover'); @@ -231,6 +265,8 @@ describe('IndexPattern Field Item', () => { closePopover(); }); + await wrapper.update(); + expect(wrapper.find(EuiPopover).prop('isOpen')).toEqual(false); act(() => { @@ -248,49 +284,59 @@ describe('IndexPattern Field Item', () => { }); }); - clickField(wrapper, 'bytes'); - - expect(core.http.post).toHaveBeenCalledTimes(2); - expect(core.http.post).toHaveBeenLastCalledWith(`/api/lens/index_stats/1/field`, { - body: JSON.stringify({ - dslQuery: { - bool: { - must: [], - filter: [ - { - bool: { - should: [{ match_phrase: { 'geo.src': 'US' } }], - minimum_should_match: 1, - }, + await clickField(wrapper, 'bytes'); + + await wrapper.update(); + + expect(loadFieldStats).toHaveBeenCalledTimes(2); + expect(loadFieldStats).toHaveBeenLastCalledWith({ + abortController: new AbortController(), + services: { data: mockedServices.data }, + dataView, + dslQuery: { + bool: { + must: [], + filter: [ + { + bool: { + should: [{ match_phrase: { 'geo.src': 'US' } }], + minimum_should_match: 1, }, - { - match: { phrase: { 'geo.dest': 'US' } }, - }, - ], - should: [], - must_not: [], - }, + }, + { + match: { phrase: { 'geo.dest': 'US' } }, + }, + ], + should: [], + must_not: [], }, - fromDate: 'now-14d', - toDate: 'now-7d', - fieldName: 'bytes', - }), + }, + fromDate: 'now-14d', + toDate: 'now-7d', + field: defaultProps.field, }); + + (loadFieldStats as jest.Mock).mockReset(); + (loadFieldStats as jest.Mock).mockImplementation(() => Promise.resolve({})); }); it('should not request field stats for document field', async () => { - const wrapper = mountWithIntl(); + const wrapper = mountWithIntl( + + ); - clickField(wrapper, DOCUMENT_FIELD_NAME); + await clickField(wrapper, DOCUMENT_FIELD_NAME); - expect(core.http.post).not.toHaveBeenCalled(); + await wrapper.update(); + + expect(loadFieldStats).not.toHaveBeenCalled(); expect(wrapper.find(EuiPopover).prop('isOpen')).toEqual(true); expect(wrapper.find(EuiLoadingSpinner)).toHaveLength(0); }); it('should not request field stats for range fields', async () => { const wrapper = mountWithIntl( - { /> ); - await act(async () => { - clickField(wrapper, 'ip_range'); - }); + await clickField(wrapper, 'ip_range'); - expect(core.http.post).not.toHaveBeenCalled(); + expect(loadFieldStats).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index 1ec3c3b41ca40..427b8e4623353 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -8,49 +8,38 @@ import './field_item.scss'; import React, { useCallback, useState, useMemo } from 'react'; -import DateMath from '@kbn/datemath'; import { - EuiButtonGroup, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiIconTip, - EuiLoadingSpinner, EuiPopover, - EuiPopoverFooter, EuiPopoverTitle, - EuiProgress, + EuiPopoverFooter, EuiSpacer, EuiText, EuiTitle, EuiToolTip, } from '@elastic/eui'; -import { - Axis, - HistogramBarSeries, - Chart, - niceTimeFormatter, - Position, - ScaleType, - Settings, - TooltipType, -} from '@elastic/charts'; import { i18n } from '@kbn/i18n'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; import { FieldButton } from '@kbn/react-field'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { EuiHighlight } from '@elastic/eui'; -import { Filter, buildEsQuery, Query } from '@kbn/es-query'; -import { KBN_FIELD_TYPES, ES_FIELD_TYPES, getEsQueryConfig } from '@kbn/data-plugin/public'; +import { Filter, Query } from '@kbn/es-query'; +import { DataViewField } from '@kbn/data-views-plugin/common'; import { ChartsPluginSetup } from '@kbn/charts-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { FieldStats } from '@kbn/unified-field-list-plugin/public'; import { DragDrop, DragDropIdentifier } from '../drag_drop'; -import type { DatasourceDataPanelProps, DataType, IndexPattern, IndexPatternField } from '../types'; -import { BucketedAggregation, DOCUMENT_FIELD_NAME, FieldStatsResponse } from '../../common'; -import { DraggedField } from './types'; +import { DatasourceDataPanelProps, DataType } from '../types'; +import { DOCUMENT_FIELD_NAME } from '../../common'; +import type { IndexPattern, IndexPatternField } from '../types'; +import type { DraggedField } from './types'; import { LensFieldIcon } from '../shared_components/field_picker/lens_field_icon'; import { VisualizeGeoFieldButton } from './visualize_geo_field_button'; import { getVisualizeGeoFieldMessage } from '../utils'; - +import type { LensAppServices } from '../app_plugin/types'; import { debouncedComponent } from '../debounced_component'; export interface FieldItemProps { @@ -74,15 +63,6 @@ export interface FieldItemProps { uiActions: UiActionsStart; } -interface State { - isLoading: boolean; - totalDocuments?: number; - sampledDocuments?: number; - sampledValues?: number; - histogram?: BucketedAggregation; - topValues?: BucketedAggregation; -} - function wrapOnDot(str?: string) { // u200B is a non-width white-space character, which allows // the browser to efficiently word-wrap right after the dot @@ -92,14 +72,10 @@ function wrapOnDot(str?: string) { export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) { const { - core, field, indexPattern, highlight, exists, - query, - dateRange, - filters, hideDetails, itemIndex, groupIndex, @@ -140,54 +116,8 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) { [dropOntoWorkspace, setOpen] ); - const [state, setState] = useState({ - isLoading: false, - }); - - function fetchData() { - // Range types don't have any useful stats we can show - if ( - state.isLoading || - field.type === 'document' || - field.type.includes('range') || - field.type === 'geo_point' || - field.type === 'geo_shape' - ) { - return; - } - - setState((s) => ({ ...s, isLoading: true })); - - core.http - .post>(`/api/lens/index_stats/${indexPattern.id}/field`, { - body: JSON.stringify({ - dslQuery: buildEsQuery(indexPattern, query, filters, getEsQueryConfig(core.uiSettings)), - fromDate: dateRange.fromDate, - toDate: dateRange.toDate, - fieldName: field.name, - }), - }) - .then((results) => { - setState((s) => ({ - ...s, - isLoading: false, - totalDocuments: results.totalDocuments, - sampledDocuments: results.sampledDocuments, - sampledValues: results.sampledValues, - histogram: results.histogram, - topValues: results.topValues, - })); - }) - .catch(() => { - setState((s) => ({ ...s, isLoading: false })); - }); - } - function togglePopover() { setOpen(!infoIsOpen); - if (!infoIsOpen) { - fetchData(); - } } const onDragStart = useCallback(() => { @@ -281,13 +211,14 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) { panelClassName="lnsFieldItem__fieldPanel" initialFocus=".lnsFieldItem__fieldPanel" > - + {infoIsOpen && ( + + )} ); @@ -373,45 +304,22 @@ function FieldPanelHeader({ ); } -function FieldItemPopoverContents(props: State & FieldItemProps) { +function FieldItemPopoverContents(props: FieldItemProps) { const { - histogram, - topValues, + query, + filters, indexPattern, field, dateRange, - core, - sampledValues, - chartsThemeService, - fieldFormats, dropOntoWorkspace, editField, removeField, hasSuggestionForField, hideDetails, uiActions, + core, } = props; - - const chartTheme = chartsThemeService.useChartsTheme(); - const chartBaseTheme = chartsThemeService.useChartsBaseTheme(); - let histogramDefault = !!props.histogram; - - const totalValuesCount = - topValues && topValues.buckets.reduce((prev, bucket) => bucket.count + prev, 0); - const otherCount = sampledValues && totalValuesCount ? sampledValues - totalValuesCount : 0; - - if ( - totalValuesCount && - histogram && - histogram.buckets.length && - topValues && - topValues.buckets.length - ) { - // Default to histogram when top values are less than 10% of total - histogramDefault = otherCount / totalValuesCount > 0.9; - } - - const [showingHistogram, setShowingHistogram] = useState(histogramDefault); + const services = useKibana().services; const panelHeader = ( string }; - if (indexPattern.fieldFormatMap && indexPattern.fieldFormatMap[field.name]) { - const FormatType = fieldFormats.getType(indexPattern.fieldFormatMap[field.name].id as string); - if (FormatType) { - formatter = new FormatType( - indexPattern.fieldFormatMap[field.name].params, - core.uiSettings.get.bind(core.uiSettings) - ); - } else { - formatter = { convert: (data: unknown) => JSON.stringify(data) }; - } - } else { - formatter = fieldFormats.getDefaultInstance( - field.type as KBN_FIELD_TYPES, - field.esTypes as ES_FIELD_TYPES[] - ); - } - - const fromDate = DateMath.parse(dateRange.fromDate); - const toDate = DateMath.parse(dateRange.toDate); - - let title = <>; - - if (props.isLoading) { - return ( - <> - {panelHeader} - - - ); - } else if (field.type.includes('range')) { - return ( - <> - {panelHeader} - - - {i18n.translate('xpack.lens.indexPattern.fieldStatsLimited', { - defaultMessage: `Summary information is not available for range type fields.`, - })} - - - ); - } else if (field.type === 'murmur3') { - return ( - <> - {panelHeader} - - - {i18n.translate('xpack.lens.indexPattern.fieldStatsMurmur3Limited', { - defaultMessage: `Summary information is not available for murmur3 fields.`, - })} - - - ); - } else if (field.type === 'geo_point' || field.type === 'geo_shape') { - return ( - <> - {panelHeader} - - {getVisualizeGeoFieldMessage(field.type)} - - - - - ); - } else if ( - (!props.histogram || props.histogram.buckets.length === 0) && - (!props.topValues || props.topValues.buckets.length === 0) - ) { - const isUsingSampling = core.uiSettings.get('lens:useFieldExistenceSampling'); - return ( - <> - {panelHeader} + return ( + <> + {panelHeader} + {element}} + overrideMissingContent={(params) => { + if (field.type === 'geo_point' || field.type === 'geo_shape') { + return ( + <> + {getVisualizeGeoFieldMessage(field.type)} + + + + + ); + } - - {isUsingSampling - ? i18n.translate('xpack.lens.indexPattern.fieldStatsSamplingNoData', { - defaultMessage: - 'Lens is unable to create visualizations with this field because it does not contain data in the first 500 documents that match your filters. To create a visualization, drag and drop a different field.', - }) - : i18n.translate('xpack.lens.indexPattern.fieldStatsNoData', { - defaultMessage: - 'Lens is unable to create visualizations with this field because it does not contain data. To create a visualization, drag and drop a different field.', - })} - - - ); - } + if (params?.noDataFound) { + const isUsingSampling = core.uiSettings.get('lens:useFieldExistenceSampling'); + return ( + <> + + {isUsingSampling + ? i18n.translate('xpack.lens.indexPattern.fieldStatsSamplingNoData', { + defaultMessage: + 'Lens is unable to create visualizations with this field because it does not contain data in the first 500 documents that match your filters. To create a visualization, drag and drop a different field.', + }) + : i18n.translate('xpack.lens.indexPattern.fieldStatsNoData', { + defaultMessage: + 'Lens is unable to create visualizations with this field because it does not contain data. To create a visualization, drag and drop a different field.', + })} + + + ); + } - if (histogram && histogram.buckets.length && topValues && topValues.buckets.length) { - title = ( - { - setShowingHistogram(optionId === 'histogram'); + return null; }} - idSelected={showingHistogram ? 'histogram' : 'topValues'} /> - ); - } else if (field.type === 'date') { - title = ( - -
- {i18n.translate('xpack.lens.indexPattern.fieldTimeDistributionLabel', { - defaultMessage: 'Time distribution', - })} -
-
- ); - } else if (topValues && topValues.buckets.length) { - title = ( - -
- {i18n.translate('xpack.lens.indexPattern.fieldTopValuesLabel', { - defaultMessage: 'Top values', - })} -
-
- ); - } - - function wrapInPopover(el: React.ReactElement) { - return ( - <> - {panelHeader} - - {title ? title : <>} - - - - {el} - - {props.totalDocuments ? ( - - - {props.sampledDocuments && ( - <> - {i18n.translate('xpack.lens.indexPattern.percentageOfLabel', { - defaultMessage: '{percentage}% of', - values: { - percentage: Math.round((props.sampledDocuments / props.totalDocuments) * 100), - }, - })} - - )}{' '} - - {fieldFormats - .getDefaultInstance(KBN_FIELD_TYPES.NUMBER, [ES_FIELD_TYPES.INTEGER]) - .convert(props.totalDocuments)} - {' '} - {i18n.translate('xpack.lens.indexPattern.ofDocumentsLabel', { - defaultMessage: 'documents', - })} - - - ) : ( - <> - )} - - ); - } - - if (histogram && histogram.buckets.length) { - const specId = i18n.translate('xpack.lens.indexPattern.fieldStatsCountLabel', { - defaultMessage: 'Count', - }); - - if (field.type === 'date') { - return wrapInPopover( - - - - - - - - ); - } else if (showingHistogram || !topValues || !topValues.buckets.length) { - return wrapInPopover( - - - - formatter.convert(d)} - /> - - - - ); - } - } - - if (props.topValues && props.topValues.buckets.length) { - const digitsRequired = props.topValues.buckets.some( - (topValue) => !Number.isInteger(topValue.count / props.sampledValues!) - ); - return wrapInPopover( -
- {props.topValues.buckets.map((topValue) => { - const formatted = formatter.convert(topValue.key); - return ( -
- - - {formatted === '' ? ( - - - {i18n.translate('xpack.lens.indexPattern.fieldPanelEmptyStringValue', { - defaultMessage: 'Empty string', - })} - - - ) : ( - - - {formatted} - - - )} - - - - {(Math.round((topValue.count / props.sampledValues!) * 1000) / 10).toFixed( - digitsRequired ? 1 : 0 - )} - % - - - - - -
- ); - })} - {otherCount ? ( - <> - - - - {i18n.translate('xpack.lens.indexPattern.otherDocsLabel', { - defaultMessage: 'Other', - })} - - - - - - {(Math.round((otherCount / props.sampledValues!) * 1000) / 10).toFixed( - digitsRequired ? 1 : 0 - )} - % - - - - - - - ) : ( - <> - )} -
- ); - } - return <>; + + ); } const DragToWorkspaceButton = ({ diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index a2ab9fd238215..74f006a0c3174 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -248,17 +248,27 @@ export function getIndexPatternDatasource({ render( - + + + , domElement @@ -586,7 +596,14 @@ export function getIndexPatternDatasource({ .filter(([_, layer]) => !!indexPatterns[layer.indexPatternId]) .map(([layerId, layer]) => ( - getErrorMessages(layer, indexPatterns[layer.indexPatternId], state, layerId, core) ?? [] + getErrorMessages( + layer, + indexPatterns[layer.indexPatternId], + state, + layerId, + core, + data + ) ?? [] ).map((message) => ({ shortMessage: '', // Not displayed currently longMessage: typeof message === 'string' ? message : message.message, 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 9a5abf8b79633..4a4364be1835d 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 @@ -325,6 +325,7 @@ interface BaseOperationDefinitionProps< fixAction?: { label: string; newState: ( + data: DataPublicPluginStart, core: CoreStart, frame: FrameDatasourceAPI, layerId: string @@ -552,6 +553,7 @@ interface FieldBasedOperationDefinition undefined, - }, - http: { - post: jest.fn(() => - Promise.resolve({ - topValues: { - buckets: [ - { - key: 'A', - }, - { - key: 'B', - }, - ], +jest.mock('@kbn/unified-field-list-plugin/public/services/field_stats', () => ({ + loadFieldStats: jest.fn().mockResolvedValue({ + topValues: { + buckets: [ + { + key: 'A', }, - }) - ), - }, -} as unknown as CoreStart; + { + key: 'B', + }, + ], + }, + }), +})); + +const indexPattern = createMockedIndexPattern(); +const dataMock = dataPluginMock.createStartContract(); +const coreMock = corePluginMock.createStart(); function getStringBasedOperationColumn( field = 'source', @@ -214,6 +210,7 @@ describe('getDisallowedTermsMessage()', () => { indexPattern )!.fixAction.newState; const newLayer = await fixAction( + dataMock, coreMock, { query: { language: 'kuery', query: 'a: b' }, @@ -261,6 +258,7 @@ describe('getDisallowedTermsMessage()', () => { indexPattern )!.fixAction.newState; const newLayer = await fixAction( + dataMock, coreMock, { query: { language: 'kuery', query: 'a: b' }, @@ -302,6 +300,7 @@ describe('getDisallowedTermsMessage()', () => { indexPattern )!.fixAction.newState; const newLayer = await fixAction( + dataMock, coreMock, { query: { language: 'kuery', query: 'a: b' }, @@ -342,6 +341,7 @@ describe('getDisallowedTermsMessage()', () => { indexPattern )!.fixAction.newState; const newLayer = await fixAction( + dataMock, coreMock, { query: { language: 'kuery', query: 'a: b' }, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/helpers.ts index a290c2d239a1e..6dec5e3aef6cf 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/helpers.ts @@ -9,12 +9,12 @@ import { i18n } from '@kbn/i18n'; import { uniq } from 'lodash'; import type { CoreStart } from '@kbn/core/public'; import { buildEsQuery } from '@kbn/es-query'; -import { getEsQueryConfig } from '@kbn/data-plugin/public'; +import { getEsQueryConfig, DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { FieldStatsResponse, loadFieldStats } from '@kbn/unified-field-list-plugin/public'; import { GenericIndexPatternColumn, operationDefinitionMap } from '..'; import { defaultLabel } from '../filters'; import { isReferenced } from '../../layer_helpers'; -import type { FieldStatsResponse } from '../../../../../common'; import type { FrameDatasourceAPI, IndexPattern, IndexPatternField } from '../../../../types'; import type { FiltersIndexPatternColumn } from '..'; import type { TermsIndexPatternColumn } from './types'; @@ -109,7 +109,12 @@ export function getDisallowedTermsMessage( label: i18n.translate('xpack.lens.indexPattern.termsWithMultipleShiftsFixActionLabel', { defaultMessage: 'Use filters', }), - newState: async (core: CoreStart, frame: FrameDatasourceAPI, layerId: string) => { + newState: async ( + data: DataPublicPluginStart, + core: CoreStart, + frame: FrameDatasourceAPI, + layerId: string + ) => { const currentColumn = layer.columns[columnId] as TermsIndexPatternColumn; const fieldNames = [ currentColumn.sourceField, @@ -133,23 +138,21 @@ export function getDisallowedTermsMessage( ); if (!activeDataFieldNameMatch || currentTerms.length === 0) { if (fieldNames.length === 1) { - const response: FieldStatsResponse = await core.http.post( - `/api/lens/index_stats/${indexPattern.id}/field`, - { - body: JSON.stringify({ - fieldName: fieldNames[0], - dslQuery: buildEsQuery( - indexPattern, - frame.query, - frame.filters, - getEsQueryConfig(core.uiSettings) - ), - fromDate: frame.dateRange.fromDate, - toDate: frame.dateRange.toDate, - size: currentColumn.params.size, - }), - } - ); + const currentDataView = await data.dataViews.get(indexPattern.id); + const response: FieldStatsResponse = await loadFieldStats({ + services: { data }, + dataView: currentDataView, + field: indexPattern.getFieldByName(fieldNames[0])!, + dslQuery: buildEsQuery( + indexPattern, + frame.query, + frame.filters, + getEsQueryConfig(core.uiSettings) + ), + fromDate: frame.dateRange.fromDate, + toDate: frame.dateRange.toDate, + size: currentColumn.params.size, + }); currentTerms = response.topValues?.buckets.map(({ key }) => String(key)) || []; } } 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 407abc0203493..8c3b7f90d57d3 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 @@ -9,17 +9,13 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { shallow, mount } from 'enzyme'; import { EuiButtonGroup, EuiComboBox, EuiFieldNumber, EuiSelect, EuiSwitch } from '@elastic/eui'; -import type { - IUiSettingsClient, - SavedObjectsClientContract, - HttpSetup, - CoreStart, -} from '@kbn/core/public'; +import type { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from '@kbn/core/public'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import { coreMock as corePluginMock } from '@kbn/core/public/mocks'; import { createMockedIndexPattern } from '../../../mocks'; import { ValuesInput } from './values_input'; import type { TermsIndexPatternColumn } from '.'; @@ -39,6 +35,21 @@ import { IndexPattern } from '../../../../types'; import { cloneDeep } from 'lodash'; import { IncludeExcludeRow } from './include_exclude_options'; +jest.mock('@kbn/unified-field-list-plugin/public/services/field_stats', () => ({ + loadFieldStats: jest.fn().mockResolvedValue({ + topValues: { + buckets: [ + { + key: 'A', + }, + { + key: 'B', + }, + ], + }, + }), +})); + // mocking random id generator function jest.mock('@elastic/eui', () => { const original = jest.requireActual('@elastic/eui'); @@ -2772,29 +2783,10 @@ describe('terms', () => { const fixAction = ( typeof errorMessage === 'object' ? errorMessage.fixAction!.newState : undefined )!; - const coreMock = { - uiSettings: { - get: () => undefined, - }, - http: { - post: jest.fn(() => - Promise.resolve({ - topValues: { - buckets: [ - { - key: 'A', - }, - { - key: 'B', - }, - ], - }, - }) - ), - }, - } as unknown as CoreStart; + const dataMock = dataPluginMock.createStartContract(); const newLayer = await fixAction( - coreMock, + dataMock, + corePluginMock.createStart(), { query: { language: 'kuery', query: 'a: b' }, filters: [], 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 a865a1de16a77..9006cf0f2cc9c 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 @@ -39,6 +39,9 @@ import { import { TinymathAST } from '@kbn/tinymath'; import { CoreStart } from '@kbn/core/public'; import { IndexPattern } from '../../types'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; + +const dataMock = dataPluginMock.createStartContract(); jest.mock('.'); jest.mock('../../id_generator'); @@ -3043,7 +3046,8 @@ describe('state_helpers', () => { indexPattern, {}, '1', - {} + {}, + dataMock ); expect(mock).toHaveBeenCalled(); expect(errors).toHaveLength(1); @@ -3069,7 +3073,8 @@ describe('state_helpers', () => { indexPattern, {} as IndexPatternPrivateState, '1', - {} as CoreStart + {} as CoreStart, + dataMock ); expect(mock).toHaveBeenCalled(); expect(errors).toHaveLength(1); @@ -3104,7 +3109,8 @@ describe('state_helpers', () => { indexPattern, {} as IndexPatternPrivateState, '1', - {} as CoreStart + {} as CoreStart, + dataMock ); expect(notCalledMock).not.toHaveBeenCalled(); expect(mock).toHaveBeenCalledTimes(1); @@ -3140,7 +3146,8 @@ describe('state_helpers', () => { indexPattern, {} as IndexPatternPrivateState, '1', - {} as CoreStart + {} as CoreStart, + dataMock ); expect(savedRef).toHaveBeenCalled(); expect(incompleteRef).not.toHaveBeenCalled(); @@ -3169,7 +3176,8 @@ describe('state_helpers', () => { indexPattern, {} as IndexPatternPrivateState, '1', - {} as CoreStart + {} as CoreStart, + dataMock ); expect(mock).toHaveBeenCalledWith( { 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 634ed490e11cc..04860408b822e 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 @@ -9,6 +9,7 @@ import { partition, mapValues, pickBy, isArray } from 'lodash'; import { CoreStart } from '@kbn/core/public'; import type { Query } from '@kbn/es-query'; import memoizeOne from 'memoize-one'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { VisualizeEditorLayersContext } from '@kbn/visualizations-plugin/public'; import type { DatasourceFixAction, @@ -1375,7 +1376,8 @@ export function getErrorMessages( indexPattern: IndexPattern, state: IndexPatternPrivateState, layerId: string, - core: CoreStart + core: CoreStart, + data: DataPublicPluginStart ): | Array< | string @@ -1417,7 +1419,7 @@ export function getErrorMessages( ...state, layers: { ...state.layers, - [layerId]: await errorMessage.fixAction!.newState(core, frame, layerId), + [layerId]: await errorMessage.fixAction!.newState(data, core, frame, layerId), }, }), } diff --git a/x-pack/plugins/lens/public/mocks/services_mock.tsx b/x-pack/plugins/lens/public/mocks/services_mock.tsx index e9d0c7cd14f28..8c323e7e071fa 100644 --- a/x-pack/plugins/lens/public/mocks/services_mock.tsx +++ b/x-pack/plugins/lens/public/mocks/services_mock.tsx @@ -16,6 +16,7 @@ import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; import { dashboardPluginMock } from '@kbn/dashboard-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; +import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { @@ -158,6 +159,7 @@ export function makeDefaultServices( clear: jest.fn(), }, spaces: spacesPluginMock.createStartContract(), + charts: chartPluginMock.createSetupContract(), dataViewFieldEditor: indexPatternFieldEditorPluginMock.createStartContract(), dataViewEditor: indexPatternEditorPluginMock.createStartContract(), }; diff --git a/x-pack/plugins/lens/server/routes/index.ts b/x-pack/plugins/lens/server/routes/index.ts index bb6986cd7d2d2..c8145cd54b9a0 100644 --- a/x-pack/plugins/lens/server/routes/index.ts +++ b/x-pack/plugins/lens/server/routes/index.ts @@ -8,9 +8,7 @@ import { CoreSetup, Logger } from '@kbn/core/server'; import { PluginStartContract } from '../plugin'; import { existingFieldsRoute } from './existing_fields'; -import { initFieldsRoute } from './field_stats'; export function setupRoutes(setup: CoreSetup, logger: Logger) { existingFieldsRoute(setup, logger); - initFieldsRoute(setup); } diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index 9f548139a47d6..e29e0d1cb86b4 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -38,6 +38,7 @@ { "path": "../../../src/plugins/data_view_editor/tsconfig.json"}, { "path": "../../../src/plugins/event_annotation/tsconfig.json"}, { "path": "../../../src/plugins/chart_expressions/expression_xy/tsconfig.json"}, - { "path": "../../../src/plugins/unified_search/tsconfig.json" } + { "path": "../../../src/plugins/unified_search/tsconfig.json" }, + { "path": "../../../src/plugins/unified_field_list/tsconfig.json" } ] } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 71160ce17bb14..0273a23d4179f 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -17071,7 +17071,6 @@ "xpack.lens.indexPattern.overallMaxOf": "Max général de {name}", "xpack.lens.indexPattern.overallMinOf": "Min général de {name}", "xpack.lens.indexPattern.overallSumOf": "Somme générale de {name}", - "xpack.lens.indexPattern.percentageOfLabel": "{percentage} % de", "xpack.lens.indexPattern.percentileOf": "{percentile, selectordinal, one {#er} two {#e} few {#e} other {#e}} centile de {name}", "xpack.lens.indexPattern.percentileRanksOf": "Rang centile ({value}) de {name}", "xpack.lens.indexPattern.pinnedTopValuesLabel": "Filtres de {field}", @@ -17469,21 +17468,13 @@ "xpack.lens.indexPattern.existenceErrorLabel": "Impossible de charger les informations de champ", "xpack.lens.indexPattern.existenceTimeoutAriaLabel": "La récupération de l'existence a expiré", "xpack.lens.indexPattern.existenceTimeoutLabel": "Les informations de champ ont pris trop de temps", - "xpack.lens.indexPattern.fieldDistributionLabel": "Distribution", "xpack.lens.indexPattern.fieldItem.visualizeGeoFieldLinkText": "Visualiser dans Maps", "xpack.lens.indexPattern.fieldItemTooltip": "Effectuez un glisser-déposer pour visualiser.", - "xpack.lens.indexPattern.fieldPanelEmptyStringValue": "Chaîne vide", "xpack.lens.indexPattern.fieldPlaceholder": "Champ", "xpack.lens.indexPattern.fieldStatsButtonEmptyLabel": "Ce champ ne comporte aucune donnée mais vous pouvez toujours effectuer un glisser-déposer pour visualiser.", "xpack.lens.indexPattern.fieldStatsButtonLabel": "Cliquez pour obtenir un aperçu du champ, ou effectuez un glisser-déposer pour visualiser.", - "xpack.lens.indexPattern.fieldStatsCountLabel": "Compte", - "xpack.lens.indexPattern.fieldStatsDisplayToggle": "Basculer soit", - "xpack.lens.indexPattern.fieldStatsLimited": "Le résumé des informations n'est pas disponible pour les champs de type de gamme.", - "xpack.lens.indexPattern.fieldStatsMurmur3Limited": "Le résumé des informations n'est pas disponible pour les champs murmur3.", "xpack.lens.indexPattern.fieldStatsNoData": "Lens ne peut pas créer de visualisation avec ce champ, car il ne contient pas de données. Pour créer une visualisation, glissez-déposez un autre champ.", "xpack.lens.indexPattern.fieldStatsSamplingNoData": "Lens ne peut pas créer de visualisation avec ce champ, car il ne contient aucune donnée dans les 500 premiers documents correspondant aux filtres. Pour créer une visualisation, glissez-déposez un autre champ.", - "xpack.lens.indexPattern.fieldTimeDistributionLabel": "Répartition du temps", - "xpack.lens.indexPattern.fieldTopValuesLabel": "Valeurs les plus élevées", "xpack.lens.indexPattern.filterBy.clickToEdit": "Cliquer pour modifier", "xpack.lens.indexPattern.filterBy.emptyFilterQuery": "(vide)", "xpack.lens.indexPattern.filterBy.label": "Filtrer par", @@ -17546,8 +17537,6 @@ "xpack.lens.indexPattern.nonDefaultTimeFieldError": "\"Explorer les données dans Discover\" ne prend pas en charge les histogrammes de date sur les champs temporels autres que les champs par défaut si le champ temporel est défini dans la vue de données.", "xpack.lens.indexPattern.noRealMetricError": "Un calque uniquement doté de valeurs statiques n’affichera pas de résultats ; utilisez au moins un indicateur dynamique.", "xpack.lens.indexPattern.numberFormatLabel": "Nombre", - "xpack.lens.indexPattern.ofDocumentsLabel": "documents", - "xpack.lens.indexPattern.otherDocsLabel": "Autre", "xpack.lens.indexPattern.overall_metric": "indicateur : nombre", "xpack.lens.indexPattern.overallMax": "Max général", "xpack.lens.indexPattern.overallMin": "Min général", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b04c00e3f4230..556e8facd1534 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -17054,7 +17054,6 @@ "xpack.lens.indexPattern.overallMaxOf": "{name}の全体最大値", "xpack.lens.indexPattern.overallMinOf": "{name}の全体最小値", "xpack.lens.indexPattern.overallSumOf": "{name}の全体平方和", - "xpack.lens.indexPattern.percentageOfLabel": "{percentage}% の", "xpack.lens.indexPattern.percentileOf": "{name}の{percentile, selectordinal, other {#}}パーセンタイル", "xpack.lens.indexPattern.percentileRanksOf": "{name}のパーセンタイルランク({value})", "xpack.lens.indexPattern.pinnedTopValuesLabel": "{field}のフィルター", @@ -17454,21 +17453,13 @@ "xpack.lens.indexPattern.existenceErrorLabel": "フィールド情報を読み込めません", "xpack.lens.indexPattern.existenceTimeoutAriaLabel": "存在の取り込みがタイムアウトしました", "xpack.lens.indexPattern.existenceTimeoutLabel": "フィールド情報に時間がかかりすぎました", - "xpack.lens.indexPattern.fieldDistributionLabel": "分布", "xpack.lens.indexPattern.fieldItem.visualizeGeoFieldLinkText": "Mapsで可視化", "xpack.lens.indexPattern.fieldItemTooltip": "可視化するには、ドラッグアンドドロップします。", - "xpack.lens.indexPattern.fieldPanelEmptyStringValue": "空の文字列", "xpack.lens.indexPattern.fieldPlaceholder": "フィールド", "xpack.lens.indexPattern.fieldStatsButtonEmptyLabel": "このフィールドにはデータがありませんが、ドラッグアンドドロップで可視化できます。", "xpack.lens.indexPattern.fieldStatsButtonLabel": "フィールドプレビューを表示するには、クリックします。可視化するには、ドラッグアンドドロップします。", - "xpack.lens.indexPattern.fieldStatsCountLabel": "カウント", - "xpack.lens.indexPattern.fieldStatsDisplayToggle": "次のどちらかを切り替えます:", - "xpack.lens.indexPattern.fieldStatsLimited": "範囲タイプフィールドの概要情報がありません。", - "xpack.lens.indexPattern.fieldStatsMurmur3Limited": "murmur3フィールドの概要情報がありません。", "xpack.lens.indexPattern.fieldStatsNoData": "Lensはこのフィールドのビジュアライゼーションを作成できません。フィールドにデータがありません。ビジュアライゼーションを作成するには、別のフィールドをドラッグします。", "xpack.lens.indexPattern.fieldStatsSamplingNoData": "Lensはこのフィールドのビジュアライゼーションを作成できません。フィルターと一致する最初の500件のドキュメントではフィールドにデータがありません。ビジュアライゼーションを作成するには、別のフィールドをドラッグします。", - "xpack.lens.indexPattern.fieldTimeDistributionLabel": "時間分布", - "xpack.lens.indexPattern.fieldTopValuesLabel": "トップの値", "xpack.lens.indexPattern.filterBy.clickToEdit": "クリックして編集", "xpack.lens.indexPattern.filterBy.emptyFilterQuery": "(空)", "xpack.lens.indexPattern.filterBy.label": "フィルタリング条件", @@ -17531,8 +17522,6 @@ "xpack.lens.indexPattern.nonDefaultTimeFieldError": "「Discoverでデータを探索」は、時間フィールドがデータビューで設定されていない場合、非デフォルト時間フィールドで日付ヒストグラムをサポートしません", "xpack.lens.indexPattern.noRealMetricError": "静的値のみのレイヤーには結果が表示されません。1つ以上の動的メトリックを使用してください", "xpack.lens.indexPattern.numberFormatLabel": "数字", - "xpack.lens.indexPattern.ofDocumentsLabel": "ドキュメント", - "xpack.lens.indexPattern.otherDocsLabel": "その他", "xpack.lens.indexPattern.overall_metric": "メトリック:数値", "xpack.lens.indexPattern.overallMax": "全体最高", "xpack.lens.indexPattern.overallMin": "全体最低", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3c6f15a198fdd..258ac5023fa9b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -17076,7 +17076,6 @@ "xpack.lens.indexPattern.overallMaxOf": "{name} 的总体最大值", "xpack.lens.indexPattern.overallMinOf": "{name} 的总体最小值", "xpack.lens.indexPattern.overallSumOf": "{name} 的总和", - "xpack.lens.indexPattern.percentageOfLabel": "{percentage}% 的", "xpack.lens.indexPattern.percentileOf": "{name} 的{percentile, selectordinal, one {第一个} two {第二个} few {第三个} other {第 #th 个}}百分位数", "xpack.lens.indexPattern.percentileRanksOf": "{name} 的百分位等级 ({value})", "xpack.lens.indexPattern.pinnedTopValuesLabel": "{field} 的筛选", @@ -17476,21 +17475,13 @@ "xpack.lens.indexPattern.existenceErrorLabel": "无法加载字段信息", "xpack.lens.indexPattern.existenceTimeoutAriaLabel": "现有内容提取超时", "xpack.lens.indexPattern.existenceTimeoutLabel": "字段信息花费时间过久", - "xpack.lens.indexPattern.fieldDistributionLabel": "分布", "xpack.lens.indexPattern.fieldItem.visualizeGeoFieldLinkText": "在 Maps 中可视化", "xpack.lens.indexPattern.fieldItemTooltip": "拖放以可视化。", - "xpack.lens.indexPattern.fieldPanelEmptyStringValue": "空字符串", "xpack.lens.indexPattern.fieldPlaceholder": "字段", "xpack.lens.indexPattern.fieldStatsButtonEmptyLabel": "此字段不包含任何数据,但您仍然可以拖放以进行可视化。", "xpack.lens.indexPattern.fieldStatsButtonLabel": "单击以进行字段预览,或拖放以进行可视化。", - "xpack.lens.indexPattern.fieldStatsCountLabel": "计数", - "xpack.lens.indexPattern.fieldStatsDisplayToggle": "切换", - "xpack.lens.indexPattern.fieldStatsLimited": "摘要信息不适用于范围类型字段。", - "xpack.lens.indexPattern.fieldStatsMurmur3Limited": "摘要信息不适用于 murmur3 字段。", "xpack.lens.indexPattern.fieldStatsNoData": "Lens 无法使用此字段创建可视化,因为其中未包含数据。要创建可视化,请拖放其他字段。", "xpack.lens.indexPattern.fieldStatsSamplingNoData": "Lens 无法使用此字段创建可视化,因为其中未包含与您的筛选匹配的前 500 个文档中的数据。要创建可视化,请拖放其他字段。", - "xpack.lens.indexPattern.fieldTimeDistributionLabel": "时间分布", - "xpack.lens.indexPattern.fieldTopValuesLabel": "排名最前值", "xpack.lens.indexPattern.filterBy.clickToEdit": "单击以编辑", "xpack.lens.indexPattern.filterBy.emptyFilterQuery": "(空)", "xpack.lens.indexPattern.filterBy.label": "筛选依据", @@ -17553,8 +17544,6 @@ "xpack.lens.indexPattern.nonDefaultTimeFieldError": "如果在数据视图上设置了时间字段,则“在 Discover 中浏览数据”不支持非默认时间字段上的日期直方图", "xpack.lens.indexPattern.noRealMetricError": "仅包含静态值的图层将不显示结果,请至少使用一个动态指标", "xpack.lens.indexPattern.numberFormatLabel": "数字", - "xpack.lens.indexPattern.ofDocumentsLabel": "文档", - "xpack.lens.indexPattern.otherDocsLabel": "其他", "xpack.lens.indexPattern.overall_metric": "指标:数字", "xpack.lens.indexPattern.overallMax": "总体最大值", "xpack.lens.indexPattern.overallMin": "总体最小值", diff --git a/x-pack/test/api_integration/apis/lens/index.ts b/x-pack/test/api_integration/apis/lens/index.ts index 8d74ad475511f..90774a2db35ed 100644 --- a/x-pack/test/api_integration/apis/lens/index.ts +++ b/x-pack/test/api_integration/apis/lens/index.ts @@ -11,6 +11,5 @@ export default function lensApiIntegrationTests({ loadTestFile }: FtrProviderCon describe('Lens', () => { loadTestFile(require.resolve('./existing_fields')); loadTestFile(require.resolve('./legacy_existing_fields')); - loadTestFile(require.resolve('./field_stats')); }); } From ac0688b90f7a58718bf18d1f6b93ebaa26fd8029 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 23 Aug 2022 10:38:22 +0200 Subject: [PATCH 08/41] [Files] Create files example plugin (#139019) * created files example stub * implementing whimsical design * added base64d image * updated files client and example plugin to work end-to-end with browser * added file deletion funcitonality * added codeowners entry * refactor downloadSrc to getDownloadHref * react-query -> @tanstack/react-query Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 1 + tsconfig.base.json | 2 + x-pack/examples/files_example/.i18nrc.json | 7 + x-pack/examples/files_example/README.md | 4 + x-pack/examples/files_example/common/index.ts | 28 +++ x-pack/examples/files_example/kibana.json | 14 ++ .../files_example/public/application.tsx | 30 ++++ .../public/assets/image.png.base64 | 1 + .../files_example/public/components/app.tsx | 169 ++++++++++++++++++ .../public/components/confirm_button.tsx | 49 +++++ .../public/components/details_flyout.tsx | 100 +++++++++++ x-pack/examples/files_example/public/index.ts | 14 ++ .../examples/files_example/public/plugin.ts | 47 +++++ x-pack/examples/files_example/public/types.ts | 25 +++ x-pack/examples/files_example/server/index.ts | 16 ++ .../examples/files_example/server/plugin.ts | 35 ++++ x-pack/examples/files_example/server/types.ts | 16 ++ x-pack/examples/files_example/tsconfig.json | 25 +++ x-pack/plugins/files/common/api_routes.ts | 2 +- x-pack/plugins/files/common/types.ts | 2 + .../files/public/files_client/files_client.ts | 19 +- x-pack/plugins/files/public/index.ts | 4 +- x-pack/plugins/files/public/types.ts | 17 +- .../files/server/routes/file_kind/upload.ts | 3 + 24 files changed, 620 insertions(+), 10 deletions(-) create mode 100644 x-pack/examples/files_example/.i18nrc.json create mode 100644 x-pack/examples/files_example/README.md create mode 100644 x-pack/examples/files_example/common/index.ts create mode 100644 x-pack/examples/files_example/kibana.json create mode 100644 x-pack/examples/files_example/public/application.tsx create mode 100644 x-pack/examples/files_example/public/assets/image.png.base64 create mode 100644 x-pack/examples/files_example/public/components/app.tsx create mode 100644 x-pack/examples/files_example/public/components/confirm_button.tsx create mode 100644 x-pack/examples/files_example/public/components/details_flyout.tsx create mode 100644 x-pack/examples/files_example/public/index.ts create mode 100644 x-pack/examples/files_example/public/plugin.ts create mode 100644 x-pack/examples/files_example/public/types.ts create mode 100644 x-pack/examples/files_example/server/index.ts create mode 100644 x-pack/examples/files_example/server/plugin.ts create mode 100644 x-pack/examples/files_example/server/types.ts create mode 100644 x-pack/examples/files_example/tsconfig.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e7f0933161b66..e6777e5e69f29 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -92,6 +92,7 @@ /x-pack/test/search_sessions_integration/ @elastic/kibana-app-services /src/plugins/dashboard/public/application/embeddable/viewport/print_media @elastic/kibana-app-services x-pack/plugins/files @elastic/kibana-app-services +x-pack/examples/files_example @elastic/kibana-app-services ### Observability Plugins diff --git a/tsconfig.base.json b/tsconfig.base.json index c6f6366bc3f84..22aeada1359fa 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -275,6 +275,8 @@ "@kbn/embedded-lens-example-plugin/*": ["x-pack/examples/embedded_lens_example/*"], "@kbn/exploratory-view-example-plugin": ["x-pack/examples/exploratory_view_example"], "@kbn/exploratory-view-example-plugin/*": ["x-pack/examples/exploratory_view_example/*"], + "@kbn/files-example-plugin": ["x-pack/examples/files_example"], + "@kbn/files-example-plugin/*": ["x-pack/examples/files_example/*"], "@kbn/reporting-example-plugin": ["x-pack/examples/reporting_example"], "@kbn/reporting-example-plugin/*": ["x-pack/examples/reporting_example/*"], "@kbn/screenshotting-example-plugin": ["x-pack/examples/screenshotting_example"], diff --git a/x-pack/examples/files_example/.i18nrc.json b/x-pack/examples/files_example/.i18nrc.json new file mode 100644 index 0000000000000..79fdf5a24917c --- /dev/null +++ b/x-pack/examples/files_example/.i18nrc.json @@ -0,0 +1,7 @@ +{ + "prefix": "filesExample", + "paths": { + "filesExample": "." + }, + "translations": ["translations/ja-JP.json"] +} diff --git a/x-pack/examples/files_example/README.md b/x-pack/examples/files_example/README.md new file mode 100644 index 0000000000000..6db1391df5873 --- /dev/null +++ b/x-pack/examples/files_example/README.md @@ -0,0 +1,4 @@ +# filesExample + +An example plugin that integrates with the Kibana "files" plugin. + diff --git a/x-pack/examples/files_example/common/index.ts b/x-pack/examples/files_example/common/index.ts new file mode 100644 index 0000000000000..a58065ad7fd98 --- /dev/null +++ b/x-pack/examples/files_example/common/index.ts @@ -0,0 +1,28 @@ +/* + * 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 { FileKind } from '@kbn/files-plugin/common'; + +export const PLUGIN_ID = 'filesExample'; +export const PLUGIN_NAME = 'filesExample'; + +const httpTags = { + tags: [`access:${PLUGIN_ID}`], +}; + +export const exampleFileKind: FileKind = { + id: 'filesExample', + http: { + create: httpTags, + delete: httpTags, + download: httpTags, + getById: httpTags, + list: httpTags, + share: httpTags, + update: httpTags, + }, +}; diff --git a/x-pack/examples/files_example/kibana.json b/x-pack/examples/files_example/kibana.json new file mode 100644 index 0000000000000..5df1141929c41 --- /dev/null +++ b/x-pack/examples/files_example/kibana.json @@ -0,0 +1,14 @@ +{ + "id": "filesExample", + "version": "1.0.0", + "kibanaVersion": "kibana", + "owner": { + "name": "kibana-app-services", + "githubTeam": "kibana-app-services" + }, + "description": "Example plugin integrating with files plugin", + "server": true, + "ui": true, + "requiredPlugins": ["files"], + "optionalPlugins": [] +} diff --git a/x-pack/examples/files_example/public/application.tsx b/x-pack/examples/files_example/public/application.tsx new file mode 100644 index 0000000000000..7f599ded82b6f --- /dev/null +++ b/x-pack/examples/files_example/public/application.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { AppMountParameters, CoreStart } from '@kbn/core/public'; +import { AppPluginStartDependencies } from './types'; +import { FilesExampleApp } from './components/app'; + +const queryClient = new QueryClient(); + +export const renderApp = ( + { notifications }: CoreStart, + { files }: AppPluginStartDependencies, + { element }: AppMountParameters +) => { + ReactDOM.render( + + + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/x-pack/examples/files_example/public/assets/image.png.base64 b/x-pack/examples/files_example/public/assets/image.png.base64 new file mode 100644 index 0000000000000..e85f2ccf1626e --- /dev/null +++ b/x-pack/examples/files_example/public/assets/image.png.base64 @@ -0,0 +1 @@ +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 diff --git a/x-pack/examples/files_example/public/components/app.tsx b/x-pack/examples/files_example/public/components/app.tsx new file mode 100644 index 0000000000000..f25494bf3e3ba --- /dev/null +++ b/x-pack/examples/files_example/public/components/app.tsx @@ -0,0 +1,169 @@ +/* + * 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, { useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; +import type { FileJSON } from '@kbn/files-plugin/common'; +import type { FilesClientResponses } from '@kbn/files-plugin/public'; + +const names = ['foo', 'bar', 'baz']; + +import { + EuiPageTemplate, + EuiInMemoryTable, + EuiInMemoryTableProps, + EuiButton, + EuiIcon, + EuiButtonIcon, + EuiLink, +} from '@elastic/eui'; + +import { CoreStart } from '@kbn/core/public'; +import { DetailsFlyout } from './details_flyout'; +import type { FileClients } from '../types'; +import { ConfirmButtonIcon } from './confirm_button'; +// @ts-ignore +import imageBase64 from '!!raw-loader!../assets/image.png.base64'; + +interface FilesExampleAppDeps { + files: FileClients; + notifications: CoreStart['notifications']; +} + +type ListResponse = FilesClientResponses['list']; + +export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) => { + const { data, isLoading, error, refetch } = useQuery(['files'], () => + files.example.list() + ); + const [isUploadingImage, setIsUploadingImage] = useState(false); + const [isDeletingFile, setIsDeletingFile] = useState(false); + const [selectedItem, setSelectedItem] = useState(); + + const uploadImage = async () => { + try { + setIsUploadingImage(true); + const { file } = await files.example.create({ + name: names[Math.floor(Math.random() * names.length)], + alt: 'My image', + meta: { myValue: 'test' }, + mimeType: 'image/png', + }); + await refetch(); + const blob = new Blob([Uint8Array.from(atob(imageBase64), (c) => c.charCodeAt(0))], { + type: 'image/png', + }); + await files.example.upload({ id: file.id, body: blob }); + await refetch(); + notifications.toasts.addSuccess('Sucessfully uploaded image'); + } finally { + setIsUploadingImage(false); + } + }; + + const renderToolsRight = () => { + return [ + + Upload image + , + ]; + }; + + const items = [...(data?.files ?? [])].reverse(); + + const columns: EuiInMemoryTableProps['columns'] = [ + { + field: 'name', + name: 'Name', + render: (name, item) => setSelectedItem(item)}>{name}, + }, + { + field: 'status', + name: 'Status', + render: (status: FileJSON['status']) => + status === 'READY' ? ( + + ) : status === 'AWAITING_UPLOAD' ? ( + + ) : ( + + ), + }, + { + name: 'Actions', + actions: [ + { + name: 'View', + description: 'View file', + isPrimary: true, + render: (item) => ( + setSelectedItem(item)} + /> + ), + }, + { + name: 'Delete', + description: 'Delete this file', + render: (item) => ( + { + try { + setIsDeletingFile(true); + await files.example.delete({ id: item.id }); + await refetch(); + } finally { + setIsDeletingFile(false); + } + }} + /> + ), + }, + ], + }, + ]; + + return ( + <> + + + + {selectedItem && ( + setSelectedItem(undefined)} + /> + )} + + ); +}; diff --git a/x-pack/examples/files_example/public/components/confirm_button.tsx b/x-pack/examples/files_example/public/components/confirm_button.tsx new file mode 100644 index 0000000000000..05e64243bb374 --- /dev/null +++ b/x-pack/examples/files_example/public/components/confirm_button.tsx @@ -0,0 +1,49 @@ +/* + * 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, { useState, FunctionComponent } from 'react'; +import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; + +interface Props { + label: string; + confirmationText: string; + onConfirm: () => void; + disabled: boolean; +} + +export const ConfirmButtonIcon: FunctionComponent = ({ + label, + confirmationText, + onConfirm, + disabled, +}) => { + const [showConfirm, setShowConfirm] = useState(false); + + return showConfirm ? ( + + + + ) : ( + void }) => { + e.stopPropagation(); + setShowConfirm(true); + setTimeout(() => setShowConfirm(false), 3000); + }} + /> + ); +}; diff --git a/x-pack/examples/files_example/public/components/details_flyout.tsx b/x-pack/examples/files_example/public/components/details_flyout.tsx new file mode 100644 index 0000000000000..64db3fc851006 --- /dev/null +++ b/x-pack/examples/files_example/public/components/details_flyout.tsx @@ -0,0 +1,100 @@ +/* + * 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 moment from 'moment'; +import type { FunctionComponent } from 'react'; +import React from 'react'; +import { css } from '@emotion/react'; +import { + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiButton, + EuiTitle, + EuiDescriptionList, + EuiSpacer, +} from '@elastic/eui'; +import type { FileJSON } from '@kbn/files-plugin/common'; +import { FileClients } from '../types'; + +interface Props { + file: FileJSON; + files: FileClients; + onDismiss: () => void; +} + +export const DetailsFlyout: FunctionComponent = ({ files, file, onDismiss }) => { + return ( + + + +

{file.name}

+
+
+ + + + {file.alt + + + + + + Download + + + + + Close + + + + +
+ ); +}; diff --git a/x-pack/examples/files_example/public/index.ts b/x-pack/examples/files_example/public/index.ts new file mode 100644 index 0000000000000..15e472c4f4cc6 --- /dev/null +++ b/x-pack/examples/files_example/public/index.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. + */ + +import { FilesExamplePlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. +export function plugin() { + return new FilesExamplePlugin(); +} diff --git a/x-pack/examples/files_example/public/plugin.ts b/x-pack/examples/files_example/public/plugin.ts new file mode 100644 index 0000000000000..ad41c3ce2d44a --- /dev/null +++ b/x-pack/examples/files_example/public/plugin.ts @@ -0,0 +1,47 @@ +/* + * 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 { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { PLUGIN_ID, PLUGIN_NAME, exampleFileKind } from '../common'; +import { FilesExamplePluginsStart, FilesExamplePluginsSetup } from './types'; + +export class FilesExamplePlugin + implements Plugin +{ + public setup(core: CoreSetup) { + // Register an application into the side navigation menu + core.application.register({ + id: PLUGIN_ID, + title: PLUGIN_NAME, + async mount(params: AppMountParameters) { + // Load application bundle + const { renderApp } = await import('./application'); + // Get start services as specified in kibana.json + const [coreStart, { files }] = await core.getStartServices(); + // Render the application + return renderApp( + coreStart, + { + files: { + example: files.filesClientFactory.asScoped(exampleFileKind.id), + }, + }, + params + ); + }, + }); + + // Return methods that should be available to other plugins + return {}; + } + + public start(core: CoreStart) { + return {}; + } + + public stop() {} +} diff --git a/x-pack/examples/files_example/public/types.ts b/x-pack/examples/files_example/public/types.ts new file mode 100644 index 0000000000000..2d450fbdad111 --- /dev/null +++ b/x-pack/examples/files_example/public/types.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FilesSetup, FilesStart, FilesClient } from '@kbn/files-plugin/public'; + +export interface FilesExamplePluginsSetup { + files: FilesSetup; +} + +export interface FilesExamplePluginsStart { + files: FilesStart; +} + +export interface FileClients { + // Example file kind + example: FilesClient; +} + +export interface AppPluginStartDependencies { + files: FileClients; +} diff --git a/x-pack/examples/files_example/server/index.ts b/x-pack/examples/files_example/server/index.ts new file mode 100644 index 0000000000000..5b6de87308e5e --- /dev/null +++ b/x-pack/examples/files_example/server/index.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 { PluginInitializerContext } from '@kbn/core/server'; +import { FilesExamplePlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. + +export function plugin(initializerContext: PluginInitializerContext) { + return new FilesExamplePlugin(initializerContext); +} diff --git a/x-pack/examples/files_example/server/plugin.ts b/x-pack/examples/files_example/server/plugin.ts new file mode 100644 index 0000000000000..2b077d6f3e88a --- /dev/null +++ b/x-pack/examples/files_example/server/plugin.ts @@ -0,0 +1,35 @@ +/* + * 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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; +import { exampleFileKind } from '../common'; +import type { FilesExamplePluginsSetup, FilesExamplePluginsStart } from './types'; + +export class FilesExamplePlugin + implements Plugin +{ + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup, { files }: FilesExamplePluginsSetup) { + this.logger.debug('filesExample: Setup'); + + files.registerFileKind(exampleFileKind); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('filesExample: Started'); + return {}; + } + + public stop() {} +} diff --git a/x-pack/examples/files_example/server/types.ts b/x-pack/examples/files_example/server/types.ts new file mode 100644 index 0000000000000..b1cef58620ca5 --- /dev/null +++ b/x-pack/examples/files_example/server/types.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 type { FilesSetup, FilesStart } from '@kbn/files-plugin/server'; + +export interface FilesExamplePluginsSetup { + files: FilesSetup; +} + +export interface FilesExamplePluginsStart { + files: FilesStart; +} diff --git a/x-pack/examples/files_example/tsconfig.json b/x-pack/examples/files_example/tsconfig.json new file mode 100644 index 0000000000000..caeb25650a142 --- /dev/null +++ b/x-pack/examples/files_example/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./target/types" + }, + "include": [ + "index.ts", + "common/**/*", + "public/**/*", + "server/**/*", + "public/**/*.ts", + "public/**/*.tsx", + "server/**/*.ts", + "../../../typings/**/*" + ], + "exclude": [], + "references": [ + { + "path": "../../../src/core/tsconfig.json" + }, + { + "path": "../../plugins/files/tsconfig.json" + } + ] +} diff --git a/x-pack/plugins/files/common/api_routes.ts b/x-pack/plugins/files/common/api_routes.ts index f3647edaf83f0..9eb6671465799 100644 --- a/x-pack/plugins/files/common/api_routes.ts +++ b/x-pack/plugins/files/common/api_routes.ts @@ -99,7 +99,7 @@ export type UpdateFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< export type UploadFileKindHttpEndpoint = HttpApiInterfaceEntryDefinition< { id: string }, unknown, - any, + { body: unknown }, { ok: true; size: number; diff --git a/x-pack/plugins/files/common/types.ts b/x-pack/plugins/files/common/types.ts index d3c8795fc7321..4c8e03497fa3b 100644 --- a/x-pack/plugins/files/common/types.ts +++ b/x-pack/plugins/files/common/types.ts @@ -440,6 +440,8 @@ export interface FileKind { id: string; /** * Maximum size, in bytes, a file of this kind can be. + * + * @default 4MiB */ maxSizeBytes?: number; diff --git a/x-pack/plugins/files/public/files_client/files_client.ts b/x-pack/plugins/files/public/files_client/files_client.ts index 3abd6c935541c..2f01405ee1492 100644 --- a/x-pack/plugins/files/public/files_client/files_client.ts +++ b/x-pack/plugins/files/public/files_client/files_client.ts @@ -77,7 +77,7 @@ const commonBodyHeaders = { }; export const createFilesClient = ({ http, fileKind }: Args): FilesClient => { - return { + const api: FilesClient = { create: (args) => { return http.post(apiRoutes.getCreateFileRoute(fileKind), { headers: commonBodyHeaders, @@ -88,13 +88,15 @@ export const createFilesClient = ({ http, fileKind }: Args): FilesClient => { return http.delete(apiRoutes.getDeleteRoute(fileKind, args.id)); }, download: (args) => { - return http.get(apiRoutes.getDownloadRoute(fileKind, args.id, args.fileName)); + return http.get(apiRoutes.getDownloadRoute(fileKind, args.id, args.fileName), { + headers: { Accept: '*/*' }, + }); }, getById: (args) => { return http.get(apiRoutes.getByIdRoute(fileKind, args.id)); }, - list: ({ page, perPage }) => { - return http.get(apiRoutes.getListRoute(fileKind, page, perPage)); + list(args = {}) { + return http.get(apiRoutes.getListRoute(fileKind, args.page, args.perPage)); }, update: ({ id, ...body }) => { return http.patch(apiRoutes.getUpdateRoute(fileKind, id), { @@ -105,9 +107,10 @@ export const createFilesClient = ({ http, fileKind }: Args): FilesClient => { upload: (args) => { return http.put(apiRoutes.getUploadRoute(fileKind, args.id), { headers: { - 'content-type': 'application/octet-stream', + 'Content-Type': 'application/octet-stream', }, - body: args.body, + + body: args.body as BodyInit, }); }, share: ({ fileId, name, validUntil }) => { @@ -137,5 +140,9 @@ export const createFilesClient = ({ http, fileKind }: Args): FilesClient => { publicDownload: ({ token, fileName }) => { return http.get(apiRoutes.getPublicDownloadRoute(token, fileName)); }, + getDownloadHref: ({ id }) => { + return `${http.basePath.prepend(apiRoutes.getDownloadRoute(fileKind, id))}`; + }, }; + return api; }; diff --git a/x-pack/plugins/files/public/index.ts b/x-pack/plugins/files/public/index.ts index 4b707aaa3b6a2..36a570c209683 100644 --- a/x-pack/plugins/files/public/index.ts +++ b/x-pack/plugins/files/public/index.ts @@ -6,8 +6,8 @@ */ import { FilesPlugin } from './plugin'; - -export type { FilesClient, FilesClientFactory } from './types'; +export type { FilesSetup, FilesStart } from './plugin'; +export type { FilesClient, FilesClientFactory, FilesClientResponses } from './types'; export function plugin() { return new FilesPlugin(); diff --git a/x-pack/plugins/files/public/types.ts b/x-pack/plugins/files/public/types.ts index 24a3125213020..3a52b863bc7e4 100644 --- a/x-pack/plugins/files/public/types.ts +++ b/x-pack/plugins/files/public/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { FileJSON } from '../common'; import type { FindFilesHttpEndpoint, FileShareHttpEndpoint, @@ -30,6 +31,10 @@ type ClientMethodFrom = ( args: E['inputs']['body'] & E['inputs']['params'] & E['inputs']['query'] ) => Promise; +type ClientMethodOptionalArgsFrom = ( + args?: E['inputs']['body'] & E['inputs']['params'] & E['inputs']['query'] +) => Promise; + /** * A client that can be used to manage a specific {@link FileKind}. */ @@ -57,7 +62,7 @@ export interface FilesClient { * * @param args - list files args */ - list: ClientMethodFrom; + list: ClientMethodOptionalArgsFrom; /** * Find a set of files given some filters. * @@ -123,8 +128,18 @@ export interface FilesClient { * @param args - Get public download arguments. */ publicDownload: ClientMethodFrom; + + /** + * Get a string for downloading a file that can be passed to a button element's + * href for download. + */ + getDownloadHref: (file: FileJSON) => string; } +export type FilesClientResponses = { + [K in keyof FilesClient]: Awaited>; +}; + /** * A factory for creating a {@link FilesClient} */ diff --git a/x-pack/plugins/files/server/routes/file_kind/upload.ts b/x-pack/plugins/files/server/routes/file_kind/upload.ts index dc6e8e7f4b268..c563cddad4877 100644 --- a/x-pack/plugins/files/server/routes/file_kind/upload.ts +++ b/x-pack/plugins/files/server/routes/file_kind/upload.ts @@ -54,6 +54,8 @@ export const handler: FileKindsRequestHandler = async ( return res.ok({ body }); }; +const fourMiB = 4 * 1024 * 1024; + export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { if (fileKind.http.create) { fileKindRouter[method]( @@ -69,6 +71,7 @@ export function register(fileKindRouter: FileKindRouter, fileKind: FileKind) { output: 'stream', parse: false, accepts: fileKind.allowedMimeTypes ?? 'application/octet-stream', + maxBytes: fileKind.maxSizeBytes ?? fourMiB, }, }, }, From 1a70f6fd376bc0d64f408acfbe46dae2f1fca5a5 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 23 Aug 2022 10:53:55 +0200 Subject: [PATCH 09/41] [Discover] Support storing time with saved searches (#138377) * [Discover] Implement UI for storing time with a saved search * [Discover] Save time range data with a saved search * [Discover] Improve updating of values * [Discover] Restore time range after loading a saved search * [Discover] Add time range validation * [Discover] Add refresh interval validation * [Discover] Update how saved search gets restored * [Discover] Improve tests * [Discover] Update tests * [Discover] Improve type imports * [Discover] Update copy * [Discover] Fix types after the merge * [Discover] Update test name * [Discover] Fix types * [Discover] Update mapping * [Discover] Update mapping * Explicitly set field limit for .kibana_ esArchives Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Rudolf Meijering --- .../components/top_nav/on_save_search.tsx | 46 +++++++- .../application/main/discover_main_route.tsx | 9 +- .../main/hooks/use_discover_state.ts | 7 ++ .../main/utils/persist_saved_search.ts | 14 +++ .../main/utils/validate_time_range.ts | 6 +- .../restore_from_saved_search.test.ts | 101 ++++++++++++++++++ .../restore_from_saved_search.ts | 34 ++++++ .../public/utils/validate_time.test.ts | 38 +++++++ .../discover/public/utils/validate_time.ts | 30 ++++++ .../saved_searches/get_saved_searches.test.ts | 6 ++ .../save_saved_searches.test.ts | 2 + .../saved_searches_utils.test.ts | 6 ++ .../saved_searches/saved_searches_utils.ts | 6 ++ .../public/services/saved_searches/types.ts | 13 ++- .../server/saved_objects/search.ts | 15 +++ .../deprecations_service/mappings.json | 5 +- .../export_transform/mappings.json | 5 +- .../hidden_saved_objects/mappings.json | 5 +- .../nested_export_transform/mappings.json | 5 +- .../visible_in_management/mappings.json | 5 +- .../saved_objects/spaces/mappings.json | 5 +- .../saved_objects/spaces/mappings.json | 5 +- 22 files changed, 351 insertions(+), 17 deletions(-) create mode 100644 src/plugins/discover/public/services/saved_searches/restore_from_saved_search.test.ts create mode 100644 src/plugins/discover/public/services/saved_searches/restore_from_saved_search.ts create mode 100644 src/plugins/discover/public/utils/validate_time.test.ts create mode 100644 src/plugins/discover/public/utils/validate_time.ts diff --git a/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx b/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx index 9f0c1f9552f2c..e99295fee9e97 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/on_save_search.tsx @@ -6,8 +6,10 @@ * Side Public License, v 1. */ -import React from 'react'; +import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; +import { EuiFormRow, EuiSwitch } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { SavedObjectSaveModal, showSaveModal, OnSaveProps } from '@kbn/saved-objects-plugin/public'; import { DataView } from '@kbn/data-views-plugin/public'; import { SavedSearch, SaveSavedSearchOptions } from '@kbn/saved-search-plugin/public'; @@ -108,20 +110,24 @@ export async function onSaveSearch({ const onSave = async ({ newTitle, newCopyOnSave, + newTimeRestore, newDescription, isTitleDuplicateConfirmed, onTitleDuplicate, }: { newTitle: string; + newTimeRestore: boolean; newCopyOnSave: boolean; newDescription: string; isTitleDuplicateConfirmed: boolean; onTitleDuplicate: () => void; }) => { const currentTitle = savedSearch.title; + const currentTimeRestore = savedSearch.timeRestore; const currentRowsPerPage = savedSearch.rowsPerPage; savedSearch.title = newTitle; savedSearch.description = newDescription; + savedSearch.timeRestore = newTimeRestore; savedSearch.rowsPerPage = uiSettings.get(DOC_TABLE_LEGACY) ? currentRowsPerPage : state.appStateContainer.getState().rowsPerPage; @@ -143,6 +149,7 @@ export async function onSaveSearch({ // If the save wasn't successful, put the original values back. if (!response.id || response.error) { savedSearch.title = currentTitle; + savedSearch.timeRestore = currentTimeRestore; savedSearch.rowsPerPage = currentRowsPerPage; } else { state.resetInitialAppState(); @@ -156,6 +163,7 @@ export async function onSaveSearch({ title={savedSearch.title ?? ''} showCopyOnSave={!!savedSearch.id} description={savedSearch.description} + timeRestore={savedSearch.timeRestore} onSave={onSave} onClose={onClose ?? (() => {})} /> @@ -167,13 +175,42 @@ const SaveSearchObjectModal: React.FC<{ title: string; showCopyOnSave: boolean; description?: string; - onSave: (props: OnSaveProps & { newRowsPerPage?: number }) => void; + timeRestore?: boolean; + onSave: (props: OnSaveProps & { newTimeRestore: boolean }) => void; onClose: () => void; -}> = ({ title, description, showCopyOnSave, onSave, onClose }) => { +}> = ({ title, description, showCopyOnSave, timeRestore: savedTimeRestore, onSave, onClose }) => { + const [timeRestore, setTimeRestore] = useState(savedTimeRestore || false); + const onModalSave = (params: OnSaveProps) => { - onSave(params); + onSave({ + ...params, + newTimeRestore: timeRestore, + }); }; + const options = ( + + } + > + setTimeRestore(event.target.checked)} + label={ + + } + /> + + ); + return ( diff --git a/src/plugins/discover/public/application/main/discover_main_route.tsx b/src/plugins/discover/public/application/main/discover_main_route.tsx index cec20f64d82b2..e8e1ec43bd42d 100644 --- a/src/plugins/discover/public/application/main/discover_main_route.tsx +++ b/src/plugins/discover/public/application/main/discover_main_route.tsx @@ -32,6 +32,7 @@ import { LoadingIndicator } from '../../components/common/loading_indicator'; import { DiscoverError } from '../../components/common/error_alert'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { getUrlTracker } from '../../kibana_services'; +import { restoreStateFromSavedSearch } from '../../services/saved_searches/restore_from_saved_search'; const DiscoverMainAppMemoized = memo(DiscoverMainApp); @@ -129,6 +130,11 @@ export function DiscoverMainRoute(props: Props) { currentSavedSearch.searchSource.setField('index', currentDataView); } + restoreStateFromSavedSearch({ + savedSearch: currentSavedSearch, + timefilter: services.timefilter, + }); + setSavedSearch(currentSavedSearch); if (currentSavedSearch.id) { @@ -163,8 +169,9 @@ export function DiscoverMainRoute(props: Props) { } }, [ id, - services.data.search, + services.data, services.spaces, + services.timefilter, core.savedObjects.client, core.application.navigateToApp, core.theme, 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 b5cf634ebe3a0..e74454247d5d1 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 @@ -34,6 +34,7 @@ import { FetchStatus } from '../../types'; import { getDataViewAppState } from '../utils/get_switch_data_view_app_state'; import { SortPairArr } from '../../../components/doc_table/utils/get_sort'; import { DataTableRecord } from '../../../types'; +import { restoreStateFromSavedSearch } from '../../../services/saved_searches/restore_from_saved_search'; const MAX_NUM_OF_COLUMNS = 50; @@ -193,6 +194,12 @@ export function useDiscoverState({ savedSearch: newSavedSearch, storage, }); + + restoreStateFromSavedSearch({ + savedSearch: newSavedSearch, + timefilter: services.timefilter, + }); + await stateContainer.replaceUrlAppState(newAppState); setState(newAppState); }, diff --git a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts index 691a8a6604194..434514721faab 100644 --- a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts +++ b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts @@ -69,6 +69,20 @@ export async function persistSavedSearch( savedSearch.isTextBasedQuery = isTextBasedQuery; } + const { from, to } = services.timefilter.getTime(); + const refreshInterval = services.timefilter.getRefreshInterval(); + savedSearch.timeRange = + savedSearch.timeRestore || savedSearch.timeRange + ? { + from, + to, + } + : undefined; + savedSearch.refreshInterval = + savedSearch.timeRestore || savedSearch.refreshInterval + ? { value: refreshInterval.value, pause: refreshInterval.pause } + : undefined; + try { const id = await saveSavedSearch(savedSearch, saveOptions, services.core.savedObjects.client); if (id) { diff --git a/src/plugins/discover/public/application/main/utils/validate_time_range.ts b/src/plugins/discover/public/application/main/utils/validate_time_range.ts index 83d5f18de7f95..65748bbd75ce9 100644 --- a/src/plugins/discover/public/application/main/utils/validate_time_range.ts +++ b/src/plugins/discover/public/application/main/utils/validate_time_range.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import dateMath from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; import { ToastsStart } from '@kbn/core/public'; +import { isTimeRangeValid } from '../../../utils/validate_time'; /** * Validates a given time filter range, provided by URL or UI @@ -18,9 +18,7 @@ export function validateTimeRange( { from, to }: { from: string; to: string }, toastNotifications: ToastsStart ): boolean { - const fromMoment = dateMath.parse(from); - const toMoment = dateMath.parse(to); - if (!fromMoment || !toMoment || !fromMoment.isValid() || !toMoment.isValid()) { + if (!isTimeRangeValid({ from, to })) { toastNotifications.addDanger({ title: i18n.translate('discover.notifications.invalidTimeRangeTitle', { defaultMessage: `Invalid time range`, diff --git a/src/plugins/discover/public/services/saved_searches/restore_from_saved_search.test.ts b/src/plugins/discover/public/services/saved_searches/restore_from_saved_search.test.ts new file mode 100644 index 0000000000000..355f80b78b2ac --- /dev/null +++ b/src/plugins/discover/public/services/saved_searches/restore_from_saved_search.test.ts @@ -0,0 +1,101 @@ +/* + * 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 { TimefilterContract } from '@kbn/data-plugin/public'; +import type { TimeRange, RefreshInterval } from '@kbn/data-plugin/common'; +import type { SavedSearch } from '@kbn/saved-search-plugin/public'; +import { restoreStateFromSavedSearch } from './restore_from_saved_search'; + +describe('discover restore state from saved search', () => { + let timefilterMock: TimefilterContract; + const timeRange: TimeRange = { + from: 'now-30m', + to: 'now', + }; + const refreshInterval: RefreshInterval = { + value: 5000, + pause: false, + }; + + beforeEach(() => { + timefilterMock = { + setTime: jest.fn(), + setRefreshInterval: jest.fn(), + } as unknown as TimefilterContract; + }); + + test('should not update timefilter if attributes are not set', async () => { + restoreStateFromSavedSearch({ + savedSearch: {} as SavedSearch, + timefilter: timefilterMock, + }); + + expect(timefilterMock.setTime).not.toHaveBeenCalled(); + expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled(); + }); + + test('should not update timefilter if timeRestore is disabled', async () => { + restoreStateFromSavedSearch({ + savedSearch: { + timeRestore: false, + timeRange, + refreshInterval, + } as SavedSearch, + timefilter: timefilterMock, + }); + + expect(timefilterMock.setTime).not.toHaveBeenCalled(); + expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled(); + }); + + test('should update timefilter if timeRestore is enabled', async () => { + restoreStateFromSavedSearch({ + savedSearch: { + timeRestore: true, + timeRange, + refreshInterval, + } as SavedSearch, + timefilter: timefilterMock, + }); + + expect(timefilterMock.setTime).toHaveBeenCalledWith(timeRange); + expect(timefilterMock.setRefreshInterval).toHaveBeenCalledWith(refreshInterval); + }); + + test('should not update timefilter if attributes are missing', async () => { + restoreStateFromSavedSearch({ + savedSearch: { + timeRestore: true, + } as SavedSearch, + timefilter: timefilterMock, + }); + + expect(timefilterMock.setTime).not.toHaveBeenCalled(); + expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled(); + }); + + test('should not update timefilter if attributes are invalid', async () => { + restoreStateFromSavedSearch({ + savedSearch: { + timeRestore: true, + timeRange: { + from: 'test', + to: 'now', + }, + refreshInterval: { + pause: false, + value: -500, + }, + } as SavedSearch, + timefilter: timefilterMock, + }); + + expect(timefilterMock.setTime).not.toHaveBeenCalled(); + expect(timefilterMock.setRefreshInterval).not.toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/discover/public/services/saved_searches/restore_from_saved_search.ts b/src/plugins/discover/public/services/saved_searches/restore_from_saved_search.ts new file mode 100644 index 0000000000000..550c36408977b --- /dev/null +++ b/src/plugins/discover/public/services/saved_searches/restore_from_saved_search.ts @@ -0,0 +1,34 @@ +/* + * 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 { TimefilterContract } from '@kbn/data-plugin/public'; +import type { SavedSearch } from '@kbn/saved-search-plugin/public'; +import { isRefreshIntervalValid, isTimeRangeValid } from '../../utils/validate_time'; + +export const restoreStateFromSavedSearch = ({ + savedSearch, + timefilter, +}: { + savedSearch: SavedSearch; + timefilter: TimefilterContract; +}) => { + if (!savedSearch) { + return; + } + + if (savedSearch.timeRestore && savedSearch.timeRange && isTimeRangeValid(savedSearch.timeRange)) { + timefilter.setTime(savedSearch.timeRange); + } + if ( + savedSearch.timeRestore && + savedSearch.refreshInterval && + isRefreshIntervalValid(savedSearch.refreshInterval) + ) { + timefilter.setRefreshInterval(savedSearch.refreshInterval); + } +}; diff --git a/src/plugins/discover/public/utils/validate_time.test.ts b/src/plugins/discover/public/utils/validate_time.test.ts new file mode 100644 index 0000000000000..771c2a7bb029f --- /dev/null +++ b/src/plugins/discover/public/utils/validate_time.test.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 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 { RefreshInterval, TimeRange } from '@kbn/data-plugin/common'; +import { isTimeRangeValid, isRefreshIntervalValid } from './validate_time'; + +describe('discover validate time', () => { + test('should validate time ranges correctly', async () => { + expect(isTimeRangeValid({ from: '2020-06-02T13:36:13.689Z', to: 'now' })).toEqual(true); + expect(isTimeRangeValid({ from: 'now', to: 'now+1h' })).toEqual(true); + expect(isTimeRangeValid({ from: '', to: '' })).toEqual(false); + expect(isTimeRangeValid({} as unknown as TimeRange)).toEqual(false); + expect(isTimeRangeValid(undefined)).toEqual(false); + }); + + test('should validate that refresh interval is valid', async () => { + expect(isRefreshIntervalValid({ value: 5000, pause: false })).toEqual(true); + expect(isRefreshIntervalValid({ value: 0, pause: false })).toEqual(true); + expect(isRefreshIntervalValid({ value: 4000, pause: true })).toEqual(true); + }); + + test('should validate that refresh interval is invalid', async () => { + expect(isRefreshIntervalValid({ value: -5000, pause: false })).toEqual(false); + expect( + isRefreshIntervalValid({ value: 'test', pause: false } as unknown as RefreshInterval) + ).toEqual(false); + expect( + isRefreshIntervalValid({ value: 4000, pause: 'test' } as unknown as RefreshInterval) + ).toEqual(false); + expect(isRefreshIntervalValid({} as unknown as RefreshInterval)).toEqual(false); + expect(isRefreshIntervalValid(undefined)).toEqual(false); + }); +}); diff --git a/src/plugins/discover/public/utils/validate_time.ts b/src/plugins/discover/public/utils/validate_time.ts new file mode 100644 index 0000000000000..a6ad44e2112c6 --- /dev/null +++ b/src/plugins/discover/public/utils/validate_time.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 dateMath from '@kbn/datemath'; +import type { RefreshInterval } from '@kbn/data-plugin/common'; + +export function isTimeRangeValid(timeRange?: { from: string; to: string }): boolean { + if (!timeRange?.from || !timeRange?.to) { + return false; + } + const fromMoment = dateMath.parse(timeRange.from); + const toMoment = dateMath.parse(timeRange.to); + return Boolean(fromMoment && toMoment && fromMoment.isValid() && toMoment.isValid()); +} + +export function isRefreshIntervalValid(refreshInterval?: RefreshInterval): boolean { + if (!refreshInterval) { + return false; + } + return ( + typeof refreshInterval?.value === 'number' && + refreshInterval?.value >= 0 && + typeof refreshInterval?.pause === 'boolean' + ); +} diff --git a/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts index 8ff4f6c1e9428..397f3c11990eb 100644 --- a/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts +++ b/src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts @@ -105,6 +105,7 @@ describe('getSavedSearch', () => { "hideChart": false, "id": "ccf1af80-2297-11ec-86e0-1155ffb9c7a7", "isTextBasedQuery": undefined, + "refreshInterval": undefined, "rowHeight": undefined, "rowsPerPage": undefined, "searchSource": Object { @@ -145,6 +146,8 @@ describe('getSavedSearch', () => { "desc", ], ], + "timeRange": undefined, + "timeRestore": undefined, "title": "test1", "viewMode": undefined, } @@ -198,6 +201,7 @@ describe('getSavedSearch', () => { "hideChart": true, "id": "ccf1af80-2297-11ec-86e0-1155ffb9c7a7", "isTextBasedQuery": true, + "refreshInterval": undefined, "rowHeight": undefined, "rowsPerPage": undefined, "searchSource": Object { @@ -238,6 +242,8 @@ describe('getSavedSearch', () => { "desc", ], ], + "timeRange": undefined, + "timeRestore": undefined, "title": "test2", "viewMode": undefined, } diff --git a/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.test.ts b/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.test.ts index 0c88b2bcea94a..56b988b20121c 100644 --- a/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.test.ts +++ b/src/plugins/saved_search/public/services/saved_searches/save_saved_searches.test.ts @@ -92,6 +92,7 @@ describe('saveSavedSearch', () => { kibanaSavedObjectMeta: { searchSourceJSON: '{}' }, sort: [], title: 'title', + timeRestore: false, }, { references: [] } ); @@ -112,6 +113,7 @@ describe('saveSavedSearch', () => { kibanaSavedObjectMeta: { searchSourceJSON: '{}' }, sort: [], title: 'title', + timeRestore: false, }, { references: [] } ); diff --git a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts index 84a6c35de0c02..a6926aef50796 100644 --- a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts +++ b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.test.ts @@ -43,6 +43,7 @@ describe('saved_searches_utils', () => { "hideChart": true, "id": "id", "isTextBasedQuery": false, + "refreshInterval": undefined, "rowHeight": undefined, "rowsPerPage": undefined, "searchSource": SearchSource { @@ -66,6 +67,8 @@ describe('saved_searches_utils', () => { }, "sharingSavedObjectProps": Object {}, "sort": Array [], + "timeRange": undefined, + "timeRestore": undefined, "title": "saved search", "viewMode": undefined, } @@ -123,6 +126,7 @@ describe('saved_searches_utils', () => { "kibanaSavedObjectMeta": Object { "searchSourceJSON": "{}", }, + "refreshInterval": undefined, "rowHeight": undefined, "rowsPerPage": undefined, "sort": Array [ @@ -131,6 +135,8 @@ describe('saved_searches_utils', () => { "asc", ], ], + "timeRange": undefined, + "timeRestore": false, "title": "title", "viewMode": undefined, } diff --git a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts index cb20b24287943..52c25783c0e50 100644 --- a/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts +++ b/src/plugins/saved_search/public/services/saved_searches/saved_searches_utils.ts @@ -43,6 +43,9 @@ export const fromSavedSearchAttributes = ( hideAggregatedPreview: attributes.hideAggregatedPreview, rowHeight: attributes.rowHeight, isTextBasedQuery: attributes.isTextBasedQuery, + timeRestore: attributes.timeRestore, + timeRange: attributes.timeRange, + refreshInterval: attributes.refreshInterval, rowsPerPage: attributes.rowsPerPage, }); @@ -61,5 +64,8 @@ export const toSavedSearchAttributes = ( hideAggregatedPreview: savedSearch.hideAggregatedPreview, rowHeight: savedSearch.rowHeight, isTextBasedQuery: savedSearch.isTextBasedQuery ?? false, + timeRestore: savedSearch.timeRestore ?? false, + timeRange: savedSearch.timeRange, + refreshInterval: savedSearch.refreshInterval, rowsPerPage: savedSearch.rowsPerPage, }); diff --git a/src/plugins/saved_search/public/services/saved_searches/types.ts b/src/plugins/saved_search/public/services/saved_searches/types.ts index e0c1e8be4a3ed..acd745374e265 100644 --- a/src/plugins/saved_search/public/services/saved_searches/types.ts +++ b/src/plugins/saved_search/public/services/saved_searches/types.ts @@ -7,7 +7,7 @@ */ import type { ResolvedSimpleSavedObject } from '@kbn/core/public'; -import type { ISearchSource } from '@kbn/data-plugin/public'; +import type { ISearchSource, RefreshInterval, TimeRange } from '@kbn/data-plugin/common'; export enum VIEW_MODE { DOCUMENT_LEVEL = 'documents', @@ -39,6 +39,11 @@ export interface SavedSearchAttributes { viewMode?: VIEW_MODE; hideAggregatedPreview?: boolean; rowHeight?: number; + + timeRestore?: boolean; + timeRange?: TimeRange; + refreshInterval?: RefreshInterval; + rowsPerPage?: number; } @@ -67,5 +72,11 @@ export interface SavedSearch { hideAggregatedPreview?: boolean; rowHeight?: number; isTextBasedQuery?: boolean; + + // for restoring time range with a saved search + timeRestore?: boolean; + timeRange?: TimeRange; + refreshInterval?: RefreshInterval; + rowsPerPage?: number; } diff --git a/src/plugins/saved_search/server/saved_objects/search.ts b/src/plugins/saved_search/server/saved_objects/search.ts index 85f6542f6b07d..dec1c852aee20 100644 --- a/src/plugins/saved_search/server/saved_objects/search.ts +++ b/src/plugins/saved_search/server/saved_objects/search.ts @@ -51,6 +51,21 @@ export function getSavedSearchObjectType( grid: { type: 'object', enabled: false }, version: { type: 'integer' }, rowHeight: { type: 'text' }, + timeRestore: { type: 'boolean', index: false, doc_values: false }, + timeRange: { + dynamic: false, + properties: { + from: { type: 'keyword', index: false, doc_values: false }, + to: { type: 'keyword', index: false, doc_values: false }, + }, + }, + refreshInterval: { + dynamic: false, + properties: { + pause: { type: 'boolean', index: false, doc_values: false }, + value: { type: 'integer', index: false, doc_values: false }, + }, + }, rowsPerPage: { type: 'integer', index: false, doc_values: false }, }, }, diff --git a/test/functional/fixtures/es_archiver/deprecations_service/mappings.json b/test/functional/fixtures/es_archiver/deprecations_service/mappings.json index 2d86b863d47dc..47bd39ebf8bcf 100644 --- a/test/functional/fixtures/es_archiver/deprecations_service/mappings.json +++ b/test/functional/fixtures/es_archiver/deprecations_service/mappings.json @@ -423,7 +423,10 @@ "number_of_shards": "1", "priority": "10", "refresh_interval": "1s", - "routing_partition_size": "1" + "routing_partition_size": "1", + "mapping": { + "total_fields": { "limit": 1500 } + } } } } diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/export_transform/mappings.json b/test/functional/fixtures/es_archiver/saved_objects_management/export_transform/mappings.json index 9562b381a40f8..84628ef0366fa 100644 --- a/test/functional/fixtures/es_archiver/saved_objects_management/export_transform/mappings.json +++ b/test/functional/fixtures/es_archiver/saved_objects_management/export_transform/mappings.json @@ -462,7 +462,10 @@ "number_of_shards": "1", "priority": "10", "refresh_interval": "1s", - "routing_partition_size": "1" + "routing_partition_size": "1", + "mapping": { + "total_fields": { "limit": 1500 } + } } } } diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/hidden_saved_objects/mappings.json b/test/functional/fixtures/es_archiver/saved_objects_management/hidden_saved_objects/mappings.json index 780fdda5f7cbe..43711680a1f12 100644 --- a/test/functional/fixtures/es_archiver/saved_objects_management/hidden_saved_objects/mappings.json +++ b/test/functional/fixtures/es_archiver/saved_objects_management/hidden_saved_objects/mappings.json @@ -470,7 +470,10 @@ "number_of_shards": "1", "priority": "10", "refresh_interval": "1s", - "routing_partition_size": "1" + "routing_partition_size": "1", + "mapping": { + "total_fields": { "limit": 1500 } + } } } } diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/nested_export_transform/mappings.json b/test/functional/fixtures/es_archiver/saved_objects_management/nested_export_transform/mappings.json index 9562b381a40f8..84628ef0366fa 100644 --- a/test/functional/fixtures/es_archiver/saved_objects_management/nested_export_transform/mappings.json +++ b/test/functional/fixtures/es_archiver/saved_objects_management/nested_export_transform/mappings.json @@ -462,7 +462,10 @@ "number_of_shards": "1", "priority": "10", "refresh_interval": "1s", - "routing_partition_size": "1" + "routing_partition_size": "1", + "mapping": { + "total_fields": { "limit": 1500 } + } } } } diff --git a/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/mappings.json b/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/mappings.json index 3c0a975a30be0..6ffcd71f29e50 100644 --- a/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/mappings.json +++ b/test/functional/fixtures/es_archiver/saved_objects_management/visible_in_management/mappings.json @@ -470,7 +470,10 @@ "number_of_shards": "1", "priority": "10", "refresh_interval": "1s", - "routing_partition_size": "1" + "routing_partition_size": "1", + "mapping": { + "total_fields": { "limit": 1500 } + } } } } diff --git a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json index 12606562ab33b..34ddbc9ac7846 100644 --- a/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json +++ b/x-pack/test/saved_object_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json @@ -24,7 +24,10 @@ "index": { "auto_expand_replicas": "0-1", "number_of_replicas": "0", - "number_of_shards": "1" + "number_of_shards": "1", + "mapping": { + "total_fields": { "limit": 1500 } + } } } } diff --git a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json index 3ef2af5f9cf7d..3f837ae5fa208 100644 --- a/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json +++ b/x-pack/test/spaces_api_integration/common/fixtures/es_archiver/saved_objects/spaces/mappings.json @@ -13,7 +13,10 @@ "index": { "auto_expand_replicas": "0-1", "number_of_replicas": "0", - "number_of_shards": "1" + "number_of_shards": "1", + "mapping": { + "total_fields": { "limit": 1500 } + } } } } From 1ae09bc91cbd277e118ad4803566f472eecc9670 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 23 Aug 2022 02:18:50 -0700 Subject: [PATCH 10/41] [Security Solution] Remove docValueFields usage from security_soultion and timelines plugins (#137802) * [Security Solution] Remove docValueFields usage from security_soultion and timelines plugins * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * Fixed tests * Fixed type checkes * Removed unused type * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * Fixed tests * Fixed FTR * Fixed unit test Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../common/search_strategy/common/index.ts | 1 - .../search_strategy/index_fields/index.ts | 6 +- .../security_solution/index.ts | 2 - .../components/matrix_histogram/index.tsx | 2 - .../components/matrix_histogram/types.ts | 2 - .../containers/matrix_histogram/index.ts | 6 +- .../common/containers/source/index.test.tsx | 19 +- .../public/common/containers/source/index.tsx | 10 +- .../public/common/containers/source/mock.ts | 12 - .../containers/source/use_data_view.tsx | 9 - .../common/containers/sourcerer/index.tsx | 1 - .../common/containers/sourcerer/readme.md | 1 - .../public/common/mock/global_state.ts | 8 +- .../public/common/store/sourcerer/actions.ts | 1 - .../public/common/store/sourcerer/model.ts | 12 +- .../public/common/store/sourcerer/readme.md | 1 - .../public/common/utils/alerts.ts | 1 - .../rules/step_define_rule/index.tsx | 1 - .../public/hosts/containers/hosts/index.tsx | 16 +- .../containers/network_dns/index.test.tsx | 1 - .../network/containers/network_dns/index.tsx | 16 +- .../pages/navigation/dns_query_tab_body.tsx | 3 - .../pages/navigation/network_routes.tsx | 14 +- .../public/network/pages/navigation/types.ts | 7 +- .../public/network/pages/network.tsx | 3 +- .../components/flyout/header/index.test.tsx | 3 +- .../components/flyout/header/index.tsx | 3 +- .../timeline/eql_tab_content/index.test.tsx | 1 - .../components/timeline/index.test.tsx | 3 +- .../timeline/query_tab_content/index.test.tsx | 1 - .../timelines/containers/kpis/index.tsx | 6 +- .../navigation/all_users_query_tab_body.tsx | 15 +- .../authentications_query_tab_body.tsx | 2 - .../public/users/pages/navigation/types.ts | 2 - .../public/users/pages/types.ts | 2 - .../public/users/pages/users.tsx | 3 +- .../resolver/tree/queries/descendants.ts | 11 +- .../routes/resolver/tree/queries/lifecycle.ts | 8 +- .../routes/resolver/tree/utils/index.ts | 26 +- .../dns/query.dns_histogram.dsl.ts | 4 - x-pack/plugins/timelines/common/index.ts | 2 - .../common/search_strategy/common/index.ts | 2 - .../search_strategy/index_fields/index.ts | 3 +- .../public/container/source/index.tsx | 25 -- .../timelines/public/mock/browser_fields.ts | 12 - .../timeline/eql/helpers.test.ts | 1 - .../apis/security_solution/authentications.ts | 2 - .../apis/security_solution/events.ts | 3 +- .../apis/security_solution/kpi_hosts.ts | 4 - .../apis/security_solution/kpi_network.ts | 11 - .../apis/security_solution/kpi_users.ts | 2 - .../security_solution/matrix_dns_histogram.ts | 1 - .../apis/security_solution/network_dns.ts | 2 - .../security_solution/network_top_n_flow.ts | 4 - .../apis/security_solution/overview_host.ts | 1 - .../security_solution/overview_network.ts | 3 - .../apis/security_solution/tls.ts | 4 - .../security_solution/uncommon_processes.ts | 3 - .../apis/security_solution/users.ts | 1 - .../apis/security_solution/utils.ts | 317 +----------------- .../security_and_spaces/tests/basic/events.ts | 14 - .../security_and_spaces/tests/trial/events.ts | 5 - 62 files changed, 46 insertions(+), 621 deletions(-) diff --git a/x-pack/plugins/security_solution/common/search_strategy/common/index.ts b/x-pack/plugins/security_solution/common/search_strategy/common/index.ts index d8ef64fe1b5a4..c33c3f9abae6b 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/common/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/common/index.ts @@ -10,7 +10,6 @@ export type { SortField, TimerangeInput, PaginationInputPaginated, - DocValueFields, CursorType, TotalValue, } from '@kbn/timelines-plugin/common'; diff --git a/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts b/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts index 9750fbde2db47..01a1073c0fa71 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts @@ -14,8 +14,4 @@ export type { BrowserField, BrowserFields, } from '@kbn/timelines-plugin/common'; -export { - EMPTY_BROWSER_FIELDS, - EMPTY_DOCVALUE_FIELD, - EMPTY_INDEX_FIELDS, -} from '@kbn/timelines-plugin/common'; +export { EMPTY_BROWSER_FIELDS, EMPTY_INDEX_FIELDS } from '@kbn/timelines-plugin/common'; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts index 43d3d8722e797..dfc26932e8d79 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { IEsSearchRequest } from '@kbn/data-plugin/common'; import type { ESQuery } from '../../typed_json'; import type { @@ -120,7 +119,6 @@ export interface RequestBasicOptions extends IEsSearchRequest { timerange: TimerangeInput; filterQuery: ESQuery | string | undefined; defaultIndex: string[]; - docValueFields?: estypes.QueryDslFieldAndFormat[]; factoryQueryType?: FactoryQueryTypes; } diff --git a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx index ae214bd201bf5..a7c2075497b5a 100644 --- a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/index.tsx @@ -72,7 +72,6 @@ const HistogramPanel = styled(Panel)<{ height?: number }>` export const MatrixHistogramComponent: React.FC = ({ chartHeight, defaultStackByOption, - docValueFields, endDate, errorMessage, filterQuery, @@ -176,7 +175,6 @@ export const MatrixHistogramComponent: React.FC = stackByField: selectedStackByOption.value, runtimeMappings, isPtrIncluded, - docValueFields, skip: querySkip, }; const [loading, { data, inspect, totalCount, refetch }] = diff --git a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts index 9557e2be55742..49ac62cb572e4 100644 --- a/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts +++ b/x-pack/plugins/security_solution/public/common/components/matrix_histogram/types.ts @@ -15,7 +15,6 @@ import type { InputsModelId } from '../../store/inputs/constants'; import type { MatrixHistogramType } from '../../../../common/search_strategy/security_solution'; import type { UpdateDateRange } from '../charts/common'; import type { GlobalTimeArgs } from '../../containers/use_global_time'; -import type { DocValueFields } from '../../../../common/search_strategy'; import type { FieldValueThreshold } from '../../../detections/components/rules/threshold_input'; import type { GetLensAttributes, LensAttributes } from '../visualization_actions/types'; @@ -66,7 +65,6 @@ interface MatrixHistogramBasicProps { } export interface MatrixHistogramQueryProps { - docValueFields?: DocValueFields[]; endDate: string; errorMessage: string; indexNames: string[]; diff --git a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts index 8fef932c991a4..c770713b602b7 100644 --- a/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts +++ b/x-pack/plugins/security_solution/public/common/containers/matrix_histogram/index.ts @@ -6,7 +6,7 @@ */ import deepEqual from 'fast-deep-equal'; -import { getOr, isEmpty, noop } from 'lodash/fp'; +import { getOr, noop } from 'lodash/fp'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Subscription } from 'rxjs'; @@ -48,7 +48,6 @@ export interface UseMatrixHistogramArgs { } export const useMatrixHistogram = ({ - docValueFields, endDate, errorMessage, filterQuery, @@ -88,7 +87,6 @@ export const useMatrixHistogram = ({ runtimeMappings, threshold, ...(isPtrIncluded != null ? { isPtrIncluded } : {}), - ...(!isEmpty(docValueFields) ? { docValueFields } : {}), ...(includeMissingData != null ? { includeMissingData } : {}), }); const { addError, addWarning } = useAppToasts(); @@ -171,7 +169,6 @@ export const useMatrixHistogram = ({ stackByField, threshold, ...(isPtrIncluded != null ? { isPtrIncluded } : {}), - ...(!isEmpty(docValueFields) ? { docValueFields } : {}), }; if (!deepEqual(prevRequest, myRequest)) { return myRequest; @@ -187,7 +184,6 @@ export const useMatrixHistogram = ({ histogramType, threshold, isPtrIncluded, - docValueFields, ]); useEffect(() => { diff --git a/x-pack/plugins/security_solution/public/common/containers/source/index.test.tsx b/x-pack/plugins/security_solution/public/common/containers/source/index.test.tsx index 24d58a665177b..40a473de30687 100644 --- a/x-pack/plugins/security_solution/public/common/containers/source/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/source/index.test.tsx @@ -102,7 +102,6 @@ describe('source/index.tsx', () => { expect(payload.id).toEqual('neato'); expect(Object.keys(payload.browserFields)).toHaveLength(12); expect(Object.keys(payload.indexFields)).toHaveLength(mocksSource.indexFields.length); - expect(payload.docValueFields).toEqual([{ field: '@timestamp' }]); }); it('should reuse the result for dataView info when cleanCache not passed', async () => { @@ -120,23 +119,18 @@ describe('source/index.tsx', () => { await indexFieldsSearch!({ dataViewId: 'neato' }); const { - payload: { browserFields, indexFields, docValueFields }, + payload: { browserFields, indexFields }, } = mockDispatch.mock.calls[1][0]; mockDispatch.mockClear(); await indexFieldsSearch!({ dataViewId: 'neato' }); const { - payload: { - browserFields: newBrowserFields, - indexFields: newIndexFields, - docValueFields: newDocValueFields, - }, + payload: { browserFields: newBrowserFields, indexFields: newIndexFields }, } = mockDispatch.mock.calls[1][0]; expect(browserFields).toBe(newBrowserFields); expect(indexFields).toBe(newIndexFields); - expect(docValueFields).toBe(newDocValueFields); }); it('should not reuse the result for dataView info when cleanCache passed', async () => { @@ -154,23 +148,18 @@ describe('source/index.tsx', () => { await indexFieldsSearch!({ dataViewId: 'neato' }); const { - payload: { browserFields, indexFields, docValueFields }, + payload: { browserFields, indexFields }, } = mockDispatch.mock.calls[1][0]; mockDispatch.mockClear(); await indexFieldsSearch!({ dataViewId: 'neato', cleanCache: true }); const { - payload: { - browserFields: newBrowserFields, - indexFields: newIndexFields, - docValueFields: newDocValueFields, - }, + payload: { browserFields: newBrowserFields, indexFields: newIndexFields }, } = mockDispatch.mock.calls[1][0]; expect(browserFields).not.toBe(newBrowserFields); expect(indexFields).not.toBe(newIndexFields); - expect(docValueFields).not.toBe(newDocValueFields); }); }); }); diff --git a/x-pack/plugins/security_solution/public/common/containers/source/index.tsx b/x-pack/plugins/security_solution/public/common/containers/source/index.tsx index 68beb34712a6e..7f420fbf085da 100644 --- a/x-pack/plugins/security_solution/public/common/containers/source/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/source/index.tsx @@ -15,7 +15,6 @@ import { Subscription } from 'rxjs'; import type { BrowserField, BrowserFields, - DocValueFields, IndexField, IndexFieldsStrategyRequest, IndexFieldsStrategyResponse, @@ -26,7 +25,7 @@ import * as i18n from './translations'; import { useAppToasts } from '../../hooks/use_app_toasts'; import { getDataViewStateFromIndexFields } from './use_data_view'; -export type { BrowserField, BrowserFields, DocValueFields }; +export type { BrowserField, BrowserFields }; export function getAllBrowserFields(browserFields: BrowserFields): Array> { const result: Array> = []; @@ -86,11 +85,8 @@ export const getBrowserFields = memoizeOne( const DEFAULT_BROWSER_FIELDS = {}; const DEFAULT_INDEX_PATTERNS = { fields: [], title: '' }; -const DEFAULT_DOC_VALUE_FIELDS: DocValueFields[] = []; - interface FetchIndexReturn { browserFields: BrowserFields; - docValueFields: DocValueFields[]; indexes: string[]; indexExists: boolean; indexPatterns: DataViewBase; @@ -112,7 +108,6 @@ export const useFetchIndex = ( const [state, setState] = useState({ browserFields: DEFAULT_BROWSER_FIELDS, - docValueFields: DEFAULT_DOC_VALUE_FIELDS, indexes: indexNames, indexExists: true, indexPatterns: DEFAULT_INDEX_PATTERNS, @@ -140,14 +135,13 @@ export const useFetchIndex = ( const stringifyIndices = response.indicesExist.sort().join(); previousIndexesName.current = response.indicesExist; - const { browserFields, docValueFields } = getDataViewStateFromIndexFields( + const { browserFields } = getDataViewStateFromIndexFields( stringifyIndices, response.indexFields ); setLoading(false); setState({ browserFields, - docValueFields, indexes: response.indicesExist, indexExists: response.indicesExist.length > 0, indexPatterns: getIndexFields(stringifyIndices, response.indexFields), diff --git a/x-pack/plugins/security_solution/public/common/containers/source/mock.ts b/x-pack/plugins/security_solution/public/common/containers/source/mock.ts index 607225ff62e57..956275d43bac7 100644 --- a/x-pack/plugins/security_solution/public/common/containers/source/mock.ts +++ b/x-pack/plugins/security_solution/public/common/containers/source/mock.ts @@ -7,7 +7,6 @@ import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { DEFAULT_INDEX_PATTERN } from '../../../../common/constants'; -import type { DocValueFields } from '../../../../common/search_strategy'; import type { BrowserFields } from '../../../../common/search_strategy/index_fields'; export const mocksSource = { @@ -957,17 +956,6 @@ export const mockBrowserFields: BrowserFields = { }, }; -export const mockDocValueFields: DocValueFields[] = [ - { - field: '@timestamp', - format: 'date_time', - }, - { - field: 'event.end', - format: 'date_time', - }, -]; - export const mockRuntimeMappings: MappingRuntimeFields = { '@a.runtime.field': { script: { diff --git a/x-pack/plugins/security_solution/public/common/containers/source/use_data_view.tsx b/x-pack/plugins/security_solution/public/common/containers/source/use_data_view.tsx index 49cf89e0de1b0..51ad895b56f0c 100644 --- a/x-pack/plugins/security_solution/public/common/containers/source/use_data_view.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/source/use_data_view.tsx @@ -12,7 +12,6 @@ import memoizeOne from 'memoize-one'; import { omit, pick } from 'lodash/fp'; import type { BrowserField, - DocValueFields, IndexField, IndexFieldsStrategyRequest, IndexFieldsStrategyResponse, @@ -40,7 +39,6 @@ type DangerCastForBrowserFieldsMutation = Record< >; interface DataViewInfo { browserFields: DangerCastForBrowserFieldsMutation; - docValueFields: DocValueFields[]; indexFields: FieldSpec[]; } @@ -69,17 +67,10 @@ export const getDataViewStateFromIndexFields = memoizeOne( pick(['name', 'searchable', 'type', 'aggregatable', 'esTypes', 'subType'], field) ); - // mutate docValueFields - if (field.readFromDocValues && acc.docValueFields.length < 100) { - acc.docValueFields.push({ - field: field.name, - }); - } return acc; }, { browserFields: {}, - docValueFields: [], indexFields: [], } ); diff --git a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx index effd5196dd9bc..6db7392b596b7 100644 --- a/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/sourcerer/index.tsx @@ -408,7 +408,6 @@ export const useSourcererDataView = ( () => ({ browserFields: sourcererDataView.browserFields, dataViewId: sourcererDataView.id, - docValueFields: sourcererDataView.docValueFields, indexPattern: { fields: sourcererDataView.indexFields, title: selectedPatterns.join(','), diff --git a/x-pack/plugins/security_solution/public/common/containers/sourcerer/readme.md b/x-pack/plugins/security_solution/public/common/containers/sourcerer/readme.md index d6edb9794dc8b..b8672d7a9edc7 100644 --- a/x-pack/plugins/security_solution/public/common/containers/sourcerer/readme.md +++ b/x-pack/plugins/security_solution/public/common/containers/sourcerer/readme.md @@ -16,7 +16,6 @@ interface SelectedDataView { browserFields: SourcererDataView['browserFields']; dataViewId: string | null; // null if legacy pre-8.0 timeline - docValueFields: SourcererDataView['docValueFields']; /** * DataViewBase with enhanced index fields used in timelines */ diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index 027827474c780..17f5e4d9be8f8 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -34,12 +34,7 @@ import type { ManagementState } from '../../management/types'; import { initialSourcererState, SourcererScopeName } from '../store/sourcerer/model'; import { allowedExperimentalValues } from '../../../common/experimental_features'; import { getScopePatternListSelection } from '../store/sourcerer/helpers'; -import { - mockBrowserFields, - mockDocValueFields, - mockIndexFields, - mockRuntimeMappings, -} from '../containers/source/mock'; +import { mockBrowserFields, mockIndexFields, mockRuntimeMappings } from '../containers/source/mock'; import { usersModel } from '../../users/store'; import { UsersFields } from '../../../common/search_strategy/security_solution/users/common'; @@ -49,7 +44,6 @@ export const mockSourcererState = { defaultDataView: { ...initialSourcererState.defaultDataView, browserFields: mockBrowserFields, - docValueFields: mockDocValueFields, id: DEFAULT_DATA_VIEW_ID, indexFields: mockIndexFields, loading: false, diff --git a/x-pack/plugins/security_solution/public/common/store/sourcerer/actions.ts b/x-pack/plugins/security_solution/public/common/store/sourcerer/actions.ts index 2abd8a7a50919..f452d34cba310 100644 --- a/x-pack/plugins/security_solution/public/common/store/sourcerer/actions.ts +++ b/x-pack/plugins/security_solution/public/common/store/sourcerer/actions.ts @@ -19,7 +19,6 @@ const actionCreator = actionCreatorFactory('x-pack/security_solution/local/sourc export const setDataView = actionCreator<{ browserFields: SourcererDataView['browserFields']; - docValueFields: SourcererDataView['docValueFields']; id: SourcererDataView['id']; indexFields: SourcererDataView['indexFields']; loading: SourcererDataView['loading']; diff --git a/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts b/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts index 3b35db56f4d0b..e4d16f2079dba 100644 --- a/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts +++ b/x-pack/plugins/security_solution/public/common/store/sourcerer/model.ts @@ -6,12 +6,8 @@ */ import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { BrowserFields, DocValueFields } from '@kbn/timelines-plugin/common'; -import { - EMPTY_BROWSER_FIELDS, - EMPTY_DOCVALUE_FIELD, - EMPTY_INDEX_FIELDS, -} from '@kbn/timelines-plugin/common'; +import type { BrowserFields } from '@kbn/timelines-plugin/common'; +import { EMPTY_BROWSER_FIELDS, EMPTY_INDEX_FIELDS } from '@kbn/timelines-plugin/common'; import type { SecuritySolutionDataViewBase } from '../../types'; /** Uniquely identifies a Sourcerer Scope */ export enum SourcererScopeName { @@ -64,8 +60,6 @@ export interface SourcererDataView extends KibanaDataView { * category, description, format * indices the field is included in etc*/ browserFields: BrowserFields; - /** query DSL field and format */ - docValueFields: DocValueFields[]; /** comes from dataView.fields.toSpec() */ indexFields: SecuritySolutionDataViewBase['fields']; /** set when data view fields are fetched */ @@ -84,7 +78,6 @@ export interface SourcererDataView extends KibanaDataView { export interface SelectedDataView { browserFields: SourcererDataView['browserFields']; dataViewId: string | null; // null if legacy pre-8.0 timeline - docValueFields: SourcererDataView['docValueFields']; /** * DataViewBase with enhanced index fields used in timelines */ @@ -131,7 +124,6 @@ export const initSourcererScope: Omit = { }; export const initDataView = { browserFields: EMPTY_BROWSER_FIELDS, - docValueFields: EMPTY_DOCVALUE_FIELD, id: '', indexFields: EMPTY_INDEX_FIELDS, loading: false, diff --git a/x-pack/plugins/security_solution/public/common/store/sourcerer/readme.md b/x-pack/plugins/security_solution/public/common/store/sourcerer/readme.md index 6dbc8f5ad817c..28059371804c9 100644 --- a/x-pack/plugins/security_solution/public/common/store/sourcerer/readme.md +++ b/x-pack/plugins/security_solution/public/common/store/sourcerer/readme.md @@ -69,7 +69,6 @@ interface SourcererDataView extends KibanaDataView { * indices the field is included in etc*/ browserFields: BrowserFields; /** query DSL field and format */ - docValueFields: DocValueFields[]; /** comes from dataView.fields.toSpec() */ indexFields: SecuritySolutionDataViewBase['fields']; /** set when data view fields are fetched */ diff --git a/x-pack/plugins/security_solution/public/common/utils/alerts.ts b/x-pack/plugins/security_solution/public/common/utils/alerts.ts index 461adbcc6e8c1..e0d497ba9e3f8 100644 --- a/x-pack/plugins/security_solution/public/common/utils/alerts.ts +++ b/x-pack/plugins/security_solution/public/common/utils/alerts.ts @@ -9,7 +9,6 @@ import { merge } from '@kbn/std'; import { isPlainObject } from 'lodash'; import type { Ecs } from '@kbn/cases-plugin/common'; -// TODO we need to allow -> docValueFields: [{ field: "@timestamp" }], export const buildAlertsQuery = (alertIds: string[]) => { if (alertIds.length === 0) { return {}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx index b1c55bdecc52d..f9be710725986 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx @@ -615,7 +615,6 @@ const StepDefineRuleComponent: FC = ({ component={QueryBarDefineRule} componentProps={{ browserFields, - // docValueFields, // runtimeMappings, idAria: 'detectionEngineStepDefineRuleQueryBar', indexPattern, diff --git a/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx b/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx index e6e02c335180c..156af86d9df37 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/containers/hosts/index.tsx @@ -17,7 +17,6 @@ import { generateTablePaginationOptions } from '../../../common/components/pagin import type { HostsEdges, PageInfoPaginated, - DocValueFields, HostsRequestOptions, } from '../../../../common/search_strategy'; import { HostsQueries } from '../../../../common/search_strategy'; @@ -44,7 +43,6 @@ export interface HostsArgs { } interface UseAllHost { - docValueFields?: DocValueFields[]; endDate: string; filterQuery?: ESTermQuery | string; indexNames: string[]; @@ -54,7 +52,6 @@ interface UseAllHost { } export const useAllHost = ({ - docValueFields, endDate, filterQuery, indexNames, @@ -136,7 +133,6 @@ export const useAllHost = ({ const myRequest = { ...(prevRequest ?? {}), defaultIndex: indexNames, - docValueFields: docValueFields ?? [], factoryQueryType: HostsQueries.hosts, filterQuery: createFilter(filterQuery), pagination: generateTablePaginationOptions(activePage, limit), @@ -155,17 +151,7 @@ export const useAllHost = ({ } return prevRequest; }); - }, [ - activePage, - direction, - docValueFields, - endDate, - filterQuery, - indexNames, - limit, - startDate, - sortField, - ]); + }, [activePage, direction, endDate, filterQuery, indexNames, limit, startDate, sortField]); useEffect(() => { if (!skip && hostsRequest) { diff --git a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.test.tsx b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.test.tsx index 34272cd7cbccf..aa260236da39d 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.test.tsx @@ -17,7 +17,6 @@ const mockUseSearchStrategy = useSearchStrategy as jest.Mock; const mockSearch = jest.fn(); const props = { - docValueFields: [], endDate: '2020-07-08T08:20:18.966Z', id: ID, indexNames: ['auditbeat-*'], diff --git a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx index 28dc7e657191c..833efc839b600 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx @@ -15,7 +15,6 @@ import { createFilter } from '../../../common/containers/helpers'; import { generateTablePaginationOptions } from '../../../common/components/paginated_table/helpers'; import { networkSelectors } from '../../store'; import type { - DocValueFields, NetworkDnsRequestOptions, NetworkDnsEdges, PageInfoPaginated, @@ -41,7 +40,6 @@ export interface NetworkDnsResponse { interface UseNetworkDns { id: string; - docValueFields: DocValueFields[]; indexNames: string[]; filterQuery?: ESTermQuery | string; endDate: string; @@ -50,7 +48,6 @@ interface UseNetworkDns { } export const useNetworkDns = ({ - docValueFields, endDate, filterQuery, id, @@ -119,7 +116,6 @@ export const useNetworkDns = ({ const myRequest = { ...(prevRequest ?? {}), defaultIndex: indexNames, - docValueFields: docValueFields ?? [], isPtrIncluded, factoryQueryType: NetworkQueries.dns, filterQuery: createFilter(filterQuery), @@ -136,17 +132,7 @@ export const useNetworkDns = ({ } return prevRequest; }); - }, [ - activePage, - indexNames, - endDate, - filterQuery, - limit, - startDate, - sort, - isPtrIncluded, - docValueFields, - ]); + }, [activePage, indexNames, endDate, filterQuery, limit, startDate, sort, isPtrIncluded]); useEffect(() => { if (!skip && networkDnsRequest) { diff --git a/x-pack/plugins/security_solution/public/network/pages/navigation/dns_query_tab_body.tsx b/x-pack/plugins/security_solution/public/network/pages/navigation/dns_query_tab_body.tsx index ee423b0343088..54bdb1acd81b6 100644 --- a/x-pack/plugins/security_solution/public/network/pages/navigation/dns_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/navigation/dns_query_tab_body.tsx @@ -51,7 +51,6 @@ export const histogramConfigs: Omit = { const DnsQueryTabBodyComponent: React.FC = ({ deleteQuery, - docValueFields, endDate, filterQuery, indexNames, @@ -82,7 +81,6 @@ const DnsQueryTabBodyComponent: React.FC = ({ loading, { totalCount, networkDns, pageInfo, loadPage, id, inspect, isInspected, refetch }, ] = useNetworkDns({ - docValueFields: docValueFields ?? [], endDate, filterQuery, id: queryId, @@ -109,7 +107,6 @@ const DnsQueryTabBodyComponent: React.FC = ({ ( - ({ - docValueFields, - type, - to, - filterQuery, - isInitializing, - from, - indexPattern, - indexNames, - setQuery, - }) => { + ({ type, to, filterQuery, isInitializing, from, indexPattern, indexNames, setQuery }) => { const networkAnomaliesFilterQuery = { bool: { should: [ @@ -83,7 +73,7 @@ export const NetworkRoutes = React.memo( return ( - + <> diff --git a/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts b/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts index e2b96fce68b6e..941ace5049cdf 100644 --- a/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts +++ b/x-pack/plugins/security_solution/public/network/pages/navigation/types.ts @@ -15,8 +15,6 @@ import type { FlowTargetSourceDest } from '../../../../common/search_strategy/se import type { networkModel } from '../../store'; import type { GlobalTimeArgs } from '../../../common/containers/use_global_time'; -import type { DocValueFields } from '../../../common/containers/source'; - export interface QueryTabBodyProps extends Pick { endDate: string; filterQuery?: string | ESTermQuery; @@ -27,9 +25,7 @@ export interface QueryTabBodyProps extends Pick( [dispatch] ); - const { docValueFields, indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); + const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); const onSkipFocusBeforeEventsTable = useCallback(() => { containerElement.current @@ -214,7 +214,6 @@ const NetworkComponent = React.memo( = ({ timelineId } const TimelineStatusInfo = React.memo(TimelineStatusInfoComponent); const FlyoutHeaderComponent: React.FC = ({ timelineId }) => { - const { selectedPatterns, indexPattern, docValueFields, browserFields } = useSourcererDataView( + const { selectedPatterns, indexPattern, browserFields } = useSourcererDataView( SourcererScopeName.timeline ); const getStartSelector = useMemo(() => startSelector(), []); @@ -409,7 +409,6 @@ const FlyoutHeaderComponent: React.FC = ({ timelineId }) => { const [loading, kpis] = useTimelineKpis({ defaultIndex: selectedPatterns, - docValueFields, timerange, isBlankTimeline, filterQuery: combinedQueries?.filterQuery ?? '', diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx index c2036263ec28d..aae85b19bfd05 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/eql_tab_content/index.test.tsx @@ -194,7 +194,6 @@ describe('Timeline', () => { test('it does render the timeline table when the source is loading with no events', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ browserFields: {}, - docValueFields: [], loading: true, indexPattern: {}, selectedPatterns: [], diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx index 292dd5e1a44b9..310849aee4c09 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx @@ -11,7 +11,7 @@ import useResizeObserver from 'use-resize-observer/polyfilled'; import { DragDropContextWrapper } from '../../../common/components/drag_and_drop/drag_drop_context_wrapper'; import '../../../common/mock/match_media'; -import { mockBrowserFields, mockDocValueFields } from '../../../common/containers/source/mock'; +import { mockBrowserFields } from '../../../common/containers/source/mock'; import { TimelineId } from '../../../../common/types/timeline'; import { createSecuritySolutionStorageMock, @@ -94,7 +94,6 @@ jest.mock('../../../common/containers/sourcerer'); const mockDataView = { dataViewId: mockGlobalState.timeline.timelineById.test?.dataViewId, browserFields: mockBrowserFields, - docValueFields: mockDocValueFields, loading: false, indexPattern: mockIndexPattern, pageInfo: { activePage: 0, querySize: 0 }, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx index 831b8358bad26..c7a30a4f501b8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_tab_content/index.test.tsx @@ -206,7 +206,6 @@ describe('Timeline', () => { test('it does render the timeline table when the source is loading with no events', () => { (useSourcererDataView as jest.Mock).mockReturnValue({ browserFields: {}, - docValueFields: [], loading: true, indexPattern: {}, selectedPatterns: [], diff --git a/x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx index 5a4a61e809bd1..5bd71f4f7be94 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/kpis/index.tsx @@ -14,7 +14,6 @@ import { isCompleteResponse, isErrorResponse } from '@kbn/data-plugin/public'; import type { inputsModel } from '../../../common/store'; import { useKibana } from '../../../common/lib/kibana'; import type { - DocValueFields, TimelineKpiStrategyRequest, TimelineKpiStrategyResponse, TimerangeInput, @@ -28,14 +27,12 @@ export interface UseTimelineKpiProps { timerange: TimerangeInput; filterQuery?: ESQuery | string | undefined; defaultIndex: string[]; - docValueFields?: DocValueFields[]; isBlankTimeline: boolean; } export const useTimelineKpis = ({ timerange, filterQuery, - docValueFields, defaultIndex, isBlankTimeline, }: UseTimelineKpiProps): [boolean, TimelineKpiStrategyResponse | null] => { @@ -96,7 +93,6 @@ export const useTimelineKpis = ({ setTimelineKpiRequest((prevRequest) => { const myRequest = { ...(prevRequest ?? {}), - docValueFields, defaultIndex, timerange, filterQuery, @@ -107,7 +103,7 @@ export const useTimelineKpis = ({ } return prevRequest; }); - }, [docValueFields, defaultIndex, timerange, filterQuery]); + }, [defaultIndex, timerange, filterQuery]); useEffect(() => { if (!isBlankTimeline) { diff --git a/x-pack/plugins/security_solution/public/users/pages/navigation/all_users_query_tab_body.tsx b/x-pack/plugins/security_solution/public/users/pages/navigation/all_users_query_tab_body.tsx index 0030391a2b54a..7c203d5920706 100644 --- a/x-pack/plugins/security_solution/public/users/pages/navigation/all_users_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/navigation/all_users_query_tab_body.tsx @@ -32,7 +32,6 @@ export const AllUsersQueryTabBody = ({ setQuery, startDate, type, - docValueFields, deleteQuery, }: UsersComponentsQueryProps) => { const { toggleStatus } = useQueryToggle(QUERY_ID); @@ -70,7 +69,6 @@ export const AllUsersQueryTabBody = ({ search({ filterQuery, defaultIndex: indexNames, - docValueFields, timerange: { interval: '12h', from: startDate, @@ -80,18 +78,7 @@ export const AllUsersQueryTabBody = ({ sort, }); } - }, [ - search, - startDate, - endDate, - filterQuery, - indexNames, - querySkip, - docValueFields, - activePage, - limit, - sort, - ]); + }, [search, startDate, endDate, filterQuery, indexNames, querySkip, activePage, limit, sort]); return ( { @@ -47,7 +46,6 @@ export const AuthenticationsQueryTabBody = ({ startDate={startDate} type={type} skip={skip} - docValueFields={docValueFields} userName={userName} /> diff --git a/x-pack/plugins/security_solution/public/users/pages/navigation/types.ts b/x-pack/plugins/security_solution/public/users/pages/navigation/types.ts index aeac9326a1f93..4bc79174beba6 100644 --- a/x-pack/plugins/security_solution/public/users/pages/navigation/types.ts +++ b/x-pack/plugins/security_solution/public/users/pages/navigation/types.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { DocValueFields } from '@kbn/timelines-plugin/common'; import type { UsersTableType, UsersType } from '../../store/model'; import type { GlobalTimeArgs } from '../../../common/containers/use_global_time'; import type { ESTermQuery } from '../../../../common/typed_json'; @@ -22,7 +21,6 @@ export interface QueryTabBodyProps { export type UsersComponentsQueryProps = QueryTabBodyProps & { deleteQuery?: GlobalTimeArgs['deleteQuery']; - docValueFields?: DocValueFields[]; indexNames: string[]; skip: boolean; setQuery: GlobalTimeArgs['setQuery']; diff --git a/x-pack/plugins/security_solution/public/users/pages/types.ts b/x-pack/plugins/security_solution/public/users/pages/types.ts index b7af4c3c54d22..955b565b328a8 100644 --- a/x-pack/plugins/security_solution/public/users/pages/types.ts +++ b/x-pack/plugins/security_solution/public/users/pages/types.ts @@ -6,13 +6,11 @@ */ import type { Filter } from '@kbn/es-query'; -import type { DocValueFields } from '@kbn/timelines-plugin/common'; import type { GlobalTimeArgs } from '../../common/containers/use_global_time'; import type { usersModel } from '../store'; export type UsersTabsProps = GlobalTimeArgs & { - docValueFields: DocValueFields[]; filterQuery: string; pageFilters?: Filter[]; indexNames: string[]; diff --git a/x-pack/plugins/security_solution/public/users/pages/users.tsx b/x-pack/plugins/security_solution/public/users/pages/users.tsx index 9d567e7605074..1f87ec55f808d 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users.tsx @@ -102,7 +102,7 @@ const UsersComponent = () => { return filters; }, [severitySelection, tabName, filters]); - const { docValueFields, indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); + const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); const [filterQuery, kqlError] = useMemo( () => convertToBuildEsQuery({ @@ -210,7 +210,6 @@ const UsersComponent = () => { String(id) !== ''); +} + +/** + * Returns the resolver fields filter to use in queries to limit the number of fields returned in the + * query response. * @param schema is the node schema information describing how relationships are formed between nodes * in the resolver graph. */ -export function docValueFields(schema: ResolverSchema): Array<{ field: string }> { +export function resolverFields(schema: ResolverSchema): Array<{ field: string }> { const filter = [{ field: '@timestamp' }, { field: schema.id }, { field: schema.parent }]; if (schema.ancestry) { filter.push({ field: schema.ancestry }); @@ -40,12 +45,3 @@ export function docValueFields(schema: ResolverSchema): Array<{ field: string }> } return filter; } - -/** - * Returns valid IDs that can be used in a search. - * - * @param ids array of ids - */ -export function validIDs(ids: NodeID[]): NodeID[] { - return ids.filter((id) => String(id) !== ''); -} diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/matrix_histogram/dns/query.dns_histogram.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/matrix_histogram/dns/query.dns_histogram.dsl.ts index 17f083eeca9c1..c547f0a6ada3f 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/matrix_histogram/dns/query.dns_histogram.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/matrix_histogram/dns/query.dns_histogram.dsl.ts @@ -5,8 +5,6 @@ * 2.0. */ -import { isEmpty } from 'lodash/fp'; - import moment from 'moment'; import type { MatrixHistogramRequestOptions } from '../../../../../../common/search_strategy'; @@ -57,7 +55,6 @@ const getHistogramAggregation = ({ from, to }: { from: string; to: string }) => export const buildDnsHistogramQuery = ({ defaultIndex, - docValueFields, filterQuery, isPtrIncluded = false, stackByField = 'dns.question.registered_domain', @@ -81,7 +78,6 @@ export const buildDnsHistogramQuery = ({ index: defaultIndex, ignore_unavailable: true, body: { - ...(!isEmpty(docValueFields) ? { docvalue_fields: docValueFields } : {}), aggregations: { ...getCountAgg(), dns_name_query_count: { diff --git a/x-pack/plugins/timelines/common/index.ts b/x-pack/plugins/timelines/common/index.ts index 86d02d1883314..56ae9344254c2 100644 --- a/x-pack/plugins/timelines/common/index.ts +++ b/x-pack/plugins/timelines/common/index.ts @@ -46,7 +46,6 @@ export type { BrowserField, BrowserFields, CursorType, - DocValueFields, EqlOptionsData, EqlOptionsSelected, FieldsEqlOptions, @@ -81,6 +80,5 @@ export { EntityType, LastEventIndexKey, EMPTY_BROWSER_FIELDS, - EMPTY_DOCVALUE_FIELD, EMPTY_INDEX_FIELDS, } from './search_strategy'; diff --git a/x-pack/plugins/timelines/common/search_strategy/common/index.ts b/x-pack/plugins/timelines/common/search_strategy/common/index.ts index 6202e965894f0..63f43c936e77e 100644 --- a/x-pack/plugins/timelines/common/search_strategy/common/index.ts +++ b/x-pack/plugins/timelines/common/search_strategy/common/index.ts @@ -52,8 +52,6 @@ export interface PaginationInputPaginated { querySize: number; } -export type DocValueFields = estypes.QueryDslFieldAndFormat; - export interface TimerangeFilter { range: { [timestamp: string]: { diff --git a/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts b/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts index d14b346290a15..0d227fe595415 100644 --- a/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts +++ b/x-pack/plugins/timelines/common/search_strategy/index_fields/index.ts @@ -10,7 +10,7 @@ import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesW import type { IEsSearchRequest, IEsSearchResponse, FieldSpec } from '@kbn/data-plugin/common'; import type { RuntimeField } from '@kbn/data-views-plugin/common'; -import type { DocValueFields, Maybe } from '../common'; +import type { Maybe } from '../common'; export type BeatFieldsFactoryQueryType = 'beatFields'; @@ -76,5 +76,4 @@ export interface BrowserField { export type BrowserFields = Readonly>>; export const EMPTY_BROWSER_FIELDS = {}; -export const EMPTY_DOCVALUE_FIELD: DocValueFields[] = []; export const EMPTY_INDEX_FIELDS: FieldSpec[] = []; diff --git a/x-pack/plugins/timelines/public/container/source/index.tsx b/x-pack/plugins/timelines/public/container/source/index.tsx index cbe2158784913..dfb995d66be98 100644 --- a/x-pack/plugins/timelines/public/container/source/index.tsx +++ b/x-pack/plugins/timelines/public/container/source/index.tsx @@ -20,7 +20,6 @@ import * as i18n from './translations'; import { BrowserField, BrowserFields, - DocValueFields, IndexField, IndexFieldsStrategyRequest, IndexFieldsStrategyResponse, @@ -29,10 +28,8 @@ import { useAppToasts } from '../../hooks/use_app_toasts'; const DEFAULT_BROWSER_FIELDS = {}; const DEFAULT_INDEX_PATTERNS = { fields: [], title: '' }; -const DEFAULT_DOC_VALUE_FIELDS: DocValueFields[] = []; interface FetchIndexReturn { browserFields: BrowserFields; - docValueFields: DocValueFields[]; indexes: string[]; indexExists: boolean; indexPatterns: DataViewBase; @@ -67,26 +64,6 @@ export const getBrowserFields = memoizeOne( (newArgs, lastArgs) => newArgs[0] === lastArgs[0] ); -export const getDocValueFields = memoizeOne( - (_title: string, fields: IndexField[]): DocValueFields[] => - fields && fields.length > 0 - ? fields.reduce((accumulator: DocValueFields[], field: IndexField) => { - if (field.readFromDocValues && accumulator.length < 100) { - return [ - ...accumulator, - { - field: field.name, - format: field.format ? field.format : undefined, - }, - ]; - } - return accumulator; - }, []) - : [], - // Update the value only if _title has changed - (newArgs, lastArgs) => newArgs[0] === lastArgs[0] -); - export const getIndexFields = memoizeOne( (title: string, fields: IndexField[]): DataViewBase => fields && fields.length > 0 @@ -112,7 +89,6 @@ export const useFetchIndex = ( const [state, setState] = useState({ browserFields: DEFAULT_BROWSER_FIELDS, - docValueFields: DEFAULT_DOC_VALUE_FIELDS, indexes: indexNames, indexExists: true, indexPatterns: DEFAULT_INDEX_PATTERNS, @@ -142,7 +118,6 @@ export const useFetchIndex = ( setState({ browserFields: getBrowserFields(stringifyIndices, response.indexFields), - docValueFields: getDocValueFields(stringifyIndices, response.indexFields), indexes: response.indicesExist, indexExists: response.indicesExist.length > 0, indexPatterns: getIndexFields(stringifyIndices, response.indexFields), diff --git a/x-pack/plugins/timelines/public/mock/browser_fields.ts b/x-pack/plugins/timelines/public/mock/browser_fields.ts index e38a435d1a4fb..1e6afa11fa138 100644 --- a/x-pack/plugins/timelines/public/mock/browser_fields.ts +++ b/x-pack/plugins/timelines/public/mock/browser_fields.ts @@ -6,7 +6,6 @@ */ import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { DocValueFields } from '../../common/search_strategy'; import type { BrowserFields } from '../../common/search_strategy/index_fields'; const DEFAULT_INDEX_PATTERN = [ @@ -815,17 +814,6 @@ export const mockBrowserFields: BrowserFields = { }, }; -export const mockDocValueFields: DocValueFields[] = [ - { - field: '@timestamp', - format: 'date_time', - }, - { - field: 'event.end', - format: 'date_time', - }, -]; - export const mockRuntimeMappings: MappingRuntimeFields = { '@a.runtime.field': { script: { diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts index fadc295a51a59..c73d36a15d40c 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.test.ts @@ -10,7 +10,6 @@ import { buildEqlDsl, parseEqlResponse } from './helpers'; import { eventsResponse, sequenceResponse } from './__mocks__'; const defaultArgs = { defaultIndex: ['logs-endpoint.events*'], - docValueFields: [], runtimeMappings: {}, fieldRequested: [ '@timestamp', diff --git a/x-pack/test/api_integration/apis/security_solution/authentications.ts b/x-pack/test/api_integration/apis/security_solution/authentications.ts index aa098648d86fd..aa54114e04d72 100644 --- a/x-pack/test/api_integration/apis/security_solution/authentications.ts +++ b/x-pack/test/api_integration/apis/security_solution/authentications.ts @@ -52,7 +52,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 1, }, defaultIndex: ['auditbeat-*'], - docValueFields: [], stackByField: AuthStackByField.userName, sort: { field: 'timestamp', direction: Direction.asc }, filterQuery: '', @@ -84,7 +83,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 2, }, defaultIndex: ['auditbeat-*'], - docValueFields: [], stackByField: AuthStackByField.userName, sort: { field: 'timestamp', direction: Direction.asc }, filterQuery: '', diff --git a/x-pack/test/api_integration/apis/security_solution/events.ts b/x-pack/test/api_integration/apis/security_solution/events.ts index 0d8ce4d88c30a..c5a4ba97fc478 100644 --- a/x-pack/test/api_integration/apis/security_solution/events.ts +++ b/x-pack/test/api_integration/apis/security_solution/events.ts @@ -14,7 +14,7 @@ import { TimelineEventsAllStrategyResponse, } from '@kbn/security-solution-plugin/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { getDocValueFields, getFieldsToRequest, getFilterValue } from './utils'; +import { getFieldsToRequest, getFilterValue } from './utils'; const TO = '3000-01-01T00:00:00.000Z'; const FROM = '2000-01-01T00:00:00.000Z'; @@ -34,7 +34,6 @@ export default function ({ getService }: FtrProviderContext) { const getPostBody = (): JsonObject => ({ defaultIndex: ['auditbeat-*'], - docValueFields: getDocValueFields(), factoryQueryType: TimelineEventsQueries.all, entityType: 'events', fieldRequested: getFieldsToRequest(), diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts b/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts index 15ff856b29221..d1ae827c535a3 100644 --- a/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts +++ b/x-pack/test/api_integration/apis/security_solution/kpi_hosts.ts @@ -64,7 +64,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -84,7 +83,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -168,7 +166,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['auditbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -188,7 +185,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['auditbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_network.ts b/x-pack/test/api_integration/apis/security_solution/kpi_network.ts index 8c9e3e3229585..446797d993294 100644 --- a/x-pack/test/api_integration/apis/security_solution/kpi_network.ts +++ b/x-pack/test/api_integration/apis/security_solution/kpi_network.ts @@ -88,7 +88,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -107,7 +106,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -126,7 +124,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -145,7 +142,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -164,7 +160,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -184,7 +179,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -235,7 +229,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -254,7 +247,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -273,7 +265,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -293,7 +284,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -312,7 +302,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/kpi_users.ts b/x-pack/test/api_integration/apis/security_solution/kpi_users.ts index 154321b1b2eef..20861f8856c83 100644 --- a/x-pack/test/api_integration/apis/security_solution/kpi_users.ts +++ b/x-pack/test/api_integration/apis/security_solution/kpi_users.ts @@ -46,7 +46,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['filebeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -86,7 +85,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['auditbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts b/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts index 50722c39476c6..f418536d5d744 100644 --- a/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts +++ b/x-pack/test/api_integration/apis/security_solution/matrix_dns_histogram.ts @@ -44,7 +44,6 @@ export default function ({ getService }: FtrProviderContext) { supertest, options: { defaultIndex: ['large_volume_dns_data'], - docValueFields: [], factoryQueryType: MatrixHistogramQuery, histogramType: MatrixHistogramType.dns, filterQuery: diff --git a/x-pack/test/api_integration/apis/security_solution/network_dns.ts b/x-pack/test/api_integration/apis/security_solution/network_dns.ts index ed3be02d8cc29..194394fbe3ae5 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_dns.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_dns.ts @@ -38,7 +38,6 @@ export default function ({ getService }: FtrProviderContext) { supertest, options: { defaultIndex: ['packetbeat-*'], - docValueFields: [], factoryQueryType: NetworkQueries.dns, filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', @@ -69,7 +68,6 @@ export default function ({ getService }: FtrProviderContext) { ip: '151.205.0.17', defaultIndex: ['packetbeat-*'], factoryQueryType: NetworkQueries.dns, - docValueFields: [], inspect: false, pagination: { activePage: 0, diff --git a/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts b/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts index 783ef2efe907a..4e4d60f437f62 100644 --- a/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_top_n_flow.ts @@ -55,7 +55,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -95,7 +94,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -135,7 +133,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -170,7 +167,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/overview_host.ts b/x-pack/test/api_integration/apis/security_solution/overview_host.ts index 3c14b4f91d86c..1cf7e9cc0b598 100644 --- a/x-pack/test/api_integration/apis/security_solution/overview_host.ts +++ b/x-pack/test/api_integration/apis/security_solution/overview_host.ts @@ -59,7 +59,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/overview_network.ts b/x-pack/test/api_integration/apis/security_solution/overview_network.ts index 51398a1e396ec..9fd5b107fa5f2 100644 --- a/x-pack/test/api_integration/apis/security_solution/overview_network.ts +++ b/x-pack/test/api_integration/apis/security_solution/overview_network.ts @@ -52,7 +52,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -95,7 +94,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -137,7 +135,6 @@ export default function ({ getService }: FtrProviderContext) { to: TO, from: FROM, }, - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/tls.ts b/x-pack/test/api_integration/apis/security_solution/tls.ts index 5949a3b85c2a7..501cff3b1095d 100644 --- a/x-pack/test/api_integration/apis/security_solution/tls.ts +++ b/x-pack/test/api_integration/apis/security_solution/tls.ts @@ -115,7 +115,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 10, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -145,7 +144,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 10, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -184,7 +182,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 10, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -214,7 +211,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 10, }, defaultIndex: ['packetbeat-*'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts b/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts index 0278852b80672..eaacd6edf7e05 100644 --- a/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts +++ b/x-pack/test/api_integration/apis/security_solution/uncommon_processes.ts @@ -52,7 +52,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 1, }, defaultIndex: ['auditbeat-uncommon-processes'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -79,7 +78,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 2, }, defaultIndex: ['auditbeat-uncommon-processes'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', @@ -108,7 +106,6 @@ export default function ({ getService }: FtrProviderContext) { querySize: 1, }, defaultIndex: ['auditbeat-uncommon-processes'], - docValueFields: [], inspect: false, }, strategy: 'securitySolutionSearchStrategy', diff --git a/x-pack/test/api_integration/apis/security_solution/users.ts b/x-pack/test/api_integration/apis/security_solution/users.ts index f9c0cda614a7f..b04a3595b0a05 100644 --- a/x-pack/test/api_integration/apis/security_solution/users.ts +++ b/x-pack/test/api_integration/apis/security_solution/users.ts @@ -46,7 +46,6 @@ export default function ({ getService }: FtrProviderContext) { from: FROM, }, defaultIndex: ['auditbeat-users'], - docValueFields: [], ip: IP, flowTarget: FlowTarget.destination, sort: { field: NetworkUsersFields.name, direction: Direction.asc }, diff --git a/x-pack/test/api_integration/apis/security_solution/utils.ts b/x-pack/test/api_integration/apis/security_solution/utils.ts index 0c8406480a4fd..f5e65c6da3e7c 100644 --- a/x-pack/test/api_integration/apis/security_solution/utils.ts +++ b/x-pack/test/api_integration/apis/security_solution/utils.ts @@ -8,7 +8,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { TransportResult } from '@elastic/elasticsearch'; import type { Client } from '@elastic/elasticsearch'; -import { JsonObject, JsonArray } from '@kbn/utility-types'; +import { JsonObject } from '@kbn/utility-types'; export async function getSavedObjectFromES( es: Client, @@ -102,318 +102,3 @@ export const getFieldsToRequest = (): string[] => [ 'host.os.family', 'event.code', ]; - -/** - * https://www.elastic.co/guide/en/elasticsearch/reference/7.12/search-fields.html#docvalue-fields - * Use the docvalue_fields parameter to get values for selected fields. - * This can be a good choice when returning a fairly small number of fields that support doc values, - * such as keywords and dates. - */ -export const getDocValueFields = (): JsonArray => [ - { - field: '@timestamp', - }, - { - field: 'agent.ephemeral_id', - }, - { - field: 'agent.id', - }, - { - field: 'agent.name', - }, - { - field: 'agent.type', - }, - { - field: 'agent.version', - }, - { - field: 'as.number', - }, - { - field: 'as.organization.name', - }, - { - field: 'client.address', - }, - { - field: 'client.as.number', - }, - { - field: 'client.as.organization.name', - }, - { - field: 'client.bytes', - format: 'bytes', - }, - { - field: 'client.domain', - }, - { - field: 'client.geo.city_name', - }, - { - field: 'client.geo.continent_name', - }, - { - field: 'client.geo.country_iso_code', - }, - { - field: 'client.geo.country_name', - }, - { - field: 'client.geo.location', - }, - { - field: 'client.geo.name', - }, - { - field: 'client.geo.region_iso_code', - }, - { - field: 'client.geo.region_name', - }, - { - field: 'client.ip', - }, - { - field: 'client.mac', - }, - { - field: 'client.nat.ip', - }, - { - field: 'client.nat.port', - format: 'string', - }, - { - field: 'client.packets', - }, - { - field: 'client.port', - format: 'string', - }, - { - field: 'client.registered_domain', - }, - { - field: 'client.top_level_domain', - }, - { - field: 'client.user.domain', - }, - { - field: 'client.user.email', - }, - { - field: 'client.user.full_name', - }, - { - field: 'client.user.group.domain', - }, - { - field: 'client.user.group.id', - }, - { - field: 'client.user.group.name', - }, - { - field: 'client.user.hash', - }, - { - field: 'client.user.id', - }, - { - field: 'client.user.name', - }, - { - field: 'cloud.account.id', - }, - { - field: 'cloud.availability_zone', - }, - { - field: 'cloud.instance.id', - }, - { - field: 'cloud.instance.name', - }, - { - field: 'cloud.machine.type', - }, - { - field: 'cloud.provider', - }, - { - field: 'cloud.region', - }, - { - field: 'code_signature.exists', - }, - { - field: 'code_signature.status', - }, - { - field: 'code_signature.subject_name', - }, - { - field: 'code_signature.trusted', - }, - { - field: 'code_signature.valid', - }, - { - field: 'container.id', - }, - { - field: 'container.image.name', - }, - { - field: 'container.image.tag', - }, - { - field: 'container.name', - }, - { - field: 'container.runtime', - }, - { - field: 'destination.address', - }, - { - field: 'destination.as.number', - }, - { - field: 'destination.as.organization.name', - }, - { - field: 'destination.bytes', - format: 'bytes', - }, - { - field: 'destination.domain', - }, - { - field: 'destination.geo.city_name', - }, - { - field: 'destination.geo.continent_name', - }, - { - field: 'destination.geo.country_iso_code', - }, - { - field: 'destination.geo.country_name', - }, - { - field: 'destination.geo.location', - }, - { - field: 'destination.geo.name', - }, - { - field: 'destination.geo.region_iso_code', - }, - { - field: 'destination.geo.region_name', - }, - { - field: 'destination.ip', - }, - { - field: 'destination.mac', - }, - { - field: 'destination.nat.ip', - }, - { - field: 'destination.nat.port', - format: 'string', - }, - { - field: 'destination.packets', - }, - { - field: 'destination.port', - format: 'string', - }, - { - field: 'destination.registered_domain', - }, - { - field: 'destination.top_level_domain', - }, - { - field: 'destination.user.domain', - }, - { - field: 'destination.user.email', - }, - { - field: 'destination.user.full_name', - }, - { - field: 'destination.user.group.domain', - }, - { - field: 'destination.user.group.id', - }, - { - field: 'destination.user.group.name', - }, - { - field: 'destination.user.hash', - }, - { - field: 'destination.user.id', - }, - { - field: 'destination.user.name', - }, - { - field: 'dll.code_signature.exists', - }, - { - field: 'dll.code_signature.status', - }, - { - field: 'dll.code_signature.subject_name', - }, - { - field: 'dll.code_signature.trusted', - }, - { - field: 'dll.code_signature.valid', - }, - { - field: 'dll.hash.md5', - }, - { - field: 'dll.hash.sha1', - }, - { - field: 'dll.hash.sha256', - }, - { - field: 'dll.hash.sha512', - }, - { - field: 'dll.name', - }, - { - field: 'dll.path', - }, - { - field: 'dll.pe.company', - }, - { - field: 'dll.pe.description', - }, - { - field: 'dll.pe.file_version', - }, - { - field: 'dll.pe.original_file_name', - }, -]; diff --git a/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts b/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts index 828be46bd484a..5ab0bb94d1383 100644 --- a/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts +++ b/x-pack/test/timeline/security_and_spaces/tests/basic/events.ts @@ -69,20 +69,6 @@ export default ({ getService }: FtrProviderContext) => { const getPostBody = (): JsonObject => ({ defaultIndex: ['.alerts-*'], entityType: 'alerts', - docValueFields: [ - { - field: '@timestamp', - }, - { - field: ALERT_RULE_CONSUMER, - }, - { - field: ALERT_UUID, - }, - { - field: 'event.kind', - }, - ], factoryQueryType: TimelineEventsQueries.all, fieldRequested: ['@timestamp', 'message', ALERT_RULE_CONSUMER, ALERT_UUID, 'event.kind'], fields: [], diff --git a/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts b/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts index 7b2ea3d2cc1b7..89a5f6d7df442 100644 --- a/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts +++ b/x-pack/test/timeline/security_and_spaces/tests/trial/events.ts @@ -78,11 +78,6 @@ export default ({ getService }: FtrProviderContext) => { const getPostBody = (): JsonObject => ({ defaultIndex: ['.alerts-*'], entityType: 'alerts', - docValueFields: [ - { - field: '@timestamp', - }, - ], factoryQueryType: TimelineEventsQueries.all, fieldRequested: ['@timestamp'], fields: [], From 0212338e4e3ec9db5cfb4e93ad1850a156f0ea9b Mon Sep 17 00:00:00 2001 From: Ievgen Sorokopud Date: Tue, 23 Aug 2022 11:47:27 +0200 Subject: [PATCH 11/41] [Security Solution] Preview button is disable when create a rule by adding only a filter without adding any query (#139179) (#139226) --- .../public/detections/components/rules/rule_preview/helpers.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts index 9ee6628636ad4..266c0185745af 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/helpers.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { isEmpty } from 'lodash'; import { Position, ScaleType } from '@elastic/charts'; import type { EuiSelectOption } from '@elastic/eui'; import type { Type, Language, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; @@ -207,7 +208,7 @@ export const getIsRulePreviewDisabled = ({ return machineLearningJobId.length === 0; } if (ruleType === 'eql' || ruleType === 'query' || ruleType === 'threshold') { - return queryBar.query.query.length === 0; + return isEmpty(queryBar.query.query) && isEmpty(queryBar.filters); } if (ruleType === 'new_terms') { return newTermsFields.length === 0; From 767cb6b1c125229fe550a66d2ed616ebca649cdd Mon Sep 17 00:00:00 2001 From: Tomasz Ciecierski Date: Tue, 23 Aug 2022 13:31:15 +0200 Subject: [PATCH 12/41] [Osquery] Refactor to React hooks form (#138501) --- .../osquery/common/schemas/common/utils.ts | 11 +- .../cypress/integration/all/alerts.spec.ts | 4 +- .../all/edit_saved_queries.spec.ts | 7 +- .../integration/all/live_query.spec.ts | 24 +- .../cypress/integration/all/packs.spec.ts | 2 + .../cypress/integration/roles/admin.spec.ts | 1 - .../integration/roles/t1_analyst.spec.ts | 3 +- .../integration/roles/t2_analyst.spec.ts | 8 +- .../osquery/cypress/tasks/live_query.ts | 5 +- .../osquery/public/agents/agents_table.tsx | 5 +- .../plugins/osquery/public/common/helpers.ts | 3 +- .../osquery/public/common/validations.ts | 18 - .../plugins/osquery/public/editor/index.tsx | 2 +- x-pack/plugins/osquery/public/form/index.ts | 12 + .../osquery/public/form/interval_field.tsx | 82 +++ .../public/form/query_description_field.tsx | 49 ++ .../osquery/public/form/query_id_field.tsx | 52 ++ x-pack/plugins/osquery/public/form/types.ts | 28 + .../osquery/public/form/version_field.tsx | 88 +++ .../live_queries/form/agents_table_field.tsx | 50 +- .../public/live_queries/form/index.tsx | 299 +++++----- .../form/live_query_query_field.tsx | 45 +- .../form/packs_combobox_field.tsx | 99 ++-- .../public/live_queries/form/schema.ts | 57 -- .../osquery/public/live_queries/index.tsx | 3 +- .../public/packs/form/queries_field.tsx | 2 + .../queries/ecs_mapping_editor_field.tsx | 552 ++++++++---------- .../queries/platform_checkbox_group_field.tsx | 58 +- .../public/packs/queries/query_flyout.tsx | 107 ++-- .../osquery/public/packs/queries/schema.tsx | 77 --- .../packs/queries/use_pack_query_form.tsx | 179 +++--- .../public/packs/queries/validations.ts | 63 +- x-pack/plugins/osquery/public/packs/types.ts | 18 - .../osquery/public/results/results_table.tsx | 17 +- .../public/routes/saved_queries/edit/form.tsx | 36 +- .../public/routes/saved_queries/edit/tabs.tsx | 3 +- .../public/routes/saved_queries/new/form.tsx | 33 +- .../saved_queries/form/code_editor_field.tsx | 47 +- .../public/saved_queries/form/index.tsx | 26 +- .../saved_queries/form/playground_flyout.tsx | 10 +- .../form/use_saved_query_form.tsx | 147 +++-- .../saved_queries/saved_queries_dropdown.tsx | 5 +- .../saved_queries/saved_query_flyout.tsx | 41 +- .../saved_queries/use_update_saved_query.ts | 4 +- .../translations/translations/fr-FR.json | 7 +- .../translations/translations/ja-JP.json | 7 +- .../translations/translations/zh-CN.json | 7 +- 47 files changed, 1271 insertions(+), 1132 deletions(-) delete mode 100644 x-pack/plugins/osquery/public/common/validations.ts create mode 100644 x-pack/plugins/osquery/public/form/index.ts create mode 100644 x-pack/plugins/osquery/public/form/interval_field.tsx create mode 100644 x-pack/plugins/osquery/public/form/query_description_field.tsx create mode 100644 x-pack/plugins/osquery/public/form/query_id_field.tsx create mode 100644 x-pack/plugins/osquery/public/form/types.ts create mode 100644 x-pack/plugins/osquery/public/form/version_field.tsx delete mode 100644 x-pack/plugins/osquery/public/live_queries/form/schema.ts delete mode 100644 x-pack/plugins/osquery/public/packs/queries/schema.tsx diff --git a/x-pack/plugins/osquery/common/schemas/common/utils.ts b/x-pack/plugins/osquery/common/schemas/common/utils.ts index 95b2bdd7a4050..f599346fa0b6b 100644 --- a/x-pack/plugins/osquery/common/schemas/common/utils.ts +++ b/x-pack/plugins/osquery/common/schemas/common/utils.ts @@ -6,14 +6,7 @@ */ import { isEmpty, reduce } from 'lodash'; - -export const convertECSMappingToArray = (ecsMapping: Record | undefined) => - ecsMapping - ? Object.entries(ecsMapping).map((item) => ({ - key: item[0], - value: item[1], - })) - : undefined; +import type { ECSMapping } from './schemas'; export const convertECSMappingToObject = ( ecsMapping: Array<{ @@ -23,7 +16,7 @@ export const convertECSMappingToObject = ( value: string; }; }> -): Record => +): ECSMapping => reduce( ecsMapping, (acc, value) => { diff --git a/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts b/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts index ee4992b04b1d2..f0b07f89cde92 100644 --- a/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/all/alerts.spec.ts @@ -8,7 +8,6 @@ import { ArchiverMethod, runKbnArchiverScript } from '../../tasks/archiver'; import { login } from '../../tasks/login'; import { - checkResults, findAndClickButton, findFormFieldByRowsLabelAndType, inputQuery, @@ -80,7 +79,8 @@ describe('Alert Event Details', () => { cy.contains('1 agent selected.'); inputQuery('select * from uptime;'); submitQuery(); - checkResults(); + cy.contains('Results'); + cy.contains('Add to timeline investigation'); cy.contains('Save for later').click(); cy.contains('Save query'); cy.get('.euiButtonEmpty--flushLeft').contains('Cancel').click(); diff --git a/x-pack/plugins/osquery/cypress/integration/all/edit_saved_queries.spec.ts b/x-pack/plugins/osquery/cypress/integration/all/edit_saved_queries.spec.ts index bc42f529f8137..42ffd48d73692 100644 --- a/x-pack/plugins/osquery/cypress/integration/all/edit_saved_queries.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/all/edit_saved_queries.spec.ts @@ -32,10 +32,9 @@ describe('ALL - Edit saved query', () => { }).click(); cy.contains('Custom key/value pairs.').should('exist'); cy.contains('Hours of uptime').should('exist'); - cy.react('ECSComboboxFieldComponent', { props: { field: { value: 'labels' } } }) - .parents('[data-test-subj="ECSMappingEditorForm"]') - .react('EuiButtonIcon', { props: { iconType: 'trash' } }) - .click(); + cy.react('ECSMappingEditorForm').within(() => { + cy.react('EuiButtonIcon', { props: { iconType: 'trash' } }).click(); + }); cy.react('PlatformCheckBoxGroupField').within(() => { cy.react('EuiCheckbox', { diff --git a/x-pack/plugins/osquery/cypress/integration/all/live_query.spec.ts b/x-pack/plugins/osquery/cypress/integration/all/live_query.spec.ts index 0678f3170f234..c332e3dae5087 100644 --- a/x-pack/plugins/osquery/cypress/integration/all/live_query.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/all/live_query.spec.ts @@ -41,6 +41,28 @@ describe('ALL - Live Query', () => { runKbnArchiverScript(ArchiverMethod.UNLOAD, 'example_pack'); }); + it('should validate the form', () => { + cy.contains('New live query').click(); + submitQuery(); + cy.contains('Agents is a required field'); + cy.contains('Query is a required field'); + selectAllAgents(); + inputQuery('select * from uptime; '); + submitQuery(); + cy.contains('Agents is a required field').should('not.exist'); + cy.contains('Query is a required field').should('not.exist'); + checkResults(); + getAdvancedButton().click(); + typeInOsqueryFieldInput('days{downArrow}{enter}'); + submitQuery(); + cy.contains('ECS field is required.'); + typeInECSFieldInput('message{downArrow}{enter}'); + submitQuery(); + cy.contains('ECS field is required.').should('not.exist'); + + checkResults(); + }); + it('should run query and enable ecs mapping', () => { const cmd = Cypress.platform === 'darwin' ? '{meta}{enter}' : '{ctrl}{enter}'; cy.contains('New live query').click(); @@ -82,7 +104,7 @@ describe('ALL - Live Query', () => { cy.contains('New live query').click(); selectAllAgents(); cy.react('SavedQueriesDropdown').type('NOMAPPING{downArrow}{enter}'); - cy.getReact('SavedQueriesDropdown').getCurrentState().should('have.length', 1); + // cy.getReact('SavedQueriesDropdown').getCurrentState().should('have.length', 1); // TODO do we need it? inputQuery('{selectall}{backspace}{selectall}{backspace}select * from users'); cy.wait(1000); submitQuery(); diff --git a/x-pack/plugins/osquery/cypress/integration/all/packs.spec.ts b/x-pack/plugins/osquery/cypress/integration/all/packs.spec.ts index 72fae5479a85e..64620cf3cc08c 100644 --- a/x-pack/plugins/osquery/cypress/integration/all/packs.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/all/packs.spec.ts @@ -77,6 +77,7 @@ describe('ALL - Packs', () => { cy.contains('Attach next query'); inputQuery('select * from uptime'); findFormFieldByRowsLabelAndType('ID', SAVED_QUERY_ID); + cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click(); cy.contains('ID must be unique').should('exist'); findFormFieldByRowsLabelAndType('ID', NEW_QUERY_NAME); cy.contains('ID must be unique').should('not.exist'); @@ -95,6 +96,7 @@ describe('ALL - Packs', () => { cy.contains('Attach next query'); cy.contains('ID must be unique').should('not.exist'); getSavedQueriesDropdown().type(`${SAVED_QUERY_ID}{downArrow}{enter}`); + cy.react('EuiFlyoutFooter').react('EuiButton').contains('Save').click(); cy.contains('ID must be unique').should('exist'); cy.react('EuiFlyoutFooter').react('EuiButtonEmpty').contains('Cancel').click(); }); diff --git a/x-pack/plugins/osquery/cypress/integration/roles/admin.spec.ts b/x-pack/plugins/osquery/cypress/integration/roles/admin.spec.ts index a22177955c4ac..b8781df09d01f 100644 --- a/x-pack/plugins/osquery/cypress/integration/roles/admin.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/roles/admin.spec.ts @@ -20,7 +20,6 @@ describe('Admin', () => { cy.contains('New live query').click(); selectAllAgents(); inputQuery('select * from uptime; '); - cy.wait(500); submitQuery(); checkResults(); }); diff --git a/x-pack/plugins/osquery/cypress/integration/roles/t1_analyst.spec.ts b/x-pack/plugins/osquery/cypress/integration/roles/t1_analyst.spec.ts index 2920cf8521ac6..d236555091b3f 100644 --- a/x-pack/plugins/osquery/cypress/integration/roles/t1_analyst.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/roles/t1_analyst.spec.ts @@ -94,6 +94,7 @@ describe('T1 Analyst - READ + runSavedQueries ', () => { cy.contains('New live query').click(); selectAllAgents(); cy.get(LIVE_QUERY_EDITOR).should('not.exist'); - cy.contains('Submit').should('be.disabled'); + submitQuery(); + cy.contains('Query is a required field'); }); }); diff --git a/x-pack/plugins/osquery/cypress/integration/roles/t2_analyst.spec.ts b/x-pack/plugins/osquery/cypress/integration/roles/t2_analyst.spec.ts index 9b73a01ac41c1..63a0eb5d1619d 100644 --- a/x-pack/plugins/osquery/cypress/integration/roles/t2_analyst.spec.ts +++ b/x-pack/plugins/osquery/cypress/integration/roles/t2_analyst.spec.ts @@ -101,15 +101,15 @@ describe('T2 Analyst - READ + Write Live/Saved + runSavedQueries ', () => { it('to click the edit button and edit pack', () => { navigateTo('/app/osquery/saved_queries'); cy.getBySel('pagination-button-next').click(); + cy.react('CustomItemAction', { props: { index: 1, item: { attributes: { id: SAVED_QUERY_ID } } }, }).click(); cy.contains('Custom key/value pairs.').should('exist'); cy.contains('Hours of uptime').should('exist'); - cy.react('ECSComboboxFieldComponent', { props: { field: { value: 'labels' } } }) - .parents('[data-test-subj="ECSMappingEditorForm"]') - .react('EuiButtonIcon', { props: { iconType: 'trash' } }) - .click(); + cy.react('ECSMappingEditorForm').within(() => { + cy.react('EuiButtonIcon', { props: { iconType: 'trash' } }).click(); + }); cy.react('EuiButton').contains('Update query').click(); cy.wait(5000); diff --git a/x-pack/plugins/osquery/cypress/tasks/live_query.ts b/x-pack/plugins/osquery/cypress/tasks/live_query.ts index 140b5698f55b5..3c571d04ff84c 100644 --- a/x-pack/plugins/osquery/cypress/tasks/live_query.ts +++ b/x-pack/plugins/osquery/cypress/tasks/live_query.ts @@ -25,7 +25,10 @@ export const clearInputQuery = () => export const inputQuery = (query: string) => cy.get(LIVE_QUERY_EDITOR).type(query); -export const submitQuery = () => cy.contains('Submit').click(); +export const submitQuery = () => { + cy.wait(1000); // wait for the validation to trigger - cypress is way faster than users ;) + cy.contains('Submit').click(); +}; export const checkResults = () => cy.getBySel('dataGridRowCell', { timeout: 120000 }).should('have.lengthOf.above', 0); diff --git a/x-pack/plugins/osquery/public/agents/agents_table.tsx b/x-pack/plugins/osquery/public/agents/agents_table.tsx index e11cb9b8277d9..2d05780d6545f 100644 --- a/x-pack/plugins/osquery/public/agents/agents_table.tsx +++ b/x-pack/plugins/osquery/public/agents/agents_table.tsx @@ -35,12 +35,13 @@ import { AGENT_GROUP_KEY } from './types'; interface AgentsTableProps { agentSelection: AgentSelection; onChange: (payload: AgentSelection) => void; + error?: string; } const perPage = 10; const DEBOUNCE_DELAY = 300; // ms -const AgentsTableComponent: React.FC = ({ agentSelection, onChange }) => { +const AgentsTableComponent: React.FC = ({ agentSelection, onChange, error }) => { // search related const [searchValue, setSearchValue] = useState(''); const [modifyingSearch, setModifyingSearch] = useState(false); @@ -185,7 +186,7 @@ const AgentsTableComponent: React.FC = ({ agentSelection, onCh return (
- + isString(filterQuery) ? filterQuery : JSON.stringify(filterQuery); @@ -44,7 +43,7 @@ export const getInspectResponse = ( response != null ? [JSON.stringify(response.rawResponse, null, 2)] : prevResponse?.response, }); -export const prepareEcsFieldsToValidate = (ecsMapping: ArrayItem[]): string[] => +export const prepareEcsFieldsToValidate = (ecsMapping: Array<{ id: string }>): string[] => ecsMapping ?.map((_: unknown, index: number) => [ `ecs_mapping[${index}].result.value`, diff --git a/x-pack/plugins/osquery/public/common/validations.ts b/x-pack/plugins/osquery/public/common/validations.ts deleted file mode 100644 index 4a29d274fcc0c..0000000000000 --- a/x-pack/plugins/osquery/public/common/validations.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 { i18n } from '@kbn/i18n'; - -import type { FormData, ValidationFunc } from '../shared_imports'; -import { fieldValidators } from '../shared_imports'; - -export const queryFieldValidation: ValidationFunc = - fieldValidators.emptyField( - i18n.translate('xpack.osquery.pack.queryFlyoutForm.emptyQueryError', { - defaultMessage: 'Query is a required field', - }) - ); diff --git a/x-pack/plugins/osquery/public/editor/index.tsx b/x-pack/plugins/osquery/public/editor/index.tsx index 2c6a505af55cd..583e3558354e8 100644 --- a/x-pack/plugins/osquery/public/editor/index.tsx +++ b/x-pack/plugins/osquery/public/editor/index.tsx @@ -7,12 +7,12 @@ import React, { useEffect, useState } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; -import 'brace/theme/tomorrow'; import type { EuiCodeEditorProps } from '../shared_imports'; import { EuiCodeEditor } from '../shared_imports'; import './osquery_mode'; +import 'brace/theme/tomorrow'; const EDITOR_SET_OPTIONS = { enableBasicAutocompletion: true, diff --git a/x-pack/plugins/osquery/public/form/index.ts b/x-pack/plugins/osquery/public/form/index.ts new file mode 100644 index 0000000000000..31ea2ac171c88 --- /dev/null +++ b/x-pack/plugins/osquery/public/form/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { VersionField } from './version_field'; +export { QueryDescriptionField } from './query_description_field'; +export { IntervalField } from './interval_field'; +export { QueryIdField } from './query_id_field'; +export type { FormField } from './types'; diff --git a/x-pack/plugins/osquery/public/form/interval_field.tsx b/x-pack/plugins/osquery/public/form/interval_field.tsx new file mode 100644 index 0000000000000..d8d1a01804d65 --- /dev/null +++ b/x-pack/plugins/osquery/public/form/interval_field.tsx @@ -0,0 +1,82 @@ +/* + * 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, { useCallback, useMemo } from 'react'; + +import { useController } from 'react-hook-form'; +import type { EuiFieldNumberProps } from '@elastic/eui'; +import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +const intervalFieldValidations = { + required: { + message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldMinNumberError', { + defaultMessage: 'A positive interval value is required', + }), + value: true, + }, + min: { + message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldMinNumberError', { + defaultMessage: 'A positive interval value is required', + }), + value: 1, + }, + max: { + message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldMaxNumberError', { + defaultMessage: 'An interval value must be lower than {than}', + values: { than: 604800 }, + }), + value: 604800, + }, +}; + +interface IntervalFieldProps { + euiFieldProps?: Record; +} + +const IntervalFieldComponent = ({ euiFieldProps }: IntervalFieldProps) => { + const { + field: { onChange, value }, + fieldState: { error }, + } = useController({ + name: 'interval', + defaultValue: 3600, + rules: { + ...intervalFieldValidations, + }, + }); + const handleChange = useCallback( + (e: React.ChangeEvent) => { + const numberValue = e.target.valueAsNumber ? e.target.valueAsNumber : 0; + onChange(numberValue); + }, + [onChange] + ); + const hasError = useMemo(() => !!error?.message, [error?.message]); + + return ( + + + + ); +}; + +export const IntervalField = React.memo(IntervalFieldComponent); diff --git a/x-pack/plugins/osquery/public/form/query_description_field.tsx b/x-pack/plugins/osquery/public/form/query_description_field.tsx new file mode 100644 index 0000000000000..ae4a216b603f5 --- /dev/null +++ b/x-pack/plugins/osquery/public/form/query_description_field.tsx @@ -0,0 +1,49 @@ +/* + * 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, { useMemo } from 'react'; +import { useController } from 'react-hook-form'; +import { EuiFieldText, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +interface QueryDescriptionFieldProps { + euiFieldProps?: Record; +} + +const QueryDescriptionFieldComponentn = ({ euiFieldProps }: QueryDescriptionFieldProps) => { + const { + field: { onChange, value, name: fieldName }, + fieldState: { error }, + } = useController({ + name: 'description', + defaultValue: '', + }); + + const hasError = useMemo(() => !!error?.message, [error?.message]); + + return ( + + + + ); +}; + +export const QueryDescriptionField = React.memo(QueryDescriptionFieldComponentn); diff --git a/x-pack/plugins/osquery/public/form/query_id_field.tsx b/x-pack/plugins/osquery/public/form/query_id_field.tsx new file mode 100644 index 0000000000000..1c0abfde5113f --- /dev/null +++ b/x-pack/plugins/osquery/public/form/query_id_field.tsx @@ -0,0 +1,52 @@ +/* + * 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, { useMemo } from 'react'; +import { useController } from 'react-hook-form'; +import { EuiFieldText, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { createFormIdFieldValidations } from '../packs/queries/validations'; + +interface QueryIdFieldProps { + idSet?: Set; + euiFieldProps?: Record; +} + +const QueryIdFieldComponentn = ({ idSet, euiFieldProps }: QueryIdFieldProps) => { + const { + field: { onChange, value, name: fieldName }, + fieldState: { error }, + } = useController({ + name: 'id', + defaultValue: '', + rules: idSet && createFormIdFieldValidations(idSet), + }); + + const hasError = useMemo(() => !!error?.message, [error?.message]); + + return ( + + + + ); +}; + +export const QueryIdField = React.memo(QueryIdFieldComponentn); diff --git a/x-pack/plugins/osquery/public/form/types.ts b/x-pack/plugins/osquery/public/form/types.ts new file mode 100644 index 0000000000000..14f013ac2b012 --- /dev/null +++ b/x-pack/plugins/osquery/public/form/types.ts @@ -0,0 +1,28 @@ +/* + * 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 type React from 'react'; +import type { ReactNode } from 'react'; + +export interface FormField { + name: string; + onChange: (data: T) => void; + value: T; + onBlur?: () => void; +} + +export interface FormFieldProps { + name: string; + label: string | Element; + labelAppend?: ReactNode; + helpText?: string | (() => React.ReactNode); + idAria?: string; + euiFieldProps?: Record; + defaultValue?: T; + required?: boolean; + rules?: Record; +} diff --git a/x-pack/plugins/osquery/public/form/version_field.tsx b/x-pack/plugins/osquery/public/form/version_field.tsx new file mode 100644 index 0000000000000..f97e26b79a651 --- /dev/null +++ b/x-pack/plugins/osquery/public/form/version_field.tsx @@ -0,0 +1,88 @@ +/* + * 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, { useCallback, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import type { EuiComboBoxOptionOption } from '@elastic/eui'; +import { EuiFormRow, EuiComboBox, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { useController } from 'react-hook-form'; +import { FormattedMessage } from '@kbn/i18n-react'; + +interface VersionFieldProps { + euiFieldProps?: Record; +} +const VersionFieldComponent = ({ euiFieldProps = {} }: VersionFieldProps) => { + const { + field: { onChange, value }, + fieldState: { error }, + } = useController({ + name: 'version', + defaultValue: [], + rules: {}, + }); + + const onCreateComboOption = useCallback( + (newValue: string) => { + const result = [...(value as string[]), newValue]; + + onChange(result); + }, + [onChange, value] + ); + + const onComboChange = useCallback( + (options: EuiComboBoxOptionOption[]) => { + onChange(options.map((option) => option.label)); + }, + [onChange] + ); + const hasError = useMemo(() => !!error?.message, [error?.message]); + + return ( + + + + + + } + labelAppend={ + + + + + + } + error={error?.message} + isInvalid={hasError} + fullWidth + > + ({ label: v }))} + onCreateOption={onCreateComboOption} + onChange={onComboChange} + fullWidth + data-test-subj="input" + {...euiFieldProps} + /> + + ); +}; + +export const VersionField = React.memo(VersionFieldComponent); diff --git a/x-pack/plugins/osquery/public/live_queries/form/agents_table_field.tsx b/x-pack/plugins/osquery/public/live_queries/form/agents_table_field.tsx index b4fd3bdaf216c..eab43c5982b80 100644 --- a/x-pack/plugins/osquery/public/live_queries/form/agents_table_field.tsx +++ b/x-pack/plugins/osquery/public/live_queries/form/agents_table_field.tsx @@ -5,27 +5,47 @@ * 2.0. */ -import React, { useCallback } from 'react'; -import type { FieldHook } from '../../shared_imports'; +import React from 'react'; +import { useController } from 'react-hook-form'; +import { isEmpty } from 'lodash'; +import { i18n } from '@kbn/i18n'; import { AgentsTable } from '../../agents/agents_table'; import type { AgentSelection } from '../../agents/types'; -interface AgentsTableFieldProps { - field: FieldHook; -} +const checkAgentsLength = (agentsSelection: AgentSelection) => { + if (!isEmpty(agentsSelection)) { + const isValid = !!( + agentsSelection.allAgentsSelected || + agentsSelection.agents?.length || + agentsSelection.platformsSelected?.length || + agentsSelection.policiesSelected?.length + ); -const AgentsTableFieldComponent: React.FC = ({ field }) => { - const { value, setValue } = field; - const handleChange = useCallback( - (props) => { - if (props !== value) { - return setValue(props); - } + return !isValid + ? i18n.translate('xpack.osquery.pack.queryFlyoutForm.osqueryAgentsMissingErrorMessage', { + defaultMessage: 'Agents is a required field', + }) + : undefined; + } + + return i18n.translate('xpack.osquery.pack.queryFlyoutForm.osqueryAgentsMissingErrorMessage', { + defaultMessage: 'Agents is a required field', + }); +}; + +const AgentsTableFieldComponent: React.FC<{}> = () => { + const { + field: { onChange, value }, + fieldState: { error }, + } = useController({ + name: 'agentSelection', + rules: { + validate: checkAgentsLength, }, - [value, setValue] - ); + defaultValue: {}, + }); - return ; + return ; }; export const AgentsTableField = React.memo(AgentsTableFieldComponent); diff --git a/x-pack/plugins/osquery/public/live_queries/form/index.tsx b/x-pack/plugins/osquery/public/live_queries/form/index.tsx index ed4059884a9af..3ed54c451f38b 100644 --- a/x-pack/plugins/osquery/public/live_queries/form/index.tsx +++ b/x-pack/plugins/osquery/public/live_queries/form/index.tsx @@ -19,27 +19,47 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; +import { useForm as useHookForm, FormProvider } from 'react-hook-form'; -import { pickBy, isEmpty, map, find } from 'lodash'; +import { isEmpty, map, find, pickBy } from 'lodash'; import { i18n } from '@kbn/i18n'; +import type { SavedQuerySOFormData } from '../../saved_queries/form/use_saved_query_form'; +import type { + EcsMappingFormField, + EcsMappingSerialized, +} from '../../packs/queries/ecs_mapping_editor_field'; +import { defaultEcsFormData } from '../../packs/queries/ecs_mapping_editor_field'; import { convertECSMappingToObject } from '../../../common/schemas/common/utils'; -import type { FormData } from '../../shared_imports'; -import { UseField, Form, useForm, useFormData } from '../../shared_imports'; -import { AgentsTableField } from './agents_table_field'; -import { LiveQueryQueryField } from './live_query_query_field'; import { useKibana } from '../../common/lib/kibana'; import { ResultTabs } from '../../routes/saved_queries/edit/tabs'; import { SavedQueryFlyout } from '../../saved_queries'; import { ECSMappingEditorField } from '../../packs/queries/lazy_ecs_mapping_editor_field'; import { SavedQueriesDropdown } from '../../saved_queries/saved_queries_dropdown'; -import { liveQueryFormSchema } from './schema'; import { usePacks } from '../../packs/use_packs'; import { PackQueriesStatusTable } from './pack_queries_status_table'; import { useCreateLiveQuery } from '../use_create_live_query_action'; import { useLiveQueryDetails } from '../../actions/use_live_query_details'; +import type { AgentSelection } from '../../agents/types'; +import { LiveQueryQueryField } from './live_query_query_field'; +import { AgentsTableField } from './agents_table_field'; import { PacksComboBoxField } from './packs_combobox_field'; +import { savedQueryDataSerializer } from '../../saved_queries/form/use_saved_query_form'; + +export interface LiveQueryFormFields { + query?: string; + agentSelection: AgentSelection; + savedQueryId?: string | null; + ecs_mapping: EcsMappingFormField[]; + packId: string[]; +} -const FORM_ID = 'liveQueryForm'; +interface DefaultLiveQueryFormFields { + query?: string; + agentSelection?: AgentSelection; + savedQueryId?: string | null; + ecs_mapping?: EcsMappingSerialized; + packId?: string; +} const StyledEuiCard = styled(EuiCard)` padding: 16px 92px 16px 16px !important; @@ -86,12 +106,10 @@ const StyledEuiAccordion = styled(EuiAccordion)` } `; -const GhostFormField = () => <>; - type FormType = 'simple' | 'steps'; interface LiveQueryFormProps { - defaultValue?: Partial; + defaultValue?: DefaultLiveQueryFormFields; onSuccess?: () => void; queryField?: boolean; ecsMappingField?: boolean; @@ -118,6 +136,22 @@ const LiveQueryFormComponent: React.FC = ({ [permissions] ); + const hooksForm = useHookForm({ + defaultValues: { + ecs_mapping: [defaultEcsFormData], + }, + }); + const { + handleSubmit, + watch, + setValue, + resetField, + clearErrors, + getFieldState, + register, + formState: { isSubmitting, errors }, + } = hooksForm; + const canRunSingleQuery = useMemo( () => !!( @@ -133,6 +167,8 @@ const LiveQueryFormComponent: React.FC = ({ const [queryType, setQueryType] = useState('query'); const [isLive, setIsLive] = useState(false); + const queryState = getFieldState('query'); + const watchedValues = watch(); const handleShowSaveQueryFlyout = useCallback(() => setShowSavedQueryFlyout(true), []); const handleCloseSaveQueryFlyout = useCallback(() => setShowSavedQueryFlyout(false), []); @@ -150,75 +186,22 @@ const LiveQueryFormComponent: React.FC = ({ isLive, }); - const { form } = useForm({ - id: FORM_ID, - schema: liveQueryFormSchema, - onSubmit: async (formData, isValid) => { - if (isValid) { - try { - // @ts-expect-error update types - await mutateAsync(formData); - // eslint-disable-next-line no-empty - } catch (e) {} - } - }, - options: { - stripEmptyFields: false, - }, - serializer: ({ - savedQueryId, - // eslint-disable-next-line @typescript-eslint/naming-convention - ecs_mapping, - packId, - ...formData - }) => - pickBy( - { - ...formData, - pack_id: packId?.length ? packId[0] : undefined, - saved_query_id: savedQueryId, - ecs_mapping: convertECSMappingToObject(ecs_mapping), - }, - (value) => !isEmpty(value) - ), - }); - - const { updateFieldValues, setFieldValue, submit, isSubmitting } = form; - const actionId = useMemo(() => liveQueryDetails?.action_id, [liveQueryDetails?.action_id]); const agentIds = useMemo(() => liveQueryDetails?.agents, [liveQueryDetails?.agents]); - const [ - { agentSelection, ecs_mapping: ecsMapping, query, savedQueryId, packId }, - formDataSerializer, - ] = useFormData({ - form, - }); - /* recalculate the form data when ecs_mapping changes */ - // eslint-disable-next-line react-hooks/exhaustive-deps - const serializedFormData = useMemo(() => formDataSerializer(), [ecsMapping, formDataSerializer]); - - const agentSelected = useMemo( - () => - agentSelection && - !!( - agentSelection.allAgentsSelected || - agentSelection.agents?.length || - agentSelection.platformsSelected?.length || - agentSelection.policiesSelected?.length - ), - [agentSelection] - ); + useEffect(() => { + register('savedQueryId'); + }, [register]); - const queryValueProvided = useMemo(() => !!query?.length, [query]); + const { packId } = watchedValues; const queryStatus = useMemo(() => { - if (isError || !form.getFields().query?.isValid) return 'danger'; + if (isError || queryState.invalid) return 'danger'; if (isLoading) return 'loading'; if (isSuccess) return 'complete'; return 'incomplete'; - }, [isError, isLoading, isSuccess, form]); + }, [isError, isLoading, isSuccess, queryState]); const resultsStatus = useMemo( () => (queryStatus === 'complete' ? 'incomplete' : 'disabled'), @@ -228,39 +211,66 @@ const LiveQueryFormComponent: React.FC = ({ const handleSavedQueryChange = useCallback( (savedQuery) => { if (savedQuery) { - updateFieldValues({ - query: savedQuery.query, - savedQueryId: savedQuery.savedQueryId, - ecs_mapping: savedQuery.ecs_mapping + setValue('query', savedQuery.query); + setValue('savedQueryId', savedQuery.savedQueryId); + setValue( + 'ecs_mapping', + !isEmpty(savedQuery.ecs_mapping) ? map(savedQuery.ecs_mapping, (value, key) => ({ key, result: { type: Object.keys(value)[0], - value: Object.values(value)[0], + value: Object.values(value)[0] as string, }, })) - : [], - }); + : [defaultEcsFormData] + ); if (!isEmpty(savedQuery.ecs_mapping)) { setAdvancedContentState('open'); } } else { - setFieldValue('savedQueryId', null); + setValue('savedQueryId', null); } }, - [setFieldValue, updateFieldValues] + [setValue] ); + const onSubmit = useCallback( + // not sure why, but submitOnCmdEnter doesn't have proper form values so I am passing them in manually + async (values: LiveQueryFormFields = watchedValues) => { + const serializedData = pickBy( + { + agentSelection: values.agentSelection, + saved_query_id: values.savedQueryId, + query: values.query, + pack_id: packId?.length ? packId[0] : undefined, + ...(values.ecs_mapping + ? { ecs_mapping: convertECSMappingToObject(values.ecs_mapping) } + : {}), + }, + (value) => !isEmpty(value) + ); + if (isEmpty(errors)) { + try { + // @ts-expect-error update types + await mutateAsync(serializedData); + // eslint-disable-next-line no-empty + } catch (e) {} + } + }, + [errors, mutateAsync, packId, watchedValues] + ); const commands = useMemo( () => [ { name: 'submitOnCmdEnter', bindKey: { win: 'ctrl+enter', mac: 'cmd+enter' }, - exec: () => submit(), + // @ts-expect-error update types - explanation in onSubmit() + exec: () => handleSubmit(onSubmit)(watchedValues), }, ], - [submit] + [handleSubmit, onSubmit, watchedValues] ); const queryComponentProps = useMemo( @@ -270,9 +280,9 @@ const LiveQueryFormComponent: React.FC = ({ [commands] ); - const flyoutFormDefaultValue = useMemo( - () => ({ savedQueryId, query, ecs_mapping: serializedFormData.ecs_mapping }), - [savedQueryId, serializedFormData.ecs_mapping, query] + const serializedData: SavedQuerySOFormData = useMemo( + () => savedQueryDataSerializer(watchedValues), + [watchedValues] ); const handleToggle = useCallback((isOpen) => { @@ -306,12 +316,7 @@ const LiveQueryFormComponent: React.FC = ({ {formType === 'steps' && queryType !== 'pack' && ( = ({ = ({ ), [ - agentSelected, - enabled, formType, - handleShowSaveQueryFlyout, - isSubmitting, - packId, - permissions.writeSavedQueries, queryType, - queryValueProvided, + permissions.writeSavedQueries, resultsStatus, - selectedPackData, - submit, + handleShowSaveQueryFlyout, + enabled, + isSubmitting, + handleSubmit, + onSubmit, ] ); const queryFieldStepContent = useMemo( () => ( <> - {queryField ? ( + {queryField && ( <> {!isSavedQueryDisabled && ( <> @@ -372,20 +367,10 @@ const LiveQueryFormComponent: React.FC = ({ /> )} - - - - ) : ( - <> - - + )} - {ecsMappingField ? ( + {ecsMappingField && ( <> = ({ - ) : ( - )} ), [ queryField, - queryComponentProps, + isSavedQueryDisabled, handleSavedQueryChange, + queryComponentProps, + queryType, ecsMappingField, advancedContentState, handleToggle, ecsFieldProps, - isSavedQueryDisabled, ] ); @@ -422,7 +406,7 @@ const LiveQueryFormComponent: React.FC = ({ singleQueryDetails?.action_id ? ( = ({ singleQueryDetails?.action_id, singleQueryDetails?.expiration, singleQueryDetails?.agents, - serializedFormData.ecs_mapping, + serializedData.ecs_mapping, addToTimeline, ] ); @@ -440,9 +424,7 @@ const LiveQueryFormComponent: React.FC = ({ useEffect(() => { if (defaultValue) { if (defaultValue.agentSelection) { - updateFieldValues({ - agentSelection: defaultValue.agentSelection, - }); + setValue('agentSelection', defaultValue.agentSelection); } if (defaultValue?.packId && canRunPacks) { @@ -451,19 +433,18 @@ const LiveQueryFormComponent: React.FC = ({ if (!isPackDataFetched) return; const selectedPackOption = find(packsData?.data, ['id', defaultValue.packId]); if (selectedPackOption) { - updateFieldValues({ - packId: [defaultValue.packId], - }); + setValue('packId', [defaultValue.packId]); } return; } if (defaultValue?.query && canRunSingleQuery) { - updateFieldValues({ - query: defaultValue.query, - savedQueryId: defaultValue.savedQueryId, - ecs_mapping: defaultValue.ecs_mapping + setValue('query', defaultValue.query); + setValue('savedQueryId', defaultValue.savedQueryId); + setValue( + 'ecs_mapping', + !isEmpty(defaultValue.ecs_mapping) ? map(defaultValue.ecs_mapping, (value, key) => ({ key, result: { @@ -471,8 +452,8 @@ const LiveQueryFormComponent: React.FC = ({ value: Object.values(value)[0], }, })) - : undefined, - }); + : [defaultEcsFormData] + ); return; } @@ -485,14 +466,7 @@ const LiveQueryFormComponent: React.FC = ({ return setQueryType('pack'); } } - }, [ - canRunPacks, - canRunSingleQuery, - defaultValue, - isPackDataFetched, - packsData?.data, - updateFieldValues, - ]); + }, [canRunPacks, canRunSingleQuery, defaultValue, isPackDataFetched, packsData?.data, setValue]); const queryCardSelectable = useMemo( () => ({ @@ -516,11 +490,20 @@ const LiveQueryFormComponent: React.FC = ({ setIsLive(() => !(liveQueryDetails?.status === 'completed')); }, [liveQueryDetails?.status]); - useEffect(() => cleanupLiveQuery(), [queryType, packId, cleanupLiveQuery]); + useEffect(() => { + cleanupLiveQuery(); + if (!defaultValue) { + resetField('packId'); + resetField('query'); + resetField('ecs_mapping'); + resetField('savedQueryId'); + clearErrors(); + } + }, [queryType, cleanupLiveQuery, resetField, setValue, clearErrors, defaultValue]); return ( <> -
+ {queryField && ( @@ -572,25 +555,23 @@ const LiveQueryFormComponent: React.FC = ({ )} - {!hideAgentsField ? ( + {!hideAgentsField && ( - + - ) : ( - )} {queryType === 'pack' ? ( <> - {submitButtonContent} + {liveQueryDetails?.queries?.length || selectedPackData?.attributes?.queries?.length ? ( <> @@ -598,6 +579,7 @@ const LiveQueryFormComponent: React.FC = ({ @@ -613,12 +595,13 @@ const LiveQueryFormComponent: React.FC = ({ )} - +
+ {showSavedQueryFlyout ? ( ) : null} diff --git a/x-pack/plugins/osquery/public/live_queries/form/live_query_query_field.tsx b/x-pack/plugins/osquery/public/live_queries/form/live_query_query_field.tsx index 86775040c7f73..e3516f982cc0b 100644 --- a/x-pack/plugins/osquery/public/live_queries/form/live_query_query_field.tsx +++ b/x-pack/plugins/osquery/public/live_queries/form/live_query_query_field.tsx @@ -6,12 +6,15 @@ */ import { EuiCodeBlock, EuiFormRow } from '@elastic/eui'; -import React, { useCallback } from 'react'; +import React from 'react'; import styled from 'styled-components'; -import type { EuiCodeEditorProps, FieldHook } from '../../shared_imports'; +import { useController } from 'react-hook-form'; +import { i18n } from '@kbn/i18n'; +import type { EuiCodeEditorProps } from '../../shared_imports'; import { OsqueryEditor } from '../../editor'; import { useKibana } from '../../common/lib/kibana'; +import { MAX_QUERY_LENGTH } from '../../packs/queries/validations'; const StyledEuiCodeBlock = styled(EuiCodeBlock)` min-height: 100px; @@ -19,30 +22,44 @@ const StyledEuiCodeBlock = styled(EuiCodeBlock)` interface LiveQueryQueryFieldProps { disabled?: boolean; - field: FieldHook; commands?: EuiCodeEditorProps['commands']; + queryType: string; } const LiveQueryQueryFieldComponent: React.FC = ({ disabled, - field, commands, + queryType, }) => { const permissions = useKibana().services.application.capabilities.osquery; - const { value, setValue, errors } = field; - const error = errors[0]?.message; - const handleEditorChange = useCallback( - (newValue) => { - setValue(newValue); + const { + field: { onChange, value }, + fieldState: { error }, + } = useController({ + name: 'query', + rules: { + required: { + message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.emptyQueryError', { + defaultMessage: 'Query is a required field', + }), + value: queryType === 'query', + }, + maxLength: { + message: i18n.translate('xpack.osquery.liveQuery.queryForm.largeQueryError', { + defaultMessage: 'Query is too large (max {maxLength} characters)', + values: { maxLength: MAX_QUERY_LENGTH }, + }), + value: MAX_QUERY_LENGTH, + }, }, - [setValue] - ); + defaultValue: '', + }); return ( @@ -56,7 +73,7 @@ const LiveQueryQueryFieldComponent: React.FC = ({ {value} ) : ( - + )} ); diff --git a/x-pack/plugins/osquery/public/live_queries/form/packs_combobox_field.tsx b/x-pack/plugins/osquery/public/live_queries/form/packs_combobox_field.tsx index e9cf7fa6f9e85..0d6c93d23ed30 100644 --- a/x-pack/plugins/osquery/public/live_queries/form/packs_combobox_field.tsx +++ b/x-pack/plugins/osquery/public/live_queries/form/packs_combobox_field.tsx @@ -12,8 +12,7 @@ import type { EuiComboBoxOptionOption } from '@elastic/eui'; import { EuiFormRow, EuiComboBox, EuiTextColor, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import styled from 'styled-components'; -import type { FieldHook } from '../../shared_imports'; -import { VALIDATION_TYPES } from '../../shared_imports'; +import { useController } from 'react-hook-form'; import type { PackSavedObject } from '../../packs/types'; const TextTruncate = styled.div` @@ -21,13 +20,12 @@ const TextTruncate = styled.div` text-overflow: ellipsis; `; -interface Props { - field: FieldHook; - euiFieldProps?: { +interface PackComboBoxFieldProps { + fieldProps?: { packsData?: PackSavedObject[]; }; idAria?: string; - [key: string]: unknown; + queryType: string; } interface PackOption { @@ -36,48 +34,53 @@ interface PackOption { description?: string; } -export const PacksComboBoxField = ({ field, euiFieldProps = {}, idAria, ...rest }: Props) => { +export const PacksComboBoxField = ({ + queryType, + fieldProps = {}, + idAria, + ...rest +}: PackComboBoxFieldProps) => { + const { + field: { value, onChange }, + fieldState, + } = useController({ + name: 'packId', + rules: { + required: { + message: i18n.translate( + 'xpack.osquery.pack.queryFlyoutForm.osqueryPackMissingErrorMessage', + { + defaultMessage: 'Pack is a required field', + } + ), + value: queryType === 'pack', + }, + }, + defaultValue: [], + }); + const error = fieldState.error?.message; const [selectedOptions, setSelectedOptions] = useState< Array> >([]); - // Errors for the comboBox value (the "array") - const errorMessageField = field.getErrorsMessages(); - - // Errors for comboBox option added (the array "item") - const errorMessageArrayItem = field.getErrorsMessages({ - validationType: VALIDATION_TYPES.ARRAY_ITEM, - }); - - const isInvalid = field.errors.length - ? errorMessageField !== null || errorMessageArrayItem !== null - : false; - - // Concatenate error messages. - const errorMessage = - errorMessageField && errorMessageArrayItem - ? `${errorMessageField}, ${errorMessageArrayItem}` - : errorMessageField - ? errorMessageField - : errorMessageArrayItem; const handlePackChange = useCallback( (newSelectedOptions) => { if (!newSelectedOptions.length) { setSelectedOptions(newSelectedOptions); - field.setValue([]); + onChange([]); return; } setSelectedOptions(newSelectedOptions); - field.setValue([newSelectedOptions[0].value?.id]); + onChange([newSelectedOptions[0].value?.id]); }, - [field] + [onChange] ); const packOptions = useMemo>>( () => - euiFieldProps?.packsData?.map((packSO) => ({ + fieldProps?.packsData?.map((packSO) => ({ label: packSO.attributes.name ?? '', value: { id: packSO.id, @@ -85,20 +88,11 @@ export const PacksComboBoxField = ({ field, euiFieldProps = {}, idAria, ...rest description: packSO.attributes.description, }, })) ?? [], - [euiFieldProps?.packsData] - ); - - const onSearchComboChange = useCallback( - (value: string) => { - if (value !== undefined) { - field.clearErrors(VALIDATION_TYPES.ARRAY_ITEM); - } - }, - [field] + [fieldProps?.packsData] ); const renderOption = useCallback( - ({ value }) => ( + ({ value: option }) => ( - {value.name} + {option?.name} - {value.description} + {option?.description} @@ -119,22 +113,22 @@ export const PacksComboBoxField = ({ field, euiFieldProps = {}, idAria, ...rest ); useEffect(() => { - if (field.value.length) { - const packOption = find(packOptions, ['value.id', field.value[0]]); + if (value?.length) { + const packOption = find(packOptions, ['value.id', value[0]]); if (packOption) { setSelectedOptions([packOption]); } } - }, [field.value, packOptions]); + }, [value, packOptions]); return ( ); diff --git a/x-pack/plugins/osquery/public/live_queries/form/schema.ts b/x-pack/plugins/osquery/public/live_queries/form/schema.ts deleted file mode 100644 index c09eccd1c5c88..0000000000000 --- a/x-pack/plugins/osquery/public/live_queries/form/schema.ts +++ /dev/null @@ -1,57 +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 MAX_QUERY_LENGTH = 2000; - -import { i18n } from '@kbn/i18n'; -import { FIELD_TYPES } from '../../shared_imports'; -import { queryFieldValidation } from '../../common/validations'; -import { fieldValidators } from '../../shared_imports'; - -export const liveQueryFormSchema = { - agentSelection: { - defaultValue: { - agents: [], - allAgentsSelected: false, - platformsSelected: [], - policiesSelected: [], - }, - type: FIELD_TYPES.JSON, - validations: [], - }, - savedQueryId: { - type: FIELD_TYPES.TEXT, - validations: [], - }, - query: { - defaultValue: '', - type: FIELD_TYPES.TEXT, - validations: [ - { - validator: fieldValidators.maxLengthField({ - length: MAX_QUERY_LENGTH, - message: i18n.translate('xpack.osquery.liveQuery.queryForm.largeQueryError', { - defaultMessage: 'Query is too large (max {maxLength} characters)', - values: { maxLength: MAX_QUERY_LENGTH }, - }), - }), - }, - { validator: queryFieldValidation }, - ], - }, - packId: { - label: i18n.translate('xpack.osquery.packs.dropdown.searchFieldLabel', { - defaultMessage: `Pack`, - }), - type: FIELD_TYPES.COMBO_BOX, - defaultValue: [], - }, - ecs_mapping: { - defaultValue: [], - type: FIELD_TYPES.JSON, - }, -}; diff --git a/x-pack/plugins/osquery/public/live_queries/index.tsx b/x-pack/plugins/osquery/public/live_queries/index.tsx index 22aa3be77c2a7..746687f4b644b 100644 --- a/x-pack/plugins/osquery/public/live_queries/index.tsx +++ b/x-pack/plugins/osquery/public/live_queries/index.tsx @@ -10,6 +10,7 @@ import { EuiCode, EuiLoadingContent, EuiEmptyPrompt } from '@elastic/eui'; import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import type { EcsMappingSerialized } from '../packs/queries/ecs_mapping_editor_field'; import { LiveQueryForm } from './form'; import { useActionResultsPrivileges } from '../action_results/use_action_privileges'; import { OSQUERY_INTEGRATION_NAME } from '../../common'; @@ -23,7 +24,7 @@ interface LiveQueryProps { onSuccess?: () => void; query?: string; savedQueryId?: string; - ecs_mapping?: unknown; + ecs_mapping?: EcsMappingSerialized; agentsField?: boolean; queryField?: boolean; ecsMappingField?: boolean; diff --git a/x-pack/plugins/osquery/public/packs/form/queries_field.tsx b/x-pack/plugins/osquery/public/packs/form/queries_field.tsx index bff3e30a901c1..62f5c9c7e7e93 100644 --- a/x-pack/plugins/osquery/public/packs/form/queries_field.tsx +++ b/x-pack/plugins/osquery/public/packs/form/queries_field.tsx @@ -93,6 +93,7 @@ const QueriesFieldComponent: React.FC = ({ if (updatedQuery.ecs_mapping) { draft[showEditQueryFlyout].ecs_mapping = updatedQuery.ecs_mapping; } else { + // @ts-expect-error update types delete draft[showEditQueryFlyout].ecs_mapping; } @@ -231,6 +232,7 @@ const QueriesFieldComponent: React.FC = ({ {showEditQueryFlyout != null && showEditQueryFlyout >= 0 && ( ; const typeMap = { binary: 'binary', @@ -80,17 +85,6 @@ const typeMap = { constant_keyword: 'string', }; -const StyledEuiSuperSelect = styled(EuiSuperSelect)` - min-width: 70px; - border-radius: 6px 0 0 6px; - - .euiIcon { - padding: 0; - width: 18px; - background: none; - } -`; - // @ts-expect-error update types const ResultComboBox = styled(EuiComboBox)` &.euiComboBox { @@ -103,6 +97,17 @@ const ResultComboBox = styled(EuiComboBox)` } `; +const StyledEuiSuperSelect = styled(EuiSuperSelect)` + min-width: 70px; + border-radius: 6px 0 0 6px; + + .euiIcon { + padding: 0; + width: 18px; + background: none; + } +`; + const StyledFieldIcon = styled(FieldIcon)` width: 32px; @@ -144,31 +149,32 @@ const ECSSchemaOptions = ECSSchema.map((ecs) => ({ type ECSSchemaOption = typeof ECSSchemaOptions[0]; -interface ECSComboboxFieldProps { - field: FieldHook; +interface ECSComboboxFieldProps extends FormField { euiFieldProps: EuiComboBoxProps; idAria?: string; + error?: string; } const ECSComboboxFieldComponent: React.FC = ({ - field, euiFieldProps = {}, idAria, + onChange, + value, + error, }) => { - const { setValue } = field; const [selectedOptions, setSelected] = useState>>( [] ); - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); const describedByIds = useMemo(() => (idAria ? [idAria] : []), [idAria]); - const [formData] = useFormData(); - + const { ecs_mapping: watchedEcsMapping } = useWatch() as unknown as { + ecs_mapping: EcsMappingFormField[]; + }; const handleChange = useCallback( (newSelectedOptions) => { setSelected(newSelectedOptions); - setValue(newSelectedOptions[0]?.label ?? ''); + onChange(newSelectedOptions[0]?.label ?? ''); }, - [setValue] + [onChange] ); // TODO: Create own component for this. @@ -230,37 +236,36 @@ const ECSComboboxFieldComponent: React.FC = ({ }, [selectedOptions]); const availableECSSchemaOptions = useMemo(() => { - const currentFormECSFieldValues = map(formData.ecs_mapping, 'key'); + const currentFormECSFieldValues = map(watchedEcsMapping, 'key'); return ECSSchemaOptions.filter(({ label }) => !currentFormECSFieldValues.includes(label)); - }, [formData.ecs_mapping]); + }, [watchedEcsMapping]); useEffect(() => { // @ts-expect-error update types setSelected(() => { - if (!field.value.length) return []; + if (!value?.length) return []; - const selectedOption = find(ECSSchemaOptions, ['label', field.value]); + const selectedOption = find(ECSSchemaOptions, ['label', value]); return selectedOption ? [selectedOption] : [ { - label: field.value, + label: value, value: { - value: field.value, + value, }, }, ]; }); - }, [field.value]); + }, [value]); return ( ; - resultValue: FieldHook; euiFieldProps: EuiComboBoxProps; - item: ArrayItem; + item: EcsMappingFormField; + index: number; idAria?: string; + isLastItem: boolean; } const OsqueryColumnFieldComponent: React.FC = ({ - resultType, - resultValue, - euiFieldProps = {}, + euiFieldProps, idAria, item, + index, + isLastItem, }) => { + const osqueryResultFieldValidator = ( + value: string, + ecsMappingFormData: EcsMappingFormField[] + ): string | undefined => { + const currentMapping = ecsMappingFormData[index]; + + if (!value.length && currentMapping.key.length) { + return i18n.translate( + 'xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage', + { + defaultMessage: 'Value field is required.', + } + ); + } + + if (!value.length || currentMapping.result.type !== 'field') return; + + const osqueryColumnExists = find(euiFieldProps.options, [ + 'label', + isArray(value) ? value[0] : value, + ]); + + return !osqueryColumnExists + ? i18n.translate( + 'xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage', + { + defaultMessage: 'The current query does not return a {columnName} field', + values: { + columnName: value, + }, + } + ) + : undefined; + }; + + const { setValue } = useFormContext(); + const { ecs_mapping: watchedEcsMapping } = useWatch() as unknown as { + ecs_mapping: EcsMappingFormField[]; + }; + + const { field: resultField, fieldState: resultFieldState } = useController({ + name: `ecs_mapping.${index}.result.value`, + rules: { + validate: (data) => osqueryResultFieldValidator(data, watchedEcsMapping), + }, + defaultValue: '', + }); + const itemPath = `ecs_mapping.${index}`; + const resultValue = item.result; const inputRef = useRef(); - const { setValue } = resultValue; - const { value: typeValue, setValue: setType } = resultType; - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(resultValue); + const [selectedOptions, setSelected] = useState([]); const describedByIds = useMemo(() => (idAria ? [idAria] : []), [idAria]); - const [selectedOptions, setSelected] = useState< - Array> - >([]); - const [formData] = useFormData(); const renderOsqueryOption = useCallback( (option, searchValue, contentClassName) => ( @@ -365,7 +413,6 @@ const OsqueryColumnFieldComponent: React.FC = ({ {option.value.suggestion_label}
- {option.value.description} @@ -376,37 +423,44 @@ const OsqueryColumnFieldComponent: React.FC = ({ [] ); - const handleChange = useCallback( + const handleKeyChange = useCallback( (newSelectedOptions) => { setSelected(newSelectedOptions); - setValue( + resultField.onChange( isArray(newSelectedOptions) ? map(newSelectedOptions, 'label') : newSelectedOptions[0]?.label ?? '' ); }, - [setValue, setSelected] + [resultField] ); const isSingleSelection = useMemo(() => { - const ecsKey = get(formData, item.path)?.key; - if (ecsKey?.length && typeValue === 'value') { - const ecsKeySchemaOption = find(ECSSchemaOptions, ['label', ecsKey]); + const ecsData = get(watchedEcsMapping, `${index}`); + if (ecsData?.key?.length && item.result.type === 'value') { + const ecsKeySchemaOption = find(ECSSchemaOptions, ['label', ecsData?.key]); return ecsKeySchemaOption?.value?.normalization !== 'array'; } - return !!ecsKey?.length; - }, [typeValue, formData, item.path]); + if (!ecsData?.key?.length && isLastItem) { + return true; + } + + return !!ecsData?.key?.length; + }, [index, isLastItem, item.result.type, watchedEcsMapping]); const onTypeChange = useCallback( (newType) => { - if (newType !== typeValue) { - setType(newType); - setValue(newType === 'value' && isSingleSelection === false ? [] : ''); + if (newType !== item.result.type) { + setValue(`${itemPath}.result.type`, newType); + setValue( + `${itemPath}.result.value`, + newType === 'value' && isSingleSelection === false ? [] : '' + ); } }, - [typeValue, setType, setValue, isSingleSelection] + [isSingleSelection, item.result.type, itemPath, setValue] ); const handleCreateOption = useCallback( @@ -416,19 +470,19 @@ const OsqueryColumnFieldComponent: React.FC = ({ if (!trimmedNewOption.length) return; if (isSingleSelection === false) { - setValue([trimmedNewOption]); - if (resultValue.value.length) { - setValue([...castArray(resultValue.value), trimmedNewOption]); + setValue(`${itemPath}.result.value`, [trimmedNewOption]); + if (item.result.value.length) { + setValue(`${itemPath}.result.value`, [...castArray(resultValue.value), trimmedNewOption]); } else { - setValue([trimmedNewOption]); + setValue(`${itemPath}.result.value`, [trimmedNewOption]); } inputRef.current?.blur(); } else { - setValue(trimmedNewOption); + setValue(`${itemPath}.result.value`, trimmedNewOption); } }, - [isSingleSelection, resultValue.value, setValue] + [isSingleSelection, item.result.value.length, itemPath, resultValue.value, setValue] ); const Prepend = useMemo( @@ -436,7 +490,7 @@ const OsqueryColumnFieldComponent: React.FC = ({ = ({ onChange={onTypeChange} /> ), - [euiFieldProps.isDisabled, onTypeChange, typeValue] + [euiFieldProps.isDisabled, item.result.type, onTypeChange] ); useEffect(() => { if (isSingleSelection && isArray(resultValue.value)) { - setValue(resultValue.value.join(' ')); + setValue(`${itemPath}.result.value`, resultValue.value.join(' ')); } if (!isSingleSelection && !isArray(resultValue.value)) { - setValue(resultValue.value.length ? [resultValue.value] : []); + const value = resultValue.value.length ? [resultValue.value] : []; + setValue(`${itemPath}.result.value`, value); } - }, [isSingleSelection, resultValue.value, setValue]); + }, [index, isSingleSelection, itemPath, resultValue, resultValue.value, setValue]); useEffect(() => { - setSelected(() => { + // @ts-expect-error hard to type to satisfy TS, but it represents proper types + setSelected((_: OsquerySchemaOption[]): OsquerySchemaOption[] | Array<{ label: string }> => { if (!resultValue.value.length) return []; // Static array values if (isArray(resultValue.value)) { - return resultValue.value.map((value) => ({ label: value })); + return resultValue.value.map((value) => ({ label: value })) as OsquerySchemaOption[]; } - const selectedOption = find(euiFieldProps?.options, ['label', resultValue.value]); + const selectedOption = find(euiFieldProps?.options, ['label', resultValue.value]) as + | OsquerySchemaOption + | undefined; return selectedOption ? [selectedOption] : [{ label: resultValue.value }]; }); @@ -476,10 +534,9 @@ const OsqueryColumnFieldComponent: React.FC = ({ return ( = ({ {Prepend} { inputRef.current = ref; }} fullWidth selectedOptions={selectedOptions} - onChange={handleChange} + onChange={handleKeyChange} onCreateOption={handleCreateOption} renderOption={renderOsqueryOption} rowHeight={32} isClearable - {...euiFieldProps} singleSelection={isSingleSelection ? SINGLE_SELECTION : false} - options={(typeValue === 'field' && euiFieldProps.options) || EMPTY_ARRAY} + options={(item.result.type === 'field' && euiFieldProps.options) || EMPTY_ARRAY} + idAria={idAria} + helpText={selectedOptions[0]?.value?.description} + {...euiFieldProps} /> @@ -518,177 +581,76 @@ export interface ECSMappingEditorFieldProps { interface ECSMappingEditorFormProps { isDisabled?: boolean; osquerySchemaOptions: OsquerySchemaOption[]; - item: ArrayItem; - isLastItem?: boolean; + item: EcsMappingFormField; + index: number; + isLastItem: boolean; + onAppend: (ecs_mapping: EcsMappingFormField[]) => void; onDelete?: FormArrayField['removeItem']; } -const ecsFieldValidator = ( - args: ValidationFuncArg & { - customData: { - value: { - editForm: boolean; - }; - }; - } -) => { - const editForm: boolean = args.customData.value?.editForm; - const rootPath = args.path.split('.')[0]; - - const fieldRequiredError = fieldValidators.emptyField( - i18n.translate('xpack.osquery.pack.queryFlyoutForm.ecsFieldRequiredErrorMessage', { - defaultMessage: 'ECS field is required.', - }) - )(args); - - if ( - fieldRequiredError && - // @ts-expect-error update types - ((!editForm && args.formData[`${rootPath}.result.value`]?.length) || editForm) - ) { - return fieldRequiredError; - } - - return undefined; -}; - -const osqueryResultFieldValidator = async ( - args: ValidationFuncArg & { - customData: { - value: { - editForm: boolean; - osquerySchemaOptions: OsquerySchemaOption[]; - }; - }; - } -) => { - const rootPath = args.path.split('.')[0]; - const { editForm, osquerySchemaOptions } = args.customData.value; - const fieldRequiredError = fieldValidators.emptyField( - i18n.translate('xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage', { - defaultMessage: 'Value is required.', - }) - )(args); - - // @ts-expect-error update types - if (fieldRequiredError && ((!editForm && args.formData[`${rootPath}.key`]?.length) || editForm)) { - return fieldRequiredError; - } - - // @ts-expect-error update types - if (!args.value?.length || args.formData[`${rootPath}.result.type`] !== 'field') return; - - const osqueryColumnExists = find(osquerySchemaOptions, [ - 'label', - isArray(args.value) ? args.value[0] : args.value, - ]); - - return !osqueryColumnExists - ? { - code: 'ERR_FIELD_FORMAT', - path: args.path, - message: i18n.translate( - 'xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage', - { - defaultMessage: 'The current query does not return a {columnName} field', - values: { - columnName: args.value, - }, - } - ), - } - : undefined; +export const defaultEcsFormData = { + key: '', + result: { + type: 'field', + value: '', + }, }; -interface ECSMappingEditorFormData { - key: string; - value: { - field?: string; - value?: string; - }; -} - export const ECSMappingEditorForm: React.FC = ({ isDisabled, osquerySchemaOptions, item, isLastItem, + index, onDelete, }) => { + const ecsFieldValidator = (value: string, ecsMapping: EcsMappingFormField[]) => { + const ecsCurrentMapping = ecsMapping[index].result.value; + + return !value.length && ecsCurrentMapping.length + ? i18n.translate('xpack.osquery.pack.queryFlyoutForm.ecsFieldRequiredErrorMessage', { + defaultMessage: 'ECS field is required.', + }) + : undefined; + }; + + const { ecs_mapping: ecsMapping } = useWatch() as unknown as { + ecs_mapping: EcsMappingFormField[]; + }; + const { field: ECSField, fieldState: ECSFieldState } = useController({ + name: `ecs_mapping.${index}.key`, + rules: { + validate: (value: string) => ecsFieldValidator(value, ecsMapping), + }, + defaultValue: '', + }); + const MultiFields = useMemo( () => ( - - {(fields) => ( - - )} - +
+ +
), - [item, osquerySchemaOptions, isLastItem, isDisabled] + [item, index, isLastItem, osquerySchemaOptions, isDisabled] ); const ecsComboBoxEuiFieldProps = useMemo(() => ({ isDisabled }), [isDisabled]); - const validationData = useMemo(() => ({ editForm: !isLastItem }), [isLastItem]); - - const config = useMemo( - () => ({ - valueChangeDebounceTime: 300, - fieldsToValidateOnChange: [`${item.path}.key`, `${item.path}.result.value`], - validations: [ - { - validator: ecsFieldValidator, - }, - ], - }), - [item.path] - ); - const handleDeleteClick = useCallback(() => { if (onDelete) { - onDelete(item.id); + onDelete(index); } - }, [item.id, onDelete]); + }, [index, onDelete]); return ( <> @@ -696,14 +658,13 @@ export const ECSMappingEditorForm: React.FC = ({ - @@ -764,22 +725,26 @@ interface OsqueryColumn { export const ECSMappingEditorField = React.memo( ({ euiFieldProps }: ECSMappingEditorFieldProps) => { - const lastItemPath = useRef(); - const onAdd = useRef(); - const itemsList = useRef([]); - const [osquerySchemaOptions, setOsquerySchemaOptions] = useState([]); - const [{ query, ...formData }, formDataSerializer, isMounted] = useFormData(); + const { trigger } = useFormContext(); + const { fields, append, remove } = useFieldArray<{ ecs_mapping: EcsMappingFormField[] }>({ + name: 'ecs_mapping', + }); - const { validateFields } = useFormContext(); + const itemsList = useRef>([]); + const [osquerySchemaOptions, setOsquerySchemaOptions] = useState([]); + const { query, ...formData } = useWatch() as unknown as { + query: string; + ecs_mapping: EcsMappingFormField[]; + }; useEffect(() => { // Additional 'suspended' validation of osquery ecs fields. fieldsToValidateOnChange doesn't work because it happens before the osquerySchema gets updated. - const fieldsToValidate = prepareEcsFieldsToValidate(itemsList.current); + const fieldsToValidate = prepareEcsFieldsToValidate(fields); // it is always at least 2 - empty fields if (fieldsToValidate.length > 2) { - setTimeout(() => validateFields(fieldsToValidate), 0); + setTimeout(async () => await trigger('ecs_mapping'), 0); } - }, [query, validateFields]); + }, [fields, query, trigger]); useEffect(() => { if (!query?.length) { @@ -1013,32 +978,23 @@ export const ECSMappingEditorField = React.memo( }, [query]); useLayoutEffect(() => { - if (isMounted) { - if (!lastItemPath.current && onAdd.current) { - onAdd.current(); - - return; - } - - if (euiFieldProps?.isDisabled) { - return; - } - - const itemKey = get(formData, `${lastItemPath.current}.key`); + const ecsList = formData?.ecs_mapping; + const lastEcs = formData?.ecs_mapping?.[itemsList?.current.length - 1]; - if (itemKey) { - const serializedFormData = formDataSerializer(); - const itemValue = - serializedFormData.ecs_mapping && - (serializedFormData.ecs_mapping[`${itemKey}`]?.field || - serializedFormData.ecs_mapping[`${itemKey}`]?.value); + // we skip appending on remove + if (itemsList?.current?.length < ecsList?.length) { + return; + } - if (itemValue && onAdd.current) { - onAdd.current(); - } - } + // // list contains ecs already, and the last item has values provided + if ( + ecsList?.length === itemsList.current.length && + lastEcs?.key?.length && + lastEcs?.result?.value?.length + ) { + return append(defaultEcsFormData); } - }, [euiFieldProps?.isDisabled, formData, formDataSerializer, isMounted, onAdd]); + }, [append, euiFieldProps?.isDisabled, formData]); return ( <> @@ -1080,28 +1036,24 @@ export const ECSMappingEditorField = React.memo( - - {({ items, addItem, removeItem }) => { - lastItemPath.current = items[items.length - 1]?.path; - onAdd.current = addItem; - itemsList.current = items; - - return ( - <> - {items.map((item, index) => ( - - ))} - - ); - }} - + + {fields.map((item, index, array) => { + itemsList.current = array; + + return ( +
+ +
+ ); + })} ); }, diff --git a/x-pack/plugins/osquery/public/packs/queries/platform_checkbox_group_field.tsx b/x-pack/plugins/osquery/public/packs/queries/platform_checkbox_group_field.tsx index 1aa83a39f12b7..62e0a7bdaef6d 100644 --- a/x-pack/plugins/osquery/public/packs/queries/platform_checkbox_group_field.tsx +++ b/x-pack/plugins/osquery/public/packs/queries/platform_checkbox_group_field.tsx @@ -11,23 +11,22 @@ import type { EuiCheckboxGroupOption } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiCheckboxGroup } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { FieldHook } from '../../shared_imports'; -import { getFieldValidityAndErrorMessage } from '../../shared_imports'; +import { useController } from 'react-hook-form'; +import { i18n } from '@kbn/i18n'; +import type { FormFieldProps } from '../../form/types'; import { PlatformIcon } from './platforms/platform_icon'; -interface Props { - field: FieldHook; - euiFieldProps?: Record; - idAria?: string; - [key: string]: unknown; -} +type Props = Omit, 'name' | 'label'>; -export const PlatformCheckBoxGroupField = ({ - field, - euiFieldProps = {}, - idAria, - ...rest -}: Props) => { +export const PlatformCheckBoxGroupField = (props: Props) => { + const { euiFieldProps = {}, idAria, helpText, ...rest } = props; + const { + field: { onChange, value }, + fieldState: { error }, + } = useController({ + name: 'platform', + defaultValue: [], + }); const options = useMemo( () => [ { @@ -82,17 +81,16 @@ export const PlatformCheckBoxGroupField = ({ [] ); - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); const [checkboxIdToSelectedMap, setCheckboxIdToSelectedMap] = useState>( () => (options as EuiCheckboxGroupOption[]).reduce((acc, option) => { - acc[option.id] = isEmpty(field.value) ? true : field.value?.includes(option.id) ?? false; + acc[option.id] = isEmpty(value) ? true : value?.includes(option.id) ?? false; return acc; }, {} as Record) ); - const onChange = useCallback( + const handleChange = useCallback( (optionId: string) => { const newCheckboxIdToSelectedMap = { ...checkboxIdToSelectedMap, @@ -100,11 +98,13 @@ export const PlatformCheckBoxGroupField = ({ }; setCheckboxIdToSelectedMap(newCheckboxIdToSelectedMap); - field.setValue(() => - Object.keys(pickBy(newCheckboxIdToSelectedMap, (value) => value === true)).join(',') + onChange( + Object.keys( + pickBy(newCheckboxIdToSelectedMap, (checkboxValue) => checkboxValue === true) + ).join(',') ); }, - [checkboxIdToSelectedMap, field] + [checkboxIdToSelectedMap, onChange] ); const describedByIds = useMemo(() => (idAria ? [idAria] : []), [idAria]); @@ -112,19 +112,23 @@ export const PlatformCheckBoxGroupField = ({ useEffect(() => { setCheckboxIdToSelectedMap(() => (options as EuiCheckboxGroupOption[]).reduce((acc, option) => { - acc[option.id] = isEmpty(field.value) ? true : field.value?.includes(option.id) ?? false; + acc[option.id] = isEmpty(value) ? true : value?.includes(option.id) ?? false; return acc; }, {} as Record) ); - }, [field.value, options]); + }, [value, options]); + + const hasError = useMemo(() => !!error?.message, [error?.message]); return ( diff --git a/x-pack/plugins/osquery/public/packs/queries/query_flyout.tsx b/x-pack/plugins/osquery/public/packs/queries/query_flyout.tsx index 72317dbadc708..3d8872cb45d64 100644 --- a/x-pack/plugins/osquery/public/packs/queries/query_flyout.tsx +++ b/x-pack/plugins/osquery/public/packs/queries/query_flyout.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { map } from 'lodash'; import { EuiFlyout, EuiTitle, @@ -17,28 +16,33 @@ import { EuiFlexItem, EuiButtonEmpty, EuiButton, - EuiText, } from '@elastic/eui'; import React, { useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { FormProvider } from 'react-hook-form'; +import { isEmpty, map } from 'lodash'; +import { QueryIdField, IntervalField } from '../../form'; +import { defaultEcsFormData } from './ecs_mapping_editor_field'; import { CodeEditorField } from '../../saved_queries/form/code_editor_field'; -import { Form, getUseField, Field } from '../../shared_imports'; import { PlatformCheckBoxGroupField } from './platform_checkbox_group_field'; import { ALL_OSQUERY_VERSIONS_OPTIONS } from './constants'; -import type { UsePackQueryFormProps, PackQueryFormData } from './use_pack_query_form'; +import type { + UsePackQueryFormProps, + PackQueryFormData, + PackSOQueryFormData, +} from './use_pack_query_form'; import { usePackQueryForm } from './use_pack_query_form'; import { SavedQueriesDropdown } from '../../saved_queries/saved_queries_dropdown'; import { ECSMappingEditorField } from './lazy_ecs_mapping_editor_field'; import { useKibana } from '../../common/lib/kibana'; - -const CommonUseField = getUseField({ component: Field }); +import { VersionField } from '../../form'; interface QueryFlyoutProps { uniqueQueryIds: string[]; defaultValue?: UsePackQueryFormProps['defaultValue'] | undefined; - onSave: (payload: PackQueryFormData) => Promise; + onSave: (payload: PackSOQueryFormData) => void; onClose: () => void; } @@ -50,45 +54,48 @@ const QueryFlyoutComponent: React.FC = ({ }) => { const permissions = useKibana().services.application.capabilities.osquery; const [isEditMode] = useState(!!defaultValue); - const { form } = usePackQueryForm({ + const { serializer, idSet, ...hooksForm } = usePackQueryForm({ uniqueQueryIds, defaultValue, - handleSubmit: async (payload, isValid) => - new Promise((resolve) => { - if (isValid) { - onSave(payload); - onClose(); - } - - resolve(); - }), }); - const { submit, isSubmitting, updateFieldValues } = form; + const { + handleSubmit, + formState: { isSubmitting }, + setValue, + clearErrors, + } = hooksForm; + const onSubmit = (payload: PackQueryFormData) => { + const serializedData: PackSOQueryFormData = serializer(payload); + onSave(serializedData); + onClose(); + }; const handleSetQueryValue = useCallback( (savedQuery) => { if (savedQuery) { - updateFieldValues({ - id: savedQuery.id, - query: savedQuery.query, - description: savedQuery.description, - platform: savedQuery.platform ? savedQuery.platform : 'linux,windows,darwin', - version: savedQuery.version, - interval: savedQuery.interval, - // @ts-expect-error update types - ecs_mapping: - map(savedQuery.ecs_mapping, (value, key) => ({ - key, - result: { - type: Object.keys(value)[0], - value: Object.values(value)[0], - }, - })) ?? [], - }); + clearErrors('id'); + setValue('id', savedQuery.id); + setValue('query', savedQuery.query); + // setValue('description', savedQuery.description); // TODO do we need it? + setValue('platform', savedQuery.platform ? savedQuery.platform : 'linux,windows,darwin'); + setValue('version', savedQuery.version ? [savedQuery.version] : []); + setValue('interval', savedQuery.interval); + setValue( + 'ecs_mapping', + !isEmpty(savedQuery.ecs_mapping) + ? map(savedQuery.ecs_mapping, (value, key) => ({ + key, + result: { + type: Object.keys(value)[0], + value: Object.values(value)[0] as string, + }, + })) + : [defaultEcsFormData] + ); } }, - [updateFieldValues] + [clearErrors, setValue] ); /* Avoids accidental closing of the flyout when the user clicks outside of the flyout */ const maskProps = useMemo(() => ({ onClick: () => ({}) }), []); @@ -119,37 +126,25 @@ const QueryFlyoutComponent: React.FC = ({ -
+ {!isEditMode && permissions.readSavedQueries ? ( <> ) : null} - + - + - - - - - - - } + = ({ /> - + @@ -172,7 +167,7 @@ const QueryFlyoutComponent: React.FC = ({ - +
@@ -185,7 +180,7 @@ const QueryFlyoutComponent: React.FC = ({
- + ) => ({ - id: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.osquery.pack.queryFlyoutForm.idFieldLabel', { - defaultMessage: 'ID', - }), - validations: createIdFieldValidations(ids).map((validator) => ({ validator })), - }, - description: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.osquery.pack.queryFlyoutForm.descriptionFieldLabel', { - defaultMessage: 'Description (optional)', - }), - validations: [], - }, - query: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.osquery.pack.queryFlyoutForm.queryFieldLabel', { - defaultMessage: 'Query', - }), - validations: [{ validator: queryFieldValidation }], - }, - interval: { - defaultValue: 3600, - type: FIELD_TYPES.NUMBER, - label: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldLabel', { - defaultMessage: 'Interval (s)', - }), - validations: intervalFieldValidations, - }, - platform: { - type: FIELD_TYPES.TEXT, - label: i18n.translate('xpack.osquery.pack.queryFlyoutForm.platformFieldLabel', { - defaultMessage: 'Platform', - }), - validations: [], - }, - version: { - defaultValue: [], - type: FIELD_TYPES.COMBO_BOX, - label: ( - - - - - - ) as unknown as string, - validations: [], - }, - ecs_mapping: { - defaultValue: [], - type: FIELD_TYPES.JSON, - }, -}); diff --git a/x-pack/plugins/osquery/public/packs/queries/use_pack_query_form.tsx b/x-pack/plugins/osquery/public/packs/queries/use_pack_query_form.tsx index 16da80b048921..4a1e47c3df9b7 100644 --- a/x-pack/plugins/osquery/public/packs/queries/use_pack_query_form.tsx +++ b/x-pack/plugins/osquery/public/packs/queries/use_pack_query_form.tsx @@ -5,134 +5,113 @@ * 2.0. */ -import { isArray, isEmpty, xor, map } from 'lodash'; -import uuid from 'uuid'; -import { produce } from 'immer'; +import { isArray, isEmpty, map, xor } from 'lodash'; +import { useForm as useHookForm } from 'react-hook-form'; +import type { Draft } from 'immer'; +import { produce } from 'immer'; import { useMemo } from 'react'; -import type { ECSMapping } from '../../../common/schemas/common'; import { convertECSMappingToObject } from '../../../common/schemas/common/utils'; -import type { FormConfig } from '../../shared_imports'; -import { useForm } from '../../shared_imports'; -import { createFormSchema } from './schema'; - -const FORM_ID = 'editQueryFlyoutForm'; +import type { EcsMappingFormField } from './ecs_mapping_editor_field'; +import { defaultEcsFormData } from './ecs_mapping_editor_field'; export interface UsePackQueryFormProps { uniqueQueryIds: string[]; - defaultValue?: PackQueryFormData | undefined; - handleSubmit: FormConfig['onSubmit']; + defaultValue?: PackSOQueryFormData | undefined; } export interface PackSOQueryFormData { id: string; query: string; - interval: number; + interval: string; platform?: string | undefined; version?: string | undefined; - ecs_mapping?: PackQuerySOECSMapping[] | undefined; + ecs_mapping?: PackQuerySOECSMapping[]; } export type PackQuerySOECSMapping = Array<{ field: string; value: string }>; export interface PackQueryFormData { - id?: string; + id: string; description?: string; query: string; - interval?: number; + interval: number; platform?: string | undefined; - version?: string | undefined; - ecs_mapping?: ECSMapping; + version?: string[] | undefined; + ecs_mapping: EcsMappingFormField[]; } -export type PackQueryECSMapping = Record< - string, - { - field?: string; - value?: string; - } ->; - -export const usePackQueryForm = ({ - uniqueQueryIds, - defaultValue, - handleSubmit, -}: UsePackQueryFormProps) => { - const idSet = useMemo>( - () => new Set(xor(uniqueQueryIds, defaultValue?.id ? [defaultValue.id] : [])), - [uniqueQueryIds, defaultValue] - ); - const formSchema = useMemo>( - () => createFormSchema(idSet), - [idSet] - ); +const deserializer = (payload: PackSOQueryFormData): PackQueryFormData => + ({ + id: payload.id, + query: payload.query, + interval: payload.interval ? parseInt(payload.interval, 10) : 3600, + platform: payload.platform, + version: payload.version ? [payload.version] : [], + ecs_mapping: !isEmpty(payload.ecs_mapping) + ? !isArray(payload.ecs_mapping) + ? map(payload.ecs_mapping as unknown as PackQuerySOECSMapping, (value, key) => ({ + key, + result: { + type: Object.keys(value)[0], + value: Object.values(value)[0], + }, + })) + : payload.ecs_mapping + : [defaultEcsFormData], + } as PackQueryFormData); - return useForm({ - id: FORM_ID + uuid.v4(), - onSubmit: async (formData, isValid) => { - if (isValid && handleSubmit) { - // @ts-expect-error update types - return handleSubmit(formData, isValid); +const serializer = (payload: PackQueryFormData): PackSOQueryFormData => + // @ts-expect-error update types + produce(payload, (draft: Draft) => { + if (isArray(draft.platform)) { + if (draft.platform.length) { + draft.platform.join(','); + } else { + delete draft.platform; } - }, - options: { - stripEmptyFields: true, - }, - // @ts-expect-error update types - defaultValue: defaultValue || { - id: '', - query: '', - interval: 3600, - ecs_mapping: [], - }, - // @ts-expect-error update types - serializer: (payload) => - produce(payload, (draft) => { - if (isArray(draft.platform)) { - draft.platform.join(','); - } + } - if (isArray(draft.version)) { - if (!draft.version.length) { - delete draft.version; - } else { - draft.version = draft.version[0]; - } - } + if (isArray(draft.version)) { + if (!draft.version.length) { + delete draft.version; + } else { + draft.version = draft.version[0]; + } + } - if (isEmpty(draft.ecs_mapping)) { - delete draft.ecs_mapping; - } else { - // @ts-expect-error update types - draft.ecs_mapping = convertECSMappingToObject(payload.ecs_mapping); - } + if (draft.interval) { + draft.interval = draft.interval + ''; + } - return draft; - }), - // @ts-expect-error update types - deserializer: (payload) => { - if (!payload) return {} as PackQueryFormData; + if (isEmpty(draft.ecs_mapping)) { + delete draft.ecs_mapping; + } else { + // @ts-expect-error update types + draft.ecs_mapping = convertECSMappingToObject(payload.ecs_mapping); + } - return { - id: payload.id, - query: payload.query, - interval: payload.interval, - platform: payload.platform, - version: payload.version ? [payload.version] : [], - ecs_mapping: !isArray(payload.ecs_mapping) - ? map(payload.ecs_mapping, (value, key) => ({ - key, - result: { - // @ts-expect-error update types - type: Object.keys(value)[0], - // @ts-expect-error update types - value: Object.values(value)[0], - }, - })) - : payload.ecs_mapping, - }; - }, - // @ts-expect-error update types - schema: formSchema, + return draft; }); + +export const usePackQueryForm = ({ uniqueQueryIds, defaultValue }: UsePackQueryFormProps) => { + const idSet = useMemo>( + () => new Set(xor(uniqueQueryIds, defaultValue?.id ? [defaultValue.id] : [])), + [uniqueQueryIds, defaultValue] + ); + + return { + serializer, + idSet, + ...useHookForm({ + defaultValues: defaultValue + ? deserializer(defaultValue) + : { + id: '', + query: '', + interval: 3600, + ecs_mapping: [defaultEcsFormData], + }, + }), + }; }; diff --git a/x-pack/plugins/osquery/public/packs/queries/validations.ts b/x-pack/plugins/osquery/public/packs/queries/validations.ts index 54ea9deece692..37d74806fd1ae 100644 --- a/x-pack/plugins/osquery/public/packs/queries/validations.ts +++ b/x-pack/plugins/osquery/public/packs/queries/validations.ts @@ -6,12 +6,11 @@ */ import { i18n } from '@kbn/i18n'; +import type { FormData, ValidationFunc } from '../../shared_imports'; -import type { FormData, ValidationConfig, ValidationFunc } from '../../shared_imports'; -import { fieldValidators } from '../../shared_imports'; -export { queryFieldValidation } from '../../common/validations'; - +export const MAX_QUERY_LENGTH = 2000; const idPattern = /^[a-zA-Z0-9-_]+$/; +// still used in Packs export const idSchemaValidation: ValidationFunc = ({ value }) => { const valueIsValid = idPattern.test(value); if (!valueIsValid) { @@ -23,47 +22,39 @@ export const idSchemaValidation: ValidationFunc = ({ v } }; +export const idHookSchemaValidation = (value: string) => { + const valueIsValid = idPattern.test(value); + + if (!valueIsValid) { + return i18n.translate('xpack.osquery.pack.queryFlyoutForm.invalidIdError', { + defaultMessage: 'Characters must be alphanumeric, _, or -', + }); + } +}; + const createUniqueIdValidation = (ids: Set) => { - const uniqueIdCheck: ValidationFunc = ({ value }) => { + const uniqueIdCheck = (value: string) => { if (ids.has(value)) { - return { - message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.uniqueIdError', { - defaultMessage: 'ID must be unique', - }), - }; + return i18n.translate('xpack.osquery.pack.queryFlyoutForm.uniqueIdError', { + defaultMessage: 'ID must be unique', + }); } }; return uniqueIdCheck; }; -export const createIdFieldValidations = (ids: Set) => [ - fieldValidators.emptyField( - i18n.translate('xpack.osquery.pack.queryFlyoutForm.emptyIdError', { +export const createFormIdFieldValidations = (ids: Set) => ({ + required: { + message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.emptyIdError', { defaultMessage: 'ID is required', - }) - ), - idSchemaValidation, - createUniqueIdValidation(ids), -]; - -export const intervalFieldValidations: Array> = [ - { - validator: fieldValidators.numberGreaterThanField({ - than: 0, - message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldMinNumberError', { - defaultMessage: 'A positive interval value is required', - }), }), + value: true, }, - { - validator: fieldValidators.numberSmallerThanField({ - than: 604800, - message: ({ than }) => - i18n.translate('xpack.osquery.pack.queryFlyoutForm.intervalFieldMaxNumberError', { - defaultMessage: 'An interval value must be lower than {than}', - values: { than }, - }), - }), + validate: (text: string) => { + const isPatternValid = idHookSchemaValidation(text); + const isUnique = createUniqueIdValidation(ids)(text); + + return isPatternValid || isUnique; }, -]; +}); diff --git a/x-pack/plugins/osquery/public/packs/types.ts b/x-pack/plugins/osquery/public/packs/types.ts index 4a4253b35b048..dcdb03045ab22 100644 --- a/x-pack/plugins/osquery/public/packs/types.ts +++ b/x-pack/plugins/osquery/public/packs/types.ts @@ -6,24 +6,6 @@ */ import type { SavedObject } from '@kbn/core/public'; import type { PackQueryFormData } from './queries/use_pack_query_form'; -import type { PackQueryECSMapping } from './queries/use_pack_query_form'; - -export interface IQueryPayload { - attributes?: { - name: string; - id: string; - }; -} - -export interface PackItemQuery { - id: string; - name: string; - interval: number; - query: string; - platform?: string; - version?: string; - ecs_mapping?: PackQueryECSMapping[]; -} export type PackSavedObject = SavedObject<{ name: string; diff --git a/x-pack/plugins/osquery/public/results/results_table.tsx b/x-pack/plugins/osquery/public/results/results_table.tsx index a00818ae4857d..a1658538045a6 100644 --- a/x-pack/plugins/osquery/public/results/results_table.tsx +++ b/x-pack/plugins/osquery/public/results/results_table.tsx @@ -28,6 +28,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React, { createContext, useEffect, useState, useCallback, useContext, useMemo } from 'react'; import { pagePathGetters } from '@kbn/fleet-plugin/public'; +import type { ECSMapping } from '../../common/schemas/common'; import { useAllResults } from './use_all_results'; import type { ResultEdges } from '../../common/search_strategy'; import { Direction } from '../../common/search_strategy'; @@ -48,7 +49,7 @@ interface ResultsTableComponentProps { actionId: string; selectedAgent?: string; agentIds?: string[]; - ecsMapping?: Record; + ecsMapping?: ECSMapping; endDate?: string; startDate?: string; addToTimeline?: (payload: { query: [string, string]; isIcon?: true }) => React.ReactElement; @@ -186,10 +187,8 @@ const ResultsTableComponent: React.FC = ({ if (!ecsMapping) return; return reduce( - (acc, [key, value]) => { - // @ts-expect-error update types + (acc: Record, [key, value]) => { if (value?.field) { - // @ts-expect-error update types acc[value?.field] = [...(acc[value?.field] ?? []), key]; } @@ -202,7 +201,6 @@ const ResultsTableComponent: React.FC = ({ const getHeaderDisplay = useCallback( (columnName: string) => { - // @ts-expect-error update types if (ecsMappingConfig && ecsMappingConfig[columnName]) { return ( <> @@ -217,12 +215,9 @@ const ResultsTableComponent: React.FC = ({ /> {`:`}
    - { - // @ts-expect-error update types - ecsMappingConfig[columnName].map((fieldName) => ( -
  • {fieldName}
  • - )) - } + {ecsMappingConfig[columnName].map((fieldName) => ( +
  • {fieldName}
  • + ))}
} diff --git a/x-pack/plugins/osquery/public/routes/saved_queries/edit/form.tsx b/x-pack/plugins/osquery/public/routes/saved_queries/edit/form.tsx index f5ab2308d1720..1b24b4a71eeb5 100644 --- a/x-pack/plugins/osquery/public/routes/saved_queries/edit/form.tsx +++ b/x-pack/plugins/osquery/public/routes/saved_queries/edit/form.tsx @@ -16,14 +16,17 @@ import { import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { PackQueryFormData } from '../../../packs/queries/use_pack_query_form'; +import { FormProvider } from 'react-hook-form'; import { useRouterNavigate } from '../../../common/lib/kibana'; -import { Form } from '../../../shared_imports'; import { SavedQueryForm } from '../../../saved_queries/form'; +import type { + SavedQueryFormData, + SavedQuerySOFormData, +} from '../../../saved_queries/form/use_saved_query_form'; import { useSavedQueryForm } from '../../../saved_queries/form/use_saved_query_form'; interface EditSavedQueryFormProps { - defaultValue?: PackQueryFormData; + defaultValue?: SavedQuerySOFormData; handleSubmit: (payload: unknown) => Promise; viewMode?: boolean; } @@ -35,15 +38,28 @@ const EditSavedQueryFormComponent: React.FC = ({ }) => { const savedQueryListProps = useRouterNavigate('saved_queries'); - const { form } = useSavedQueryForm({ + const hooksForm = useSavedQueryForm({ defaultValue, - handleSubmit, }); - const { submit, isSubmitting } = form; + + const { + serializer, + idSet, + handleSubmit: formSubmit, + formState: { isSubmitting }, + } = hooksForm; + + const onSubmit = (payload: SavedQueryFormData) => { + const serializedData = serializer(payload); + try { + handleSubmit(serializedData); + // eslint-disable-next-line no-empty + } catch (e) {} + }; return ( -
- + + {!viewMode && ( <> @@ -65,7 +81,7 @@ const EditSavedQueryFormComponent: React.FC = ({ fill size="m" iconType="save" - onClick={submit} + onClick={formSubmit(onSubmit)} > = ({ )} - + ); }; diff --git a/x-pack/plugins/osquery/public/routes/saved_queries/edit/tabs.tsx b/x-pack/plugins/osquery/public/routes/saved_queries/edit/tabs.tsx index c8e57f4f5db23..081530479c8b1 100644 --- a/x-pack/plugins/osquery/public/routes/saved_queries/edit/tabs.tsx +++ b/x-pack/plugins/osquery/public/routes/saved_queries/edit/tabs.tsx @@ -9,6 +9,7 @@ import { EuiTabbedContent, EuiNotificationBadge } from '@elastic/eui'; import React, { useMemo } from 'react'; import type { ReactElement } from 'react'; +import type { ECSMapping } from '../../../../common/schemas/common'; import { ResultsTable } from '../../../results/results_table'; import { ActionResultsSummary } from '../../../action_results/action_results_summary'; @@ -16,7 +17,7 @@ interface ResultTabsProps { actionId: string; agentIds?: string[]; startDate?: string; - ecsMapping?: Record; + ecsMapping?: ECSMapping; failedAgentsCount?: number; endDate?: string; addToTimeline?: (payload: { query: [string, string]; isIcon?: true }) => ReactElement; diff --git a/x-pack/plugins/osquery/public/routes/saved_queries/new/form.tsx b/x-pack/plugins/osquery/public/routes/saved_queries/new/form.tsx index 4dc26c5aaedf4..350c35b2b3fa5 100644 --- a/x-pack/plugins/osquery/public/routes/saved_queries/new/form.tsx +++ b/x-pack/plugins/osquery/public/routes/saved_queries/new/form.tsx @@ -15,15 +15,19 @@ import { } from '@elastic/eui'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { FormProvider } from 'react-hook-form'; -import type { PackQueryFormData } from '../../../packs/queries/use_pack_query_form'; +import { isEmpty } from 'lodash'; import { useRouterNavigate } from '../../../common/lib/kibana'; -import { Form } from '../../../shared_imports'; import { SavedQueryForm } from '../../../saved_queries/form'; +import type { + SavedQuerySOFormData, + SavedQueryFormData, +} from '../../../saved_queries/form/use_saved_query_form'; import { useSavedQueryForm } from '../../../saved_queries/form/use_saved_query_form'; interface NewSavedQueryFormProps { - defaultValue?: PackQueryFormData; + defaultValue?: SavedQuerySOFormData; handleSubmit: (payload: unknown) => Promise; } @@ -33,15 +37,24 @@ const NewSavedQueryFormComponent: React.FC = ({ }) => { const savedQueryListProps = useRouterNavigate('saved_queries'); - const { form } = useSavedQueryForm({ + const hooksForm = useSavedQueryForm({ defaultValue, - handleSubmit, }); - const { submit, isSubmitting, isValid } = form; + const { + serializer, + idSet, + handleSubmit: formSubmit, + formState: { isSubmitting, errors }, + } = hooksForm; + + const onSubmit = (payload: SavedQueryFormData) => { + const serializedData = serializer(payload); + handleSubmit(serializedData); + }; return ( -
- + + @@ -61,7 +74,7 @@ const NewSavedQueryFormComponent: React.FC = ({ fill size="m" iconType="save" - onClick={submit} + onClick={formSubmit(onSubmit)} > = ({ - + ); }; diff --git a/x-pack/plugins/osquery/public/saved_queries/form/code_editor_field.tsx b/x-pack/plugins/osquery/public/saved_queries/form/code_editor_field.tsx index de9d62fe1406c..2f4ee427461dc 100644 --- a/x-pack/plugins/osquery/public/saved_queries/form/code_editor_field.tsx +++ b/x-pack/plugins/osquery/public/saved_queries/form/code_editor_field.tsx @@ -10,9 +10,11 @@ import { EuiCodeBlock, EuiFormRow } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; +import { useController } from 'react-hook-form'; +import { i18n } from '@kbn/i18n'; +import { MAX_QUERY_LENGTH } from '../../packs/queries/validations'; import { OsquerySchemaLink } from '../../components/osquery_schema_link'; import { OsqueryEditor } from '../../editor'; -import type { FieldHook } from '../../shared_imports'; const StyledEuiCodeBlock = styled(EuiCodeBlock)` min-height: 100px; @@ -20,20 +22,47 @@ const StyledEuiCodeBlock = styled(EuiCodeBlock)` interface CodeEditorFieldProps { euiFieldProps?: Record; - field: FieldHook; + labelAppend?: string; + helpText?: string; } -const CodeEditorFieldComponent: React.FC = ({ euiFieldProps, field }) => { - const { value, label, labelAppend, helpText, setValue, errors } = field; - const error = errors[0]?.message; +const CodeEditorFieldComponent: React.FC = ({ + euiFieldProps, + labelAppend, + helpText, +}) => { + const { + field: { onChange, value }, + fieldState: { error }, + } = useController({ + name: 'query', + rules: { + required: { + message: i18n.translate('xpack.osquery.pack.queryFlyoutForm.emptyQueryError', { + defaultMessage: 'Query is a required field', + }), + value: true, + }, + maxLength: { + message: i18n.translate('xpack.osquery.liveQuery.queryForm.largeQueryError', { + defaultMessage: 'Query is too large (max {maxLength} characters)', + values: { maxLength: MAX_QUERY_LENGTH }, + }), + value: MAX_QUERY_LENGTH, + }, + }, + defaultValue: '', + }); return ( } helpText={helpText} - isInvalid={typeof error === 'string'} - error={error} + isInvalid={!!error?.message} + error={error?.message} fullWidth > {euiFieldProps?.isDisabled ? ( @@ -46,7 +75,7 @@ const CodeEditorFieldComponent: React.FC = ({ euiFieldProp {value} ) : ( - + )} ); diff --git a/x-pack/plugins/osquery/public/saved_queries/form/index.tsx b/x-pack/plugins/osquery/public/saved_queries/form/index.tsx index ec87f430eea92..6bddd7f0508e4 100644 --- a/x-pack/plugins/osquery/public/saved_queries/form/index.tsx +++ b/x-pack/plugins/osquery/public/saved_queries/form/index.tsx @@ -17,25 +17,25 @@ import React, { useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ALL_OSQUERY_VERSIONS_OPTIONS } from '../../packs/queries/constants'; +import { IntervalField, QueryIdField, QueryDescriptionField, VersionField } from '../../form'; import { PlatformCheckBoxGroupField } from '../../packs/queries/platform_checkbox_group_field'; -import { Field, getUseField, UseField } from '../../shared_imports'; -import { CodeEditorField } from './code_editor_field'; +import { ALL_OSQUERY_VERSIONS_OPTIONS } from '../../packs/queries/constants'; import { ECSMappingEditorField } from '../../packs/queries/lazy_ecs_mapping_editor_field'; import { PlaygroundFlyout } from './playground_flyout'; - -export const CommonUseField = getUseField({ component: Field }); +import { CodeEditorField } from './code_editor_field'; interface SavedQueryFormProps { viewMode?: boolean; hasPlayground?: boolean; isValid?: boolean; + idSet?: Set; } const SavedQueryFormComponent: React.FC = ({ viewMode, hasPlayground, isValid, + idSet, }) => { const [playgroundVisible, setPlaygroundVisible] = useState(false); @@ -77,11 +77,11 @@ const SavedQueryFormComponent: React.FC = ({ return ( <> - + - + - + @@ -119,16 +119,12 @@ const SavedQueryFormComponent: React.FC = ({ - + - + - + {playgroundVisible && ( diff --git a/x-pack/plugins/osquery/public/saved_queries/form/playground_flyout.tsx b/x-pack/plugins/osquery/public/saved_queries/form/playground_flyout.tsx index a253fada318a0..741651b5f2a9a 100644 --- a/x-pack/plugins/osquery/public/saved_queries/form/playground_flyout.tsx +++ b/x-pack/plugins/osquery/public/saved_queries/form/playground_flyout.tsx @@ -10,8 +10,8 @@ import React, { useMemo } from 'react'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useFormContext } from 'react-hook-form'; import { LiveQuery } from '../../live_queries'; -import { useFormData } from '../../shared_imports'; const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` &.euiFlyoutHeader.euiFlyoutHeader--hasBorder { @@ -26,11 +26,13 @@ interface PlaygroundFlyoutProps { } const PlaygroundFlyoutComponent: React.FC = ({ enabled, onClose }) => { - const [{ query, ecs_mapping: ecsMapping, id }, formDataSerializer] = useFormData(); - + // @ts-expect-error update types + const { serializer, watch } = useFormContext(); + const watchedValues = watch(); + const { query, ecs_mapping: ecsMapping, id } = watchedValues; /* recalculate the form data when ecs_mapping changes */ // eslint-disable-next-line react-hooks/exhaustive-deps - const serializedFormData = useMemo(() => formDataSerializer(), [ecsMapping, formDataSerializer]); + const serializedFormData = useMemo(() => serializer(watchedValues), [ecsMapping]); return ( diff --git a/x-pack/plugins/osquery/public/saved_queries/form/use_saved_query_form.tsx b/x-pack/plugins/osquery/public/saved_queries/form/use_saved_query_form.tsx index 92849b57f7122..36f303c8dfff3 100644 --- a/x-pack/plugins/osquery/public/saved_queries/form/use_saved_query_form.tsx +++ b/x-pack/plugins/osquery/public/saved_queries/form/use_saved_query_form.tsx @@ -5,105 +5,98 @@ * 2.0. */ +import { useForm as useHookForm } from 'react-hook-form'; import { isArray, isEmpty, map } from 'lodash'; -import uuid from 'uuid'; -import { produce } from 'immer'; +import type { Draft } from 'immer'; +import produce from 'immer'; import { useMemo } from 'react'; - +import type { ECSMapping } from '../../../common/schemas/common'; import { convertECSMappingToObject } from '../../../common/schemas/common/utils'; -import { useForm } from '../../shared_imports'; -import { createFormSchema } from '../../packs/queries/schema'; -import type { - PackQueryECSMapping, - PackQueryFormData, -} from '../../packs/queries/use_pack_query_form'; +import type { EcsMappingFormField } from '../../packs/queries/ecs_mapping_editor_field'; +import { defaultEcsFormData } from '../../packs/queries/ecs_mapping_editor_field'; import { useSavedQueries } from '../use_saved_queries'; -const SAVED_QUERY_FORM_ID = 'savedQueryForm'; +export interface SavedQuerySOFormData { + id?: string; + description?: string; + query?: string; + interval?: string; + platform?: string; + version?: string | undefined; + ecs_mapping?: ECSMapping | undefined; +} -interface ReturnFormData { +export interface SavedQueryFormData { id?: string; description?: string; - query: string; + query?: string; interval?: number; platform?: string; version?: string[]; - ecs_mapping?: PackQueryECSMapping[] | undefined; + ecs_mapping: EcsMappingFormField[]; } interface UseSavedQueryFormProps { - defaultValue?: PackQueryFormData; - handleSubmit: (payload: unknown) => Promise; + defaultValue?: SavedQuerySOFormData; } -export const useSavedQueryForm = ({ defaultValue, handleSubmit }: UseSavedQueryFormProps) => { +const deserializer = (payload: SavedQuerySOFormData): SavedQueryFormData => ({ + id: payload.id, + description: payload.description, + query: payload.query, + interval: payload.interval ? parseInt(payload.interval, 10) : 3600, + platform: payload.platform, + version: payload.version ? [payload.version] : [], + ecs_mapping: !isEmpty(payload.ecs_mapping) + ? (map(payload.ecs_mapping, (value, key: string) => ({ + key, + result: { + type: Object.keys(value)[0], + value: Object.values(value)[0], + }, + })) as unknown as EcsMappingFormField[]) + : [defaultEcsFormData], +}); + +export const savedQueryDataSerializer = (payload: SavedQueryFormData): SavedQuerySOFormData => + // @ts-expect-error update types + produce(payload, (draft: Draft) => { + if (isArray(draft.version)) { + if (!draft.version.length) { + draft.version = ''; + } else { + draft.version = draft.version[0]; + } + } + + if (isArray(draft.platform) && !draft.platform.length) { + delete draft.platform; + } + + draft.ecs_mapping = convertECSMappingToObject(payload.ecs_mapping); + + if (draft.interval) { + draft.interval = draft.interval + ''; + } + + return draft; + }); + +export const useSavedQueryForm = ({ defaultValue }: UseSavedQueryFormProps) => { const { data } = useSavedQueries({}); - const ids: string[] = useMemo(() => map(data, 'attributes.id') ?? [], [data]); + const ids: string[] = useMemo(() => map(data?.data, 'attributes.id') ?? [], [data]); const idSet = useMemo>(() => { const res = new Set(ids); if (defaultValue && defaultValue.id) res.delete(defaultValue.id); return res; }, [ids, defaultValue]); - const formSchema = useMemo(() => createFormSchema(idSet), [idSet]); - - return useForm({ - id: SAVED_QUERY_FORM_ID + uuid.v4(), - schema: formSchema, - onSubmit: async (formData, isValid) => { - if (isValid) { - try { - await handleSubmit(formData); - // eslint-disable-next-line no-empty - } catch (e) {} - } - }, - defaultValue, - // @ts-expect-error update types - serializer: (payload) => - produce(payload, (draft) => { - if (isArray(draft.version)) { - if (!draft.version.length) { - // @ts-expect-error update types - draft.version = ''; - } else { - // @ts-expect-error update types - draft.version = draft.version[0]; - } - } - if (isEmpty(payload.ecs_mapping)) { - delete draft.ecs_mapping; - } else { - // @ts-expect-error update types - draft.ecs_mapping = convertECSMappingToObject(payload.ecs_mapping); - } - - // @ts-expect-error update types - draft.interval = draft.interval + ''; - - return draft; - }), - deserializer: (payload) => { - if (!payload) return {} as ReturnFormData; - - return { - id: payload.id, - description: payload.description, - query: payload.query, - interval: payload.interval ?? 3600, - platform: payload.platform, - version: payload.version ? [payload.version] : [], - ecs_mapping: (!isEmpty(payload.ecs_mapping) - ? map(payload.ecs_mapping, (value, key: string) => ({ - key, - result: { - type: Object.keys(value)[0], - value: Object.values(value)[0], - }, - })) - : ([] as PackQueryECSMapping[])) as PackQueryECSMapping[], - }; - }, - }); + return { + serializer: savedQueryDataSerializer, + idSet, + ...useHookForm({ + defaultValues: defaultValue ? deserializer(defaultValue) : {}, + }), + }; }; diff --git a/x-pack/plugins/osquery/public/saved_queries/saved_queries_dropdown.tsx b/x-pack/plugins/osquery/public/saved_queries/saved_queries_dropdown.tsx index c70bad1a617c1..eedaf8ac5ce0f 100644 --- a/x-pack/plugins/osquery/public/saved_queries/saved_queries_dropdown.tsx +++ b/x-pack/plugins/osquery/public/saved_queries/saved_queries_dropdown.tsx @@ -9,11 +9,11 @@ import { find } from 'lodash/fp'; import { EuiCodeBlock, EuiFormRow, EuiComboBox, EuiTextColor } from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; +import { useWatch } from 'react-hook-form'; import { QUERIES_DROPDOWN_LABEL, QUERIES_DROPDOWN_SEARCH_FIELD_LABEL } from './constants'; import { OsquerySchemaLink } from '../components/osquery_schema_link'; import { useSavedQueries } from './use_saved_queries'; -import { useFormData } from '../shared_imports'; import type { SavedQuerySO } from '../routes/saved_queries/list'; const TextTruncate = styled.div` @@ -49,10 +49,9 @@ const SavedQueriesDropdownComponent: React.FC = ({ disabled, onChange, }) => { + const savedQueryId = useWatch({ name: 'savedQueryId' }); const [selectedOptions, setSelectedOptions] = useState([]); - const [{ savedQueryId }] = useFormData(); - const { data } = useSavedQueries({}); const queryOptions = useMemo( diff --git a/x-pack/plugins/osquery/public/saved_queries/saved_query_flyout.tsx b/x-pack/plugins/osquery/public/saved_queries/saved_query_flyout.tsx index 1e92294a5f1b4..abf8138ff11fa 100644 --- a/x-pack/plugins/osquery/public/saved_queries/saved_query_flyout.tsx +++ b/x-pack/plugins/osquery/public/saved_queries/saved_query_flyout.tsx @@ -17,17 +17,18 @@ import { EuiButtonEmpty, EuiButton, } from '@elastic/eui'; +import { FormProvider } from 'react-hook-form'; + import React, { useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { Form } from '../shared_imports'; +import type { SavedQuerySOFormData, SavedQueryFormData } from './form/use_saved_query_form'; import { useSavedQueryForm } from './form/use_saved_query_form'; import { SavedQueryForm } from './form'; import { useCreateSavedQuery } from './use_create_saved_query'; -import type { PackQueryFormData } from '../packs/queries/use_pack_query_form'; interface AddQueryFlyoutProps { - defaultValue: PackQueryFormData; + defaultValue: SavedQuerySOFormData; onClose: () => void; isExternal?: boolean; } @@ -41,18 +42,24 @@ const SavedQueryFlyoutComponent: React.FC = ({ }) => { const createSavedQueryMutation = useCreateSavedQuery({ withRedirect: false }); - const handleSubmit = useCallback( - async (payload) => { - await createSavedQueryMutation.mutateAsync(payload).then(() => onClose()); - }, - [createSavedQueryMutation, onClose] - ); - - const { form } = useSavedQueryForm({ + const hooksForm = useSavedQueryForm({ defaultValue, - handleSubmit, }); - const { submit, isSubmitting } = form; + const { + serializer, + idSet, + handleSubmit, + formState: { isSubmitting }, + } = hooksForm; + const onSubmit = useCallback( + async (payload: SavedQueryFormData) => { + const serializedData = serializer(payload); + // TODO CHECK THIS + // @ts-expect-error update types + await createSavedQueryMutation.mutateAsync(serializedData).then(() => onClose()); + }, + [createSavedQueryMutation, onClose, serializer] + ); return ( @@ -74,9 +81,9 @@ const SavedQueryFlyoutComponent: React.FC = ({ -
- - + + +
@@ -89,7 +96,7 @@ const SavedQueryFlyoutComponent: React.FC = ({
- + { + onSuccess: (payload: { data: SavedQuerySO }) => { queryClient.invalidateQueries([SAVED_QUERIES_ID]); queryClient.invalidateQueries([SAVED_QUERY_ID, { savedQueryId }]); navigateToApp(PLUGIN_ID, { path: pagePathGetters.saved_queries() }); @@ -48,7 +48,7 @@ export const useUpdateSavedQuery = ({ savedQueryId }: UseUpdateSavedQueryProps) i18n.translate('xpack.osquery.editSavedQuery.successToastMessageText', { defaultMessage: 'Successfully updated "{savedQueryName}" query', values: { - savedQueryName: payload.attributes?.id ?? '', + savedQueryName: payload.data.attributes?.id ?? '', }, }) ); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0273a23d4179f..837a3a17db9ce 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -23657,7 +23657,7 @@ "xpack.osquery.pack.queriesTable.deleteActionAriaLabel": "Supprimer {queryName}", "xpack.osquery.pack.queriesTable.editActionAriaLabel": "Modifier {queryName}", "xpack.osquery.pack.queryFlyoutForm.intervalFieldMaxNumberError": "La valeur d'intervalle doit être inférieure à {than}", - "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage": "La recherche en cours ne retourne pas de champ {columnName}", + "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "Valeur obligatoire.", "xpack.osquery.pack.table.activatedSuccessToastMessageText": "Le pack \"{packName}\" a bien été activé.", "xpack.osquery.pack.table.deactivatedSuccessToastMessageText": "Le pack \"{packName}\" a bien été désactivé.", "xpack.osquery.pack.table.deleteQueriesButtonLabel": "Supprimer {queriesCount, plural, one {# recherche} other {# recherches}}", @@ -23820,7 +23820,6 @@ "xpack.osquery.pack.queriesTable.viewResultsColumnTitle": "Afficher les résultats", "xpack.osquery.pack.queryFlyoutForm.cancelButtonLabel": "Annuler", "xpack.osquery.pack.queryFlyoutForm.deleteECSMappingRowButtonAriaLabel": "Supprimer la ligne de mapping ECS", - "xpack.osquery.pack.queryFlyoutForm.descriptionFieldLabel": "Description (facultative)", "xpack.osquery.pack.queryFlyoutForm.ecsFieldRequiredErrorMessage": "Le champ ECS est requis.", "xpack.osquery.pack.queryFlyoutForm.emptyIdError": "L'ID est requis", "xpack.osquery.pack.queryFlyoutForm.emptyQueryError": "La recherche est requise", @@ -23830,12 +23829,11 @@ "xpack.osquery.pack.queryFlyoutForm.invalidIdError": "Les caractères doivent être alphanumériques, _ ou -", "xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "Champ ECS", "xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "Valeur", - "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "Valeur obligatoire.", + "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage": "La recherche en cours ne retourne pas de champ {columnName}", "xpack.osquery.pack.queryFlyoutForm.platformFieldLabel": "Plateforme", "xpack.osquery.pack.queryFlyoutForm.platformLinusLabel": "macOS", "xpack.osquery.pack.queryFlyoutForm.platformMacOSLabel": "Linux", "xpack.osquery.pack.queryFlyoutForm.platformWindowsLabel": "Windows", - "xpack.osquery.pack.queryFlyoutForm.queryFieldLabel": "Recherche", "xpack.osquery.pack.queryFlyoutForm.saveButtonLabel": "Enregistrer", "xpack.osquery.pack.queryFlyoutForm.uniqueIdError": "L'ID doit être unique", "xpack.osquery.pack.queryFlyoutForm.versionFieldLabel": "Version Osquery minimale", @@ -23851,7 +23849,6 @@ "xpack.osquery.packList.prePackagedPacks.emptyPromptTitle.emptyPromptMessage": "Un pack est un ensemble de requêtes pouvant être planifié. Chargez des packs prédéfinis ou créez vos propres packs.", "xpack.osquery.packList.prePackagedPacks.loadButtonLabel": "Charger les pack prédéfinis Elastic", "xpack.osquery.packList.prePackagedPacks.updateButtonLabel": "Mettre à jour les pack prédéfinis Elastic", - "xpack.osquery.packs.dropdown.searchFieldLabel": "Pack", "xpack.osquery.packs.dropdown.searchFieldPlaceholder": "Rechercher un pack à exécuter", "xpack.osquery.packs.table.activeColumnTitle": "Actif", "xpack.osquery.packs.table.createdByColumnTitle": "Créé par", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 556e8facd1534..26614ab69d1df 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -23637,7 +23637,7 @@ "xpack.osquery.pack.queriesTable.deleteActionAriaLabel": "{queryName}を削除", "xpack.osquery.pack.queriesTable.editActionAriaLabel": "{queryName}を編集", "xpack.osquery.pack.queryFlyoutForm.intervalFieldMaxNumberError": "間隔値は{than}よりも小さくなければなりません", - "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage": "現在のクエリは{columnName}フィールドを返しません", + "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "値が必要です。", "xpack.osquery.pack.table.activatedSuccessToastMessageText": "\"{packName}\"が正常にアクティブ化されました", "xpack.osquery.pack.table.deactivatedSuccessToastMessageText": "\"{packName}\"が正常に非アクティブ化されました", "xpack.osquery.pack.table.deleteQueriesButtonLabel": "{queriesCount, plural, other {# 個のクエリ}}を削除", @@ -23800,7 +23800,6 @@ "xpack.osquery.pack.queriesTable.viewResultsColumnTitle": "結果を表示", "xpack.osquery.pack.queryFlyoutForm.cancelButtonLabel": "キャンセル", "xpack.osquery.pack.queryFlyoutForm.deleteECSMappingRowButtonAriaLabel": "ECSマッピング行を削除", - "xpack.osquery.pack.queryFlyoutForm.descriptionFieldLabel": "説明(オプション)", "xpack.osquery.pack.queryFlyoutForm.ecsFieldRequiredErrorMessage": "ECSフィールドは必須です。", "xpack.osquery.pack.queryFlyoutForm.emptyIdError": "IDが必要です", "xpack.osquery.pack.queryFlyoutForm.emptyQueryError": "クエリは必須フィールドです", @@ -23810,12 +23809,11 @@ "xpack.osquery.pack.queryFlyoutForm.invalidIdError": "文字は英数字、_、または-でなければなりません", "xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "ECSフィールド", "xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "値", - "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "値が必要です。", + "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage": "現在のクエリは{columnName}フィールドを返しません", "xpack.osquery.pack.queryFlyoutForm.platformFieldLabel": "プラットフォーム", "xpack.osquery.pack.queryFlyoutForm.platformLinusLabel": "macOS", "xpack.osquery.pack.queryFlyoutForm.platformMacOSLabel": "Linux", "xpack.osquery.pack.queryFlyoutForm.platformWindowsLabel": "Windows", - "xpack.osquery.pack.queryFlyoutForm.queryFieldLabel": "クエリ", "xpack.osquery.pack.queryFlyoutForm.saveButtonLabel": "保存", "xpack.osquery.pack.queryFlyoutForm.uniqueIdError": "IDは一意でなければなりません", "xpack.osquery.pack.queryFlyoutForm.versionFieldLabel": "最低Osqueryバージョン", @@ -23831,7 +23829,6 @@ "xpack.osquery.packList.prePackagedPacks.emptyPromptTitle.emptyPromptMessage": "パックはスケジュールできるクエリのセットです。事前構築済みパックを読み込むか、独自のパックを作成します。", "xpack.osquery.packList.prePackagedPacks.loadButtonLabel": "Elastic事前構築済みパックを読み込む", "xpack.osquery.packList.prePackagedPacks.updateButtonLabel": "Elastic事前構築済みパックの更新", - "xpack.osquery.packs.dropdown.searchFieldLabel": "パック", "xpack.osquery.packs.dropdown.searchFieldPlaceholder": "実行するパックを検索", "xpack.osquery.packs.table.activeColumnTitle": "アクティブ", "xpack.osquery.packs.table.createdByColumnTitle": "作成者", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 258ac5023fa9b..413d470fb870e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -23665,7 +23665,7 @@ "xpack.osquery.pack.queriesTable.deleteActionAriaLabel": "删除 {queryName}", "xpack.osquery.pack.queriesTable.editActionAriaLabel": "编辑 {queryName}", "xpack.osquery.pack.queryFlyoutForm.intervalFieldMaxNumberError": "间隔值必须小于 {than}", - "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage": "当前查询不返回 {columnName} 字段", + "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "“值”必填。", "xpack.osquery.pack.table.activatedSuccessToastMessageText": "已成功激活“{packName}”包", "xpack.osquery.pack.table.deactivatedSuccessToastMessageText": "已成功停用“{packName}”包", "xpack.osquery.pack.table.deleteQueriesButtonLabel": "删除 {queriesCount, plural, other {# 个查询}}", @@ -23828,7 +23828,6 @@ "xpack.osquery.pack.queriesTable.viewResultsColumnTitle": "查看结果", "xpack.osquery.pack.queryFlyoutForm.cancelButtonLabel": "取消", "xpack.osquery.pack.queryFlyoutForm.deleteECSMappingRowButtonAriaLabel": "删除 ECS 映射行", - "xpack.osquery.pack.queryFlyoutForm.descriptionFieldLabel": "描述(可选)", "xpack.osquery.pack.queryFlyoutForm.ecsFieldRequiredErrorMessage": "ECS 字段必填。", "xpack.osquery.pack.queryFlyoutForm.emptyIdError": "“ID”必填", "xpack.osquery.pack.queryFlyoutForm.emptyQueryError": "“查询”是必填字段", @@ -23838,12 +23837,11 @@ "xpack.osquery.pack.queryFlyoutForm.invalidIdError": "字符必须是数字字母、_ 或 -", "xpack.osquery.pack.queryFlyoutForm.mappingEcsFieldLabel": "ECS 字段", "xpack.osquery.pack.queryFlyoutForm.mappingValueFieldLabel": "值", - "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldRequiredErrorMessage": "“值”必填。", + "xpack.osquery.pack.queryFlyoutForm.osqueryResultFieldValueMissingErrorMessage": "当前查询不返回 {columnName} 字段", "xpack.osquery.pack.queryFlyoutForm.platformFieldLabel": "平台", "xpack.osquery.pack.queryFlyoutForm.platformLinusLabel": "macOS", "xpack.osquery.pack.queryFlyoutForm.platformMacOSLabel": "Linux", "xpack.osquery.pack.queryFlyoutForm.platformWindowsLabel": "Windows", - "xpack.osquery.pack.queryFlyoutForm.queryFieldLabel": "查询", "xpack.osquery.pack.queryFlyoutForm.saveButtonLabel": "保存", "xpack.osquery.pack.queryFlyoutForm.uniqueIdError": "ID 必须唯一", "xpack.osquery.pack.queryFlyoutForm.versionFieldLabel": "最低 Osquery 版本", @@ -23859,7 +23857,6 @@ "xpack.osquery.packList.prePackagedPacks.emptyPromptTitle.emptyPromptMessage": "包是您可以计划的一组查询。加载预构建包或创建您自己的预构建包。", "xpack.osquery.packList.prePackagedPacks.loadButtonLabel": "加载 Elastic 预构建包", "xpack.osquery.packList.prePackagedPacks.updateButtonLabel": "更新 Elastic 预构建包", - "xpack.osquery.packs.dropdown.searchFieldLabel": "包", "xpack.osquery.packs.dropdown.searchFieldPlaceholder": "搜索要运行的包", "xpack.osquery.packs.table.activeColumnTitle": "活动", "xpack.osquery.packs.table.createdByColumnTitle": "创建者", From 147e4142c80b8b30d70f30d44230ec09ad0018f2 Mon Sep 17 00:00:00 2001 From: Juan Pablo Djeredjian Date: Tue, 23 Aug 2022 13:35:53 +0200 Subject: [PATCH 13/41] [Security Solution][Detections] Update rules count indicator in the Rules table to show pagination info (#138902) **Fixes:** https://github.com/elastic/kibana/issues/121754 ## Summary Changes rules count pagination count to format: **"Showing 1-10 of 596 rules"** -> when page 1, rules per page is 10 and total rules is 596 **"Showing 6-6 of 6 rules"** -> when page 2, rules per page is 5 and total rules is 6 See other cases in tests. **Before changes** ![image](https://user-images.githubusercontent.com/5354282/184883106-118f0041-5567-4cf8-bfd5-8383e8146018.png) ![image](https://user-images.githubusercontent.com/5354282/184884145-22d30482-cc2d-4796-8f84-d809a8ca6d8a.png) **After changes** ![image](https://user-images.githubusercontent.com/5354282/184882149-d6c55dff-39a0-4a72-94a9-217b2e5ca7ac.png) ![image](https://user-images.githubusercontent.com/5354282/184886334-a107a2c5-31dc-4a7b-9e70-54c87c1630e0.png) ## Codebase changes - Refactors `AllRulesUtilityBar` component to separate usage of the utility bar between the all-rules table use-case and the Exceptions table use-case, by creating a new `ExceptionsTableUtilityBar` component. ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../detection_rules/custom_query_rule.spec.ts | 30 ++-- .../detection_rules/prebuilt_rules.spec.ts | 15 +- .../rules/all/exceptions/exceptions_table.tsx | 9 +- .../exceptions_table_utility_bar.test.tsx | 43 +++++ .../exceptions_table_utility_bar.tsx | 51 ++++++ .../rules/all/exceptions/translations.ts | 16 ++ ...t.tsx => rules_table_utility_bar.test.tsx} | 159 ++++++++++++++---- ...ty_bar.tsx => rules_table_utility_bar.tsx} | 134 +++++++-------- .../rules/all/rules_tables.tsx | 11 +- .../detection_engine/rules/translations.ts | 13 +- .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 13 files changed, 334 insertions(+), 153 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx rename x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/{utility_bar.test.tsx => rules_table_utility_bar.test.tsx} (52%) rename x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/{utility_bar.tsx => rules_table_utility_bar.tsx} (58%) diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts index ba886993c7433..5725e511f2dec 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts @@ -23,7 +23,6 @@ import { RULES_TABLE, RULE_SWITCH, SEVERITY, - SHOWING_RULES_TEXT, } from '../../screens/alerts_detection_rules'; import { ABOUT_CONTINUE_BTN, @@ -218,7 +217,10 @@ describe('Custom query rules', () => { const initialNumberOfRules = rules.length; const expectedNumberOfRulesAfterDeletion = initialNumberOfRules - 1; - cy.get(SHOWING_RULES_TEXT).should('have.text', `Showing ${initialNumberOfRules} rules`); + cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => { + const numberOfRules = body.data.length; + expect(numberOfRules).to.eql(initialNumberOfRules); + }); deleteFirstRule(); waitForRulesTableToBeRefreshed(); @@ -226,10 +228,10 @@ describe('Custom query rules', () => { cy.get(RULES_TABLE) .find(RULES_ROW) .should('have.length', expectedNumberOfRulesAfterDeletion); - cy.get(SHOWING_RULES_TEXT).should( - 'have.text', - `Showing ${expectedNumberOfRulesAfterDeletion} rules` - ); + cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => { + const numberOfRules = body.data.length; + expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion); + }); cy.get(CUSTOM_RULES_BTN).should( 'have.text', `Custom rules (${expectedNumberOfRulesAfterDeletion})` @@ -253,10 +255,10 @@ describe('Custom query rules', () => { cy.get(RULES_TABLE) .find(RULES_ROW) .should('have.length', expectedNumberOfRulesAfterDeletion); - cy.get(SHOWING_RULES_TEXT).should( - 'have.text', - `Showing ${expectedNumberOfRulesAfterDeletion} rule` - ); + cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => { + const numberOfRules = body.data.length; + expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion); + }); cy.get(CUSTOM_RULES_BTN).should( 'have.text', `Custom rules (${expectedNumberOfRulesAfterDeletion})` @@ -281,10 +283,10 @@ describe('Custom query rules', () => { cy.get(RULES_TABLE) .find(RULES_ROW) .should('have.length', expectedNumberOfRulesAfterDeletion); - cy.get(SHOWING_RULES_TEXT).should( - 'have.text', - `Showing ${expectedNumberOfRulesAfterDeletion} rules` - ); + cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => { + const numberOfRules = body.data.length; + expect(numberOfRules).to.eql(expectedNumberOfRulesAfterDeletion); + }); cy.get(CUSTOM_RULES_BTN).should( 'have.text', `Custom rules (${expectedNumberOfRulesAfterDeletion})` diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts index 397162f69d490..ed5f5629985ae 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/prebuilt_rules.spec.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { rawRules } from '../../../server/lib/detection_engine/rules/prepackaged_rules'; import { COLLAPSED_ACTION_BTN, ELASTIC_RULES_BTN, @@ -12,11 +13,10 @@ import { RELOAD_PREBUILT_RULES_BTN, RULES_EMPTY_PROMPT, RULE_SWITCH, - SHOWING_RULES_TEXT, RULES_MONITORING_TABLE, SELECT_ALL_RULES_ON_PAGE_CHECKBOX, + RULE_NAME, } from '../../screens/alerts_detection_rules'; - import { deleteFirstRule, deleteSelectedRules, @@ -59,7 +59,16 @@ describe('Prebuilt rules', () => { changeRowsPerPageTo(rowsPerPage); - cy.get(SHOWING_RULES_TEXT).should('have.text', `Showing ${expectedNumberOfRules} rules`); + cy.request({ url: '/api/detection_engine/rules/_find' }).then(({ body }) => { + // Assert the total number of loaded rules equals the expected number of in-memory rules + expect(body.total).to.equal(rawRules.length); + // Assert the table was refreshed with the rules returned by the API request + const ruleNames = rawRules.map((rule) => rule.name); + cy.get(RULE_NAME).each(($item) => { + expect($item.text()).to.be.oneOf(ruleNames); + }); + }); + cy.get(pageSelector(expectedNumberOfPages)).should('exist'); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx index 415bbfd1498c7..d7908d0bbce66 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx @@ -26,7 +26,7 @@ import { useFormatUrl } from '../../../../../../common/components/link_to'; import { Loader } from '../../../../../../common/components/loader'; import * as i18n from './translations'; -import { AllRulesUtilityBar } from '../utility_bar'; +import { ExceptionsTableUtilityBar } from './exceptions_table_utility_bar'; import type { AllExceptionListsColumns } from './columns'; import { getAllExceptionListsColumns } from './columns'; import { useAllExceptionLists } from './use_all_exception_lists'; @@ -378,11 +378,8 @@ export const ExceptionListsTable = React.memo(() => { ) : ( <> - diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx new file mode 100644 index 0000000000000..d2bf2b8547f68 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.test.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { TestProviders } from '../../../../../../common/mock'; +import { render, screen, within } from '@testing-library/react'; +import { ExceptionsTableUtilityBar } from './exceptions_table_utility_bar'; + +describe('ExceptionsTableUtilityBar', () => { + it('displays correct exception lists label and refresh rules action button', () => { + const EXCEPTION_LISTS_NUMBER = 25; + render( + + + + ); + + expect(screen.getByTestId('showingExceptionLists')).toBeInTheDocument(); + expect(screen.getByTestId('refreshRulesAction')).toBeInTheDocument(); + expect(screen.getByText(`Showing ${EXCEPTION_LISTS_NUMBER} lists`)).toBeInTheDocument(); + }); + + it('invokes refresh on refresh action click', () => { + const mockRefresh = jest.fn(); + render( + + + + ); + + const buttonWrapper = screen.getByTestId('refreshRulesAction'); + within(buttonWrapper).getByRole('button').click(); + + expect(mockRefresh).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx new file mode 100644 index 0000000000000..062b4b0fef8f9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table_utility_bar.tsx @@ -0,0 +1,51 @@ +/* + * 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 { + UtilityBar, + UtilityBarAction, + UtilityBarGroup, + UtilityBarSection, + UtilityBarText, +} from '../../../../../../common/components/utility_bar'; +import * as i18n from './translations'; + +interface ExceptionsTableUtilityBarProps { + onRefresh?: () => void; + totalExceptionLists: number; +} + +export const ExceptionsTableUtilityBar: React.FC = ({ + onRefresh, + totalExceptionLists, +}) => { + return ( + + + + + {i18n.SHOWING_EXCEPTION_LISTS(totalExceptionLists)} + + + + + {i18n.REFRESH_EXCEPTIONS_TABLE} + + + + + ); +}; + +ExceptionsTableUtilityBar.displayName = 'ExceptionsTableUtilityBar'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts index 004b6c5d97bec..b22d4030384a3 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/translations.ts @@ -28,6 +28,15 @@ export const EXCEPTION_LIST_ACTIONS = i18n.translate( } ); +export const SHOWING_EXCEPTION_LISTS = (totalLists: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.all.exceptions.showingExceptionLists', + { + values: { totalLists }, + defaultMessage: 'Showing {totalLists} {totalLists, plural, =1 {list} other {lists}}', + } + ); + export const RULES_ASSIGNED_TO_TITLE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.all.exceptions.rulesAssignedTitle', { @@ -151,3 +160,10 @@ export const EXCEPTION_LIST_SEARCH_PLACEHOLDER = i18n.translate( defaultMessage: 'e.g. Example List Name', } ); + +export const REFRESH_EXCEPTIONS_TABLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.all.exceptions.refresh', + { + defaultMessage: 'Refresh', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx similarity index 52% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.test.tsx rename to x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx index 91f4a0b06e71d..4fecfc4afa6a2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.test.tsx @@ -9,67 +9,80 @@ import React from 'react'; import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; -import { AllRulesUtilityBar } from './utility_bar'; +import { getShowingRulesParams, RulesTableUtilityBar } from './rules_table_utility_bar'; import { TestProviders } from '../../../../../common/mock'; -describe('AllRules', () => { - it('renders AllRulesUtilityBar total rules and selected rules', () => { +jest.mock('./rules_table/rules_table_context'); + +describe('RulesTableUtilityBar', () => { + it('renders RulesTableUtilityBar total rules and selected rules', () => { const wrapper = mount( - ); - expect(wrapper.find('[data-test-subj="showingRules"]').at(0).text()).toEqual('Showing 4 rules'); + expect(wrapper.find('[data-test-subj="showingRules"]').at(0).text()).toEqual( + 'Showing 1-10 of 21 rules' + ); expect(wrapper.find('[data-test-subj="selectedRules"]').at(0).text()).toEqual( 'Selected 1 rule' ); }); - it('does not render total selected and bulk actions when "hasBulkActions" is false', () => { + it('renders correct pagination label according to pagination data', () => { const wrapper = mount( - ); - - expect(wrapper.find('[data-test-subj="showingRules"]').exists()).toBeFalsy(); - expect(wrapper.find('[data-test-subj="tableBulkActions"]').exists()).toBeFalsy(); - expect(wrapper.find('[data-test-subj="showingExceptionLists"]').at(0).text()).toEqual( - 'Showing 4 lists' + expect(wrapper.find('[data-test-subj="showingRules"]').at(0).text()).toEqual( + 'Showing 1-10 of 21 rules' ); }); it('renders utility actions if user has permissions', () => { const wrapper = mount( - ); @@ -80,15 +93,19 @@ describe('AllRules', () => { it('renders no utility actions if user has no permissions', () => { const wrapper = mount( - ); @@ -100,15 +117,19 @@ describe('AllRules', () => { const mockRefresh = jest.fn(); const wrapper = mount( - ); @@ -122,15 +143,19 @@ describe('AllRules', () => { const mockSwitch = jest.fn(); const wrapper = mount( - ); @@ -146,15 +171,19 @@ describe('AllRules', () => { const mockSwitch = jest.fn(); const wrapper = mount( - ); @@ -165,4 +194,72 @@ describe('AllRules', () => { expect(mockSwitch).not.toHaveBeenCalled(); }); }); + + describe('getShowingRulesParams creates correct label when', () => { + it('there are 0 rules to display', () => { + const pagination = { + page: 1, + perPage: 10, + total: 0, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(0); + expect(lastInPage).toEqual(0); + }); + + it('there is 1 rule to display', () => { + const pagination = { + page: 1, + perPage: 10, + total: 1, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(1); + expect(lastInPage).toEqual(1); + }); + + it('the table displays the first page, and rules per page is less than total rules', () => { + const pagination = { + page: 1, + perPage: 10, + total: 21, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(1); + expect(lastInPage).toEqual(10); + }); + + it('the table displays the first page, and rules per page is greater than total rules', () => { + const pagination = { + page: 1, + perPage: 10, + total: 8, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(1); + expect(lastInPage).toEqual(8); + }); + + it('the table displays the second page, and rules per page is less than total rules', () => { + const pagination = { + page: 2, + perPage: 10, + total: 31, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(11); + expect(lastInPage).toEqual(20); + }); + + it('the table displays the last page, displaying the remaining rules', () => { + const pagination = { + page: 2, + perPage: 100, + total: 101, + }; + const [firstInPage, lastInPage] = getShowingRulesParams(pagination); + expect(firstInPage).toEqual(101); + expect(lastInPage).toEqual(101); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx similarity index 58% rename from x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.tsx rename to x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx index 4809a44528e2a..7f9b0dba04881 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/utility_bar.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_utility_bar.tsx @@ -25,25 +25,31 @@ import { } from '../../../../../common/components/utility_bar'; import * as i18n from '../translations'; import { useKibana } from '../../../../../common/lib/kibana'; -import { useRulesTableContextOptional } from './rules_table/rules_table_context'; +import { useRulesTableContext } from './rules_table/rules_table_context'; +import type { PaginationOptions } from '../../../../containers/detection_engine/rules/types'; -interface AllRulesUtilityBarProps { +export const getShowingRulesParams = ({ page, perPage, total: totalRules }: PaginationOptions) => { + const firstInPage = totalRules === 0 ? 0 : (page - 1) * perPage + 1; + const lastInPage = page * perPage > totalRules ? totalRules : page * perPage; + + return [firstInPage, lastInPage, totalRules] as const; +}; + +interface RulesTableUtilityBarProps { canBulkEdit: boolean; isAllSelected?: boolean; isAutoRefreshOn?: boolean; numberSelectedItems: number; onGetBulkItemsPopoverContent?: (closePopover: () => void) => EuiContextMenuPanelDescriptor[]; - onRefresh?: () => void; - onRefreshSwitch?: (checked: boolean) => void; - onToggleSelectAll?: () => void; - paginationTotal: number; - hasBulkActions: boolean; - hasPagination?: boolean; + onRefresh: () => void; + onRefreshSwitch: (checked: boolean) => void; + onToggleSelectAll: () => void; + pagination: PaginationOptions; isBulkActionInProgress?: boolean; hasDisabledActions?: boolean; } -export const AllRulesUtilityBar = React.memo( +export const RulesTableUtilityBar = React.memo( ({ canBulkEdit, isAllSelected, @@ -53,14 +59,12 @@ export const AllRulesUtilityBar = React.memo( onRefresh, onRefreshSwitch, onToggleSelectAll, - paginationTotal, - hasBulkActions = true, - hasPagination, + pagination, isBulkActionInProgress, hasDisabledActions, }) => { const { timelines } = useKibana().services; - const rulesTableContext = useRulesTableContextOptional(); + const rulesTableContext = useRulesTableContext(); const isAnyRuleSelected = numberSelectedItems > 0; const handleGetBulkItemsPopoverContent = useCallback( @@ -125,73 +129,44 @@ export const AllRulesUtilityBar = React.memo( - {hasBulkActions ? ( - - {i18n.SHOWING_RULES(paginationTotal)} - - ) : ( - - {i18n.SHOWING_EXCEPTION_LISTS(paginationTotal)} - - )} + + {i18n.SHOWING_RULES(...getShowingRulesParams(pagination))} + + <> + + + {i18n.SELECTED_RULES(numberSelectedItems)} + - {hasBulkActions ? ( - <> - - - {i18n.SELECTED_RULES(numberSelectedItems)} - - - {canBulkEdit && onToggleSelectAll && hasPagination && ( - - {isAllSelected ? i18n.CLEAR_SELECTION : i18n.SELECT_ALL_RULES(paginationTotal)} - - )} - - {canBulkEdit && ( - - {i18n.BATCH_ACTIONS} - - )} - + {canBulkEdit && ( - {i18n.REFRESH} + {isAllSelected ? i18n.CLEAR_SELECTION : i18n.SELECT_ALL_RULES(pagination.total)} + )} + + {canBulkEdit && ( - {i18n.REFRESH_RULE_POPOVER_LABEL} + {i18n.BATCH_ACTIONS} - - - ) : ( - + )} + ( > {i18n.REFRESH} + + {i18n.REFRESH_RULE_POPOVER_LABEL} + - )} + + + + {timelines.getLastUpdated({ + showUpdating: rulesTableContext.state.isFetching, + updatedAt: rulesTableContext.state.lastUpdated, + })} - {rulesTableContext && ( - - {timelines.getLastUpdated({ - showUpdating: rulesTableContext.state.isFetching, - updatedAt: rulesTableContext.state.lastUpdated, - })} - - )} ); } ); -AllRulesUtilityBar.displayName = 'AllRulesUtilityBar'; +RulesTableUtilityBar.displayName = 'RulesTableUtilityBar'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx index 328b9a51b30a3..d04832d2e738c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx @@ -5,8 +5,6 @@ * 2.0. */ -/* eslint-disable complexity */ - import { EuiBasicTable, EuiConfirmModal, @@ -33,7 +31,7 @@ import { showRulesTable } from './helpers'; import { useRulesTableContext } from './rules_table/rules_table_context'; import { useAsyncConfirmation } from './rules_table/use_async_confirmation'; import { RulesTableFilters } from './rules_table_filters/rules_table_filters'; -import { AllRulesUtilityBar } from './utility_bar'; +import { RulesTableUtilityBar } from './rules_table_utility_bar'; import { useBulkActionsDryRun } from './bulk_actions/use_bulk_actions_dry_run'; import { useBulkActionsConfirmation } from './bulk_actions/use_bulk_actions_confirmation'; import { useBulkEditFormFlyout } from './bulk_actions/use_bulk_edit_form_flyout'; @@ -147,7 +145,6 @@ export const RulesTables = React.memo( } = useBulkEditFormFlyout(); const selectedItemsCount = isAllSelected ? pagination.total : selectedRuleIds.length; - const hasPagination = pagination.total > pagination.perPage; const { isBulkActionsDryRunLoading, executeBulkActionsDryRun } = useBulkActionsDryRun(); @@ -334,10 +331,9 @@ export const RulesTables = React.memo( )} {shouldShowRulesTable && ( <> - ( onToggleSelectAll={toggleSelectAll} isBulkActionInProgress={isBulkActionsDryRunLoading || loadingRulesAction != null} hasDisabledActions={loadingRulesAction != null} - hasBulkActions /> +export const SHOWING_RULES = (firstInPage: number, lastOfPage: number, totalRules: number) => i18n.translate('xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle', { - values: { totalRules }, - defaultMessage: 'Showing {totalRules} {totalRules, plural, =1 {rule} other {rules}}', + values: { firstInPage, lastOfPage, totalRules }, + defaultMessage: + 'Showing {firstInPage}-{lastOfPage} of {totalRules} {totalRules, plural, =1 {rule} other {rules}}', }); export const SELECT_ALL_RULES = (totalRules: number) => @@ -839,12 +840,6 @@ export const REFRESH_RULE_POPOVER_LABEL = i18n.translate( } ); -export const SHOWING_EXCEPTION_LISTS = (totalLists: number) => - i18n.translate('xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists', { - values: { totalLists }, - defaultMessage: 'Showing {totalLists} {totalLists, plural, =1 {list} other {lists}}', - }); - /** * Bulk Export */ diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 837a3a17db9ce..f8ae6a357f90a 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -25355,8 +25355,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.gapTooltip": "Durée de l'écart le plus récent dans l'exécution de la règle. Ajustez l'historique des règles ou {seeDocs} pour réduire les écarts.", "xpack.securitySolution.detectionEngine.rules.allRules.selectAllRulesTitle": "Sélection totale de {totalRules} {totalRules, plural, =1 {règle} other {règles}} effectuée", "xpack.securitySolution.detectionEngine.rules.allRules.selectedRulesTitle": "Sélection de {selectedRules} {selectedRules, plural, =1 {règle} other {règles}} effectuée", - "xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists": "Affichage de {totalLists} {totalLists, plural, =1 {liste} other {listes}}", - "xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle": "Affichage de {totalRules} {totalRules, plural, =1 {règle} other {règles}}", "xpack.securitySolution.detectionEngine.rules.create.successfullyCreatedRuleTitle": "{ruleName} a été créé", "xpack.securitySolution.detectionEngine.rules.popoverTooltip.ariaLabel": "Infobulle pour la colonne : {columnName}", "xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton": "Installez {missingRules} {missingRules, plural, =1 {règle prédéfinie} other {règles prédéfinies}} d'Elastic et {missingTimelines} {missingTimelines, plural, =1 {chronologie prédéfinie} other {chronologies prédéfinies}} d'Elastic ", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 26614ab69d1df..7029e1e2ed77d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -25333,8 +25333,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.gapTooltip": "ルール実行の最新のギャップの期間。ルールルックバックを調整するか、ギャップの軽減については{seeDocs}してください。", "xpack.securitySolution.detectionEngine.rules.allRules.selectAllRulesTitle": "すべての{totalRules} {totalRules, plural, other {個のルール}}を選択", "xpack.securitySolution.detectionEngine.rules.allRules.selectedRulesTitle": "{selectedRules} {selectedRules, plural, other {ルール}}を選択しました", - "xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists": "{totalLists} {totalLists, plural, other {件のリスト}}を表示しています。", - "xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle": "{totalRules} {totalRules, plural, other {ルール}}を表示中", "xpack.securitySolution.detectionEngine.rules.create.successfullyCreatedRuleTitle": "{ruleName}が作成されました", "xpack.securitySolution.detectionEngine.rules.popoverTooltip.ariaLabel": "列のツールチップ:{columnName}", "xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton": "{missingRules} Elastic事前構築済み{missingRules, plural, other {ルール}}と{missingTimelines} Elastic事前構築済み{missingTimelines, plural, other {タイムライン}}をインストール ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 413d470fb870e..466249148fec7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25363,8 +25363,6 @@ "xpack.securitySolution.detectionEngine.rules.allRules.columns.gapTooltip": "规则执行中最近缺口的持续时间。调整规则回查或{seeDocs}以缩小缺口。", "xpack.securitySolution.detectionEngine.rules.allRules.selectAllRulesTitle": "选择所有 {totalRules} 个{totalRules, plural, other {规则}}", "xpack.securitySolution.detectionEngine.rules.allRules.selectedRulesTitle": "已选择 {selectedRules} 个{selectedRules, plural, other {规则}}", - "xpack.securitySolution.detectionEngine.rules.allRules.showingExceptionLists": "正在显示 {totalLists} 个{totalLists, plural, other {列表}}", - "xpack.securitySolution.detectionEngine.rules.allRules.showingRulesTitle": "正在显示 {totalRules} 个{totalRules, plural, other {规则}}", "xpack.securitySolution.detectionEngine.rules.create.successfullyCreatedRuleTitle": "{ruleName} 已创建", "xpack.securitySolution.detectionEngine.rules.popoverTooltip.ariaLabel": "列的工具提示:{columnName}", "xpack.securitySolution.detectionEngine.rules.reloadMissingPrePackagedRulesAndTimelinesButton": "安装 {missingRules} 个 Elastic 预构建{missingRules, plural, other {规则}}以及 {missingTimelines} 个 Elastic 预构建{missingTimelines, plural, other {时间线}} ", From 97a9e8d57d25b4e33dfb66cc448cc2315d72273c Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Tue, 23 Aug 2022 13:46:00 +0200 Subject: [PATCH 14/41] Bump a number of the user profile activation attempts from 3 to 10. (#139276) --- .../user_profile/user_profile_service.test.ts | 16 ++++++---------- .../server/user_profile/user_profile_service.ts | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts index 9254a46c0e8c5..53a8dea9ebb1a 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.test.ts @@ -466,21 +466,17 @@ describe('UserProfileService', () => { type: 'accessToken', accessToken: 'some-token', }); - await nextTick(); - jest.runAllTimers(); - - // The first retry. - await nextTick(); - jest.runAllTimers(); - // The second retry. - await nextTick(); - jest.runAllTimers(); + // Re-try 9 more times. + for (const _ of Array.from({ length: 9 })) { + await nextTick(); + jest.runAllTimers(); + } await expect(activatePromise).rejects.toBe(failureReason); expect( mockStartParams.clusterClient.asInternalUser.security.activateUserProfile - ).toHaveBeenCalledTimes(3); + ).toHaveBeenCalledTimes(10); expect( mockStartParams.clusterClient.asInternalUser.security.activateUserProfile ).toHaveBeenCalledWith({ grant_type: 'access_token', access_token: 'some-token' }); diff --git a/x-pack/plugins/security/server/user_profile/user_profile_service.ts b/x-pack/plugins/security/server/user_profile/user_profile_service.ts index 7be2abe07a24a..7abc9e41504fb 100644 --- a/x-pack/plugins/security/server/user_profile/user_profile_service.ts +++ b/x-pack/plugins/security/server/user_profile/user_profile_service.ts @@ -28,7 +28,7 @@ import { getPrintableSessionId } from '../session_management'; import type { UserProfileGrant } from './user_profile_grant'; const KIBANA_DATA_ROOT = 'kibana'; -const ACTIVATION_MAX_RETRIES = 3; +const ACTIVATION_MAX_RETRIES = 10; const ACTIVATION_RETRY_SCALE_DURATION_MS = 150; const MAX_SUGGESTIONS_COUNT = 100; const DEFAULT_SUGGESTIONS_COUNT = 10; From bdbd227bb1c508e68a1857f3e6216c576dd77dee Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 23 Aug 2022 07:53:28 -0400 Subject: [PATCH 15/41] Add 'fork' to child_process hardening tests (#139222) --- test/harden/child_process.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/harden/child_process.js b/test/harden/child_process.js index cd1c54aa5db2d..f15f5aceb39e7 100644 --- a/test/harden/child_process.js +++ b/test/harden/child_process.js @@ -25,10 +25,7 @@ test('test setup ok', (t) => { t.end(); }); -// TODO: fork() has been omitted as it doesn't validate its arguments in -// Node.js 10 and will throw an internal error asynchronously. This is fixed in -// newer versions. See https://github.com/elastic/kibana/issues/59628 -const functions = ['exec', 'execFile', 'spawn', 'execFileSync', 'execSync', 'spawnSync']; +const functions = ['exec', 'execFile', 'fork', 'spawn', 'execFileSync', 'execSync', 'spawnSync']; for (const name of functions) { test(`${name}()`, (t) => { t.throws(() => cp[name](), /argument must be of type string/); From 1a213bd7cea43caee7ac02f2490c357c27544923 Mon Sep 17 00:00:00 2001 From: Matthias Wilhelm Date: Tue, 23 Aug 2022 13:54:59 +0200 Subject: [PATCH 16/41] [Discover] Fix legacy sort saved search stored in dashboard saved objects (#137488) * Refactor and centralize sort functionality --- .../context/context_app_content.tsx | 4 +- .../components/layout/discover_documents.tsx | 5 +-- .../main/hooks/use_discover_state.ts | 4 +- .../main/utils/get_state_defaults.ts | 2 +- .../utils/get_switch_data_view_app_state.ts | 5 ++- .../main/utils/persist_saved_search.ts | 4 +- .../main/utils/update_search_source.ts | 2 +- .../discover_grid/discover_grid.tsx | 4 +- .../components/table_header/helpers.tsx | 1 - .../table_header/table_header.test.tsx | 2 +- .../components/table_header/table_header.tsx | 5 ++- .../table_header/table_header_column.tsx | 2 +- .../doc_table/doc_table_wrapper.tsx | 2 +- .../embeddable/saved_search_embeddable.tsx | 37 +++++++++---------- .../discover/public/embeddable/types.ts | 2 +- .../embeddable/utils/update_search_source.ts | 8 ++-- .../discover/public/utils/get_sharing_data.ts | 2 +- .../sorting}/get_default_sort.test.ts | 0 .../sorting}/get_default_sort.ts | 2 +- .../utils => utils/sorting}/get_sort.test.ts | 36 ++++++++++++++++-- .../utils => utils/sorting}/get_sort.ts | 32 +++++++++++++--- .../get_sort_for_search_source.test.ts | 3 +- .../sorting}/get_sort_for_search_source.ts | 2 +- .../doc_table => utils/sorting}/index.ts | 8 ++-- .../discover/group2/_data_grid_context.ts | 2 + 25 files changed, 111 insertions(+), 65 deletions(-) rename src/plugins/discover/public/{components/doc_table/utils => utils/sorting}/get_default_sort.test.ts (100%) rename src/plugins/discover/public/{components/doc_table/utils => utils/sorting}/get_default_sort.ts (93%) rename src/plugins/discover/public/{components/doc_table/utils => utils/sorting}/get_sort.test.ts (66%) rename src/plugins/discover/public/{components/doc_table/utils => utils/sorting}/get_sort.ts (67%) rename src/plugins/discover/public/{components/doc_table/utils => utils/sorting}/get_sort_for_search_source.test.ts (96%) rename src/plugins/discover/public/{components/doc_table/utils => utils/sorting}/get_sort_for_search_source.ts (96%) rename src/plugins/discover/public/{components/doc_table => utils/sorting}/index.ts (59%) 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 3ba518c4a3df8..7471f15092c3b 100644 --- a/src/plugins/discover/public/application/context/context_app_content.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.tsx @@ -11,6 +11,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiHorizontalRule, EuiText } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; import { SortDirection } from '@kbn/data-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { CONTEXT_STEP_SETTING, DOC_HIDE_TIME_COLUMN_SETTING } from '../../../common'; import { LoadingStatus } from './services/context_query_state'; import { ActionBar } from './components/action_bar/action_bar'; @@ -20,7 +21,6 @@ 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 type { SortPairArr } from '../../components/doc_table/utils/get_sort'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import type { DataTableRecord } from '../../types'; @@ -151,7 +151,7 @@ export function ContextAppContent({ expandedDoc={expandedDoc} isLoading={isAnchorLoading} sampleSize={0} - sort={sort as SortPairArr[]} + sort={sort as SortOrder[]} isSortEnabled={false} showTimeCol={showTimeCol} useNewFieldsApi={useNewFieldsApi} 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 92443cea9f1ae..dfff574659744 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 @@ -15,7 +15,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { DataView } from '@kbn/data-views-plugin/public'; -import { SavedSearch } from '@kbn/saved-search-plugin/public'; +import { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; import { DocViewFilterFn } from '../../../../services/doc_views/doc_views_types'; import { DiscoverGrid } from '../../../../components/discover_grid/discover_grid'; @@ -32,7 +32,6 @@ import { DataDocuments$, DataDocumentsMsg, RecordRawType } from '../../hooks/use 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 { DocumentExplorerCallout } from '../document_explorer_callout'; import { DocumentExplorerUpdateCallout } from '../document_explorer_callout/document_explorer_update_callout'; import { DiscoverTourProvider } from '../../../../components/discover_tour'; @@ -195,7 +194,7 @@ function DiscoverDocumentsComponent({ dataView={dataView} isLoading={isLoading} rows={rows} - sort={(state.sort as SortPairArr[]) || []} + sort={(state.sort as SortOrder[]) || []} sampleSize={sampleSize} searchDescription={savedSearch.description} searchTitle={savedSearch.title} 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 e74454247d5d1..b3aaed0d880db 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 @@ -17,6 +17,7 @@ import { Query, } from '@kbn/es-query'; import { SavedSearch, getSavedSearch } from '@kbn/saved-search-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { getState } from '../services/discover_state'; import { getStateDefaults } from '../utils/get_state_defaults'; import { DiscoverServices } from '../../../build_services'; @@ -32,7 +33,6 @@ import { useSearchSession } from './use_search_session'; import { useDataState } from './use_data_state'; import { FetchStatus } from '../../types'; import { getDataViewAppState } from '../utils/get_switch_data_view_app_state'; -import { SortPairArr } from '../../../components/doc_table/utils/get_sort'; import { DataTableRecord } from '../../../types'; import { restoreStateFromSavedSearch } from '../../../services/saved_searches/restore_from_saved_search'; @@ -217,7 +217,7 @@ export function useDiscoverState({ dataView, nextDataView, state.columns || [], - (state.sort || []) as SortPairArr[], + (state.sort || []) as SortOrder[], config.get(MODIFY_COLUMNS_ON_SWITCH), config.get(SORT_DEFAULT_ORDER_SETTING), state.query diff --git a/src/plugins/discover/public/application/main/utils/get_state_defaults.ts b/src/plugins/discover/public/application/main/utils/get_state_defaults.ts index 5eb863372d90c..f058c473127d4 100644 --- a/src/plugins/discover/public/application/main/utils/get_state_defaults.ts +++ b/src/plugins/discover/public/application/main/utils/get_state_defaults.ts @@ -11,6 +11,7 @@ import { IUiSettingsClient } from '@kbn/core/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { SavedSearch } from '@kbn/saved-search-plugin/public'; +import { getDefaultSort, getSortArray } from '../../../utils/sorting'; import { DEFAULT_COLUMNS_SETTING, DOC_HIDE_TIME_COLUMN_SETTING, @@ -19,7 +20,6 @@ import { } from '../../../../common'; import { AppState } from '../services/discover_state'; -import { getDefaultSort, getSortArray } from '../../../components/doc_table'; import { CHART_HIDDEN_KEY } from '../components/chart/discover_chart'; function getDefaultColumns(savedSearch: SavedSearch, config: IUiSettingsClient) { diff --git a/src/plugins/discover/public/application/main/utils/get_switch_data_view_app_state.ts b/src/plugins/discover/public/application/main/utils/get_switch_data_view_app_state.ts index 6ed489e504231..064fe36d974ec 100644 --- a/src/plugins/discover/public/application/main/utils/get_switch_data_view_app_state.ts +++ b/src/plugins/discover/public/application/main/utils/get_switch_data_view_app_state.ts @@ -7,7 +7,8 @@ */ import { isOfAggregateQueryType, Query, AggregateQuery } from '@kbn/es-query'; import type { DataView } from '@kbn/data-views-plugin/public'; -import { getSortArray, SortPairArr } from '../../../components/doc_table/utils/get_sort'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; +import { getSortArray } from '../../../utils/sorting'; /** * Helper function to remove or adapt the currently selected columns/sort to be valid with the next @@ -17,7 +18,7 @@ export function getDataViewAppState( currentDataView: DataView, nextDataView: DataView, currentColumns: string[], - currentSort: SortPairArr[], + currentSort: SortOrder[], modifyColumns: boolean = true, sortDirection: string = 'desc', query?: Query | AggregateQuery diff --git a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts index 434514721faab..488f9598aaae7 100644 --- a/src/plugins/discover/public/application/main/utils/persist_saved_search.ts +++ b/src/plugins/discover/public/application/main/utils/persist_saved_search.ts @@ -8,9 +8,7 @@ import { isOfAggregateQueryType } from '@kbn/es-query'; import { DataView } from '@kbn/data-views-plugin/public'; import { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public'; -import { SavedSearch } from '@kbn/saved-search-plugin/public'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { saveSavedSearch } from '@kbn/saved-search-plugin/public'; +import { SavedSearch, SortOrder, saveSavedSearch } from '@kbn/saved-search-plugin/public'; import { updateSearchSource } from './update_search_source'; import { AppState } from '../services/discover_state'; import { DiscoverServices } from '../../../build_services'; diff --git a/src/plugins/discover/public/application/main/utils/update_search_source.ts b/src/plugins/discover/public/application/main/utils/update_search_source.ts index aea864af91d81..4966a66cf9687 100644 --- a/src/plugins/discover/public/application/main/utils/update_search_source.ts +++ b/src/plugins/discover/public/application/main/utils/update_search_source.ts @@ -11,7 +11,7 @@ import { DataViewType, DataView } from '@kbn/data-views-plugin/public'; import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { SORT_DEFAULT_ORDER_SETTING } from '../../../../common'; import { DiscoverServices } from '../../../build_services'; -import { getSortForSearchSource } from '../../../components/doc_table'; +import { getSortForSearchSource } from '../../../utils/sorting'; /** * Helper function to update the given searchSource before fetching/sharing/persisting 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 d02529d924e3f..1987542931676 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid.tsx @@ -23,6 +23,7 @@ import { EuiLink, } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { DocViewFilterFn } from '../../services/doc_views/doc_views_types'; import { getSchemaDetectors } from './discover_grid_schema'; import { DiscoverGridFlyout } from './discover_grid_flyout'; @@ -43,7 +44,6 @@ import { SHOW_MULTIFIELDS, } from '../../../common'; 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 { DataTableRecord, ValueToStringConverter } from '../../types'; import { useRowHeightsOptions } from '../../hooks/use_row_heights_options'; @@ -141,7 +141,7 @@ export interface DiscoverGridProps { /** * Current sort setting */ - sort: SortPairArr[]; + sort: SortOrder[]; /** * How the data is fetched */ diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx index 47b96d266067b..57cdc35bad016 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx @@ -9,7 +9,6 @@ import { i18n } from '@kbn/i18n'; import type { DataView } from '@kbn/data-views-plugin/public'; -export type SortOrder = [string, string]; export interface ColumnProps { name: string; displayName: string; diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx index 2b1937c177e15..78d15870e6353 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { TableHeader } from './table_header'; import { findTestSubject } from '@elastic/eui/lib/test'; -import { SortOrder } from './helpers'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { DOC_HIDE_TIME_COLUMN_SETTING } from '../../../../../common'; import { FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common'; diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx index ac9dc4c8e204f..ef5ca408d2bd8 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx @@ -9,9 +9,10 @@ import React, { useMemo } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; import { FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { TableHeaderColumn } from './table_header_column'; -import { SortOrder, getDisplayedColumns } from './helpers'; -import { getDefaultSort } from '../../utils/get_default_sort'; +import { getDisplayedColumns } from './helpers'; +import { getDefaultSort } from '../../../../utils/sorting'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../../../common'; diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx index 80a1aee5e920f..f7322b778a558 100644 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx +++ b/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButtonIcon, EuiToolTip, EuiIconTip } from '@elastic/eui'; -import { SortOrder } from './helpers'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { DocViewTableScoreSortWarning } from './score_sort_warning'; interface Props { 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 c7036deaff50b..23f8b3e2e888b 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 @@ -9,10 +9,10 @@ import React, { forwardRef, useCallback, useMemo } from 'react'; import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui'; import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; 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 { TableRow } from './components/table_row'; import { DocViewFilterFn } from '../../services/doc_views/doc_views_types'; import { getFieldsToShow } from '../../utils/get_fields_to_show'; diff --git a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx index b4c3f41e4ba36..fc9afe946fae0 100644 --- a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx @@ -22,6 +22,7 @@ import { I18nProvider } from '@kbn/i18n-react'; import type { KibanaExecutionContext } from '@kbn/core/public'; import { Container, Embeddable, FilterableEmbeddable } from '@kbn/embeddable-plugin/public'; import { Adapters, RequestAdapter } from '@kbn/inspector-plugin/common'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { APPLY_FILTER_TRIGGER, FilterManager, @@ -33,6 +34,7 @@ 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 { SavedSearch } from '@kbn/saved-search-plugin/public'; +import { getSortForEmbeddable, SortPair } from '../utils/sorting'; import { RecordRawType } from '../application/main/hooks/use_saved_search'; import { buildDataTableRecord } from '../utils/build_data_record'; import { DataTableRecord, EsHitRecord } from '../types'; @@ -53,8 +55,6 @@ import { handleSourceColumnState } from '../utils/state_helpers'; import { DiscoverGridProps } from '../components/discover_grid/discover_grid'; import { DiscoverGridSettings } from '../components/discover_grid/types'; import { DocTableProps } from '../components/doc_table/doc_table_wrapper'; -import { getDefaultSort } from '../components/doc_table'; -import { SortOrder } from '../components/doc_table/components/table_header/helpers'; import { VIEW_MODE } from '../components/view_mode_toggle'; import { updateSearchSource } from './utils/update_search_source'; import { FieldStatisticsTable } from '../application/main/components/field_stats_table'; @@ -103,6 +103,7 @@ export class SavedSearchEmbeddable private prevTimeRange?: TimeRange; private prevFilters?: Filter[]; private prevQuery?: Query; + private prevSort?: SortOrder[]; private prevSearchSessionId?: string; private searchProps?: SearchProps; @@ -285,10 +286,8 @@ export class SavedSearchEmbeddable } }; - private getDefaultSort(dataView?: DataView) { - const defaultSortOrder = this.services.uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'); - const hidingTimeColumn = this.services.uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false); - return getDefaultSort(dataView, defaultSortOrder, hidingTimeColumn); + private getSort(sort: SortPair[] | undefined, dataView?: DataView) { + return getSortForEmbeddable(sort, dataView, this.services.uiSettings); } private initializeSearchEmbeddableProps() { @@ -299,16 +298,13 @@ export class SavedSearchEmbeddable if (!dataView) { return; } - - if (!this.savedSearch.sort || !this.savedSearch.sort.length) { - this.savedSearch.sort = this.getDefaultSort(dataView); - } + const sort = this.getSort(this.savedSearch.sort, dataView); const props: SearchProps = { columns: this.savedSearch.columns, dataView, isLoading: false, - sort: this.getDefaultSort(dataView), + sort, rows: [], searchDescription: this.savedSearch.description, description: this.savedSearch.description, @@ -339,9 +335,9 @@ export class SavedSearchEmbeddable onSetColumns: (columns: string[]) => { this.updateInput({ columns }); }, - onSort: (sort: string[][]) => { + onSort: (nextSort: string[][]) => { const sortOrderArr: SortOrder[] = []; - sort.forEach((arr) => { + nextSort.forEach((arr) => { sortOrderArr.push(arr as SortOrder); }); this.updateInput({ sort: sortOrderArr }); @@ -400,14 +396,15 @@ export class SavedSearchEmbeddable } private isFetchRequired(searchProps?: SearchProps) { - if (!searchProps) { + if (!searchProps || !searchProps.dataView) { 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) || + !isEqual(this.prevSort, this.input.sort) || this.prevSearchSessionId !== this.input.searchSessionId ); } @@ -431,12 +428,11 @@ export class SavedSearchEmbeddable { columns: this.input.columns || this.savedSearch.columns }, this.services.core.uiSettings ).columns; + searchProps.sort = this.getSort( + this.input.sort || this.savedSearch.sort, + searchProps?.dataView + ); - const savedSearchSort = - this.savedSearch.sort && this.savedSearch.sort.length - ? this.savedSearch.sort - : this.getDefaultSort(this.searchProps?.dataView); - searchProps.sort = this.input.sort || savedSearchSort; searchProps.sharedItemTitle = this.panelTitle; searchProps.rowHeightState = this.input.rowHeight || this.savedSearch.rowHeight; searchProps.rowsPerPageState = this.input.rowsPerPage || this.savedSearch.rowsPerPage; @@ -453,6 +449,7 @@ export class SavedSearchEmbeddable this.prevQuery = this.input.query; this.prevTimeRange = this.input.timeRange; this.prevSearchSessionId = this.input.searchSessionId; + this.prevSort = this.input.sort; this.searchProps = searchProps; await this.fetch(); } else if (this.searchProps && this.node) { diff --git a/src/plugins/discover/public/embeddable/types.ts b/src/plugins/discover/public/embeddable/types.ts index dacb9b7d81d43..6038aa5a0625c 100644 --- a/src/plugins/discover/public/embeddable/types.ts +++ b/src/plugins/discover/public/embeddable/types.ts @@ -15,7 +15,7 @@ import { import type { Filter, TimeRange, Query } from '@kbn/es-query'; import { DataView } from '@kbn/data-views-plugin/public'; import { SavedSearch } from '@kbn/saved-search-plugin/public'; -import { SortOrder } from '../components/doc_table/components/table_header/helpers'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; export interface SearchInput extends EmbeddableInput { timeRange: TimeRange; diff --git a/src/plugins/discover/public/embeddable/utils/update_search_source.ts b/src/plugins/discover/public/embeddable/utils/update_search_source.ts index 0126ed4d021e6..87ee137aed796 100644 --- a/src/plugins/discover/public/embeddable/utils/update_search_source.ts +++ b/src/plugins/discover/public/embeddable/utils/update_search_source.ts @@ -6,14 +6,14 @@ * Side Public License, v 1. */ import type { DataView } from '@kbn/data-views-plugin/public'; -import { ISearchSource } from '@kbn/data-plugin/public'; -import { getSortForSearchSource } from '../../components/doc_table'; -import { SortPairArr } from '../../components/doc_table/utils/get_sort'; +import type { ISearchSource } from '@kbn/data-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; +import { getSortForSearchSource } from '../../utils/sorting'; export const updateSearchSource = ( searchSource: ISearchSource, dataView: DataView | undefined, - sort: (SortPairArr[] & string[][]) | undefined, + sort: (SortOrder[] & string[][]) | undefined, useNewFieldsApi: boolean, defaults: { sampleSize: number; diff --git a/src/plugins/discover/public/utils/get_sharing_data.ts b/src/plugins/discover/public/utils/get_sharing_data.ts index 6d99edd3d9fe1..ace169359e318 100644 --- a/src/plugins/discover/public/utils/get_sharing_data.ts +++ b/src/plugins/discover/public/utils/get_sharing_data.ts @@ -15,12 +15,12 @@ import type { } from '@kbn/data-plugin/public'; import type { Filter } from '@kbn/es-query'; import type { SavedSearch, SortOrder } from '@kbn/saved-search-plugin/public'; +import { getSortForSearchSource } from './sorting'; import { DOC_HIDE_TIME_COLUMN_SETTING, SEARCH_FIELDS_FROM_SOURCE, SORT_DEFAULT_ORDER_SETTING, } from '../../common'; -import { getSortForSearchSource } from '../components/doc_table'; import { AppState, isEqualFilters } from '../application/main/services/discover_state'; /** diff --git a/src/plugins/discover/public/components/doc_table/utils/get_default_sort.test.ts b/src/plugins/discover/public/utils/sorting/get_default_sort.test.ts similarity index 100% rename from src/plugins/discover/public/components/doc_table/utils/get_default_sort.test.ts rename to src/plugins/discover/public/utils/sorting/get_default_sort.test.ts diff --git a/src/plugins/discover/public/components/doc_table/utils/get_default_sort.ts b/src/plugins/discover/public/utils/sorting/get_default_sort.ts similarity index 93% rename from src/plugins/discover/public/components/doc_table/utils/get_default_sort.ts rename to src/plugins/discover/public/utils/sorting/get_default_sort.ts index 82055e94f5407..d5b72c4b13949 100644 --- a/src/plugins/discover/public/components/doc_table/utils/get_default_sort.ts +++ b/src/plugins/discover/public/utils/sorting/get_default_sort.ts @@ -7,8 +7,8 @@ */ import type { DataView } from '@kbn/data-views-plugin/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { isSortable } from './get_sort'; -import { SortOrder } from '../components/table_header/helpers'; /** * use in case the user didn't manually sort. diff --git a/src/plugins/discover/public/components/doc_table/utils/get_sort.test.ts b/src/plugins/discover/public/utils/sorting/get_sort.test.ts similarity index 66% rename from src/plugins/discover/public/components/doc_table/utils/get_sort.test.ts rename to src/plugins/discover/public/utils/sorting/get_sort.test.ts index f778bbd8fecaa..0656a2e36c4ca 100644 --- a/src/plugins/discover/public/components/doc_table/utils/get_sort.test.ts +++ b/src/plugins/discover/public/utils/sorting/get_sort.test.ts @@ -6,11 +6,12 @@ * Side Public License, v 1. */ -import { getSort, getSortArray } from './get_sort'; +import { getSort, getSortArray, getSortForEmbeddable } from './get_sort'; import { stubDataView, stubDataViewWithoutTimeField, } from '@kbn/data-views-plugin/common/data_view.stub'; +import { uiSettingsMock } from '../../__mocks__/ui_settings'; describe('docTable', function () { describe('getSort function', function () { @@ -47,7 +48,6 @@ describe('docTable', function () { expect(getSort(['foo', 'asc'], stubDataView)).toEqual([{ foo: 'asc' }]); }); }); - describe('getSortArray function', function () { test('should have an array method', function () { expect(getSortArray).toBeInstanceOf(Function); @@ -64,14 +64,42 @@ describe('docTable', function () { test('should sort by an empty array when an unsortable field is given', function () { expect(getSortArray([{ 'non-sortable': 'asc' }], stubDataView)).toEqual([]); expect(getSortArray([{ lol_nope: 'asc' }], stubDataView)).toEqual([]); - expect(getSortArray([{ 'non-sortable': 'asc' }], stubDataViewWithoutTimeField)).toEqual([]); }); test('should return an empty array when passed an empty sort array', () => { expect(getSortArray([], stubDataView)).toEqual([]); - expect(getSortArray([], stubDataViewWithoutTimeField)).toEqual([]); }); }); + describe('getSortForEmbeddable function', function () { + test('should return an array of arrays for sortable fields', function () { + expect(getSortForEmbeddable([['bytes', 'desc']], stubDataView)).toEqual([['bytes', 'desc']]); + }); + + test('should return an array of arrays from an array of elasticsearch sort objects', function () { + expect(getSortForEmbeddable([{ bytes: 'desc' }], stubDataView)).toEqual([['bytes', 'desc']]); + }); + + test('should sort by an empty array when an unsortable field is given', function () { + expect(getSortForEmbeddable([{ 'non-sortable': 'asc' }], stubDataView)).toEqual([]); + expect(getSortForEmbeddable([{ lol_nope: 'asc' }], stubDataView)).toEqual([]); + expect( + getSortForEmbeddable([{ 'non-sortable': 'asc' }], stubDataViewWithoutTimeField) + ).toEqual([]); + }); + + test('should return an empty array when passed an empty sort array', () => { + expect(getSortForEmbeddable([], stubDataView)).toEqual([]); + expect(getSortForEmbeddable([], stubDataViewWithoutTimeField)).toEqual([]); + }); + + test('should provide fallback results', () => { + expect(getSortForEmbeddable(undefined)).toEqual([]); + expect(getSortForEmbeddable(undefined, stubDataView)).toEqual([]); + expect(getSortForEmbeddable(undefined, stubDataView, uiSettingsMock)).toEqual([ + ['@timestamp', 'desc'], + ]); + }); + }); }); diff --git a/src/plugins/discover/public/components/doc_table/utils/get_sort.ts b/src/plugins/discover/public/utils/sorting/get_sort.ts similarity index 67% rename from src/plugins/discover/public/components/doc_table/utils/get_sort.ts rename to src/plugins/discover/public/utils/sorting/get_sort.ts index 31d4375a5f266..59d414d8e1eea 100644 --- a/src/plugins/discover/public/components/doc_table/utils/get_sort.ts +++ b/src/plugins/discover/public/utils/sorting/get_sort.ts @@ -8,10 +8,13 @@ import { isPlainObject } from 'lodash'; import { DataView } from '@kbn/data-views-plugin/public'; +import { IUiSettingsClient } from '@kbn/core/public'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; +import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '../../../common'; +import { getDefaultSort } from './get_default_sort'; export type SortPairObj = Record; -export type SortPairArr = [string, string]; -export type SortPair = SortPairArr | SortPairObj; +export type SortPair = SortOrder | SortPairObj; export type SortInput = SortPair | SortPair[]; export function isSortable(fieldName: string, dataView: DataView): boolean { @@ -25,7 +28,7 @@ function createSortObject(sortPair: SortInput, dataView: DataView): SortPairObj sortPair.length === 2 && isSortable(String(sortPair[0]), dataView) ) { - const [field, direction] = sortPair as SortPairArr; + const [field, direction] = sortPair as SortOrder; return { [field]: direction }; } else if (isPlainObject(sortPair) && isSortable(Object.keys(sortPair)[0], dataView)) { return sortPair as SortPairObj; @@ -62,8 +65,8 @@ export function getSort(sort: SortPair[] | SortPair, dataView: DataView): SortPa * compared to getSort it doesn't return an array of objects, it returns an array of arrays * [[fieldToSort: directionToSort]] */ -export function getSortArray(sort: SortPair[], dataView: DataView): SortPairArr[] { - return getSort(sort, dataView).reduce((acc: SortPairArr[], sortPair) => { +export function getSortArray(sort: SortInput, dataView: DataView): SortOrder[] { + return getSort(sort, dataView).reduce((acc: SortOrder[], sortPair) => { const entries = Object.entries(sortPair); if (entries && entries[0]) { acc.push(entries[0]); @@ -71,3 +74,22 @@ export function getSortArray(sort: SortPair[], dataView: DataView): SortPairArr[ return acc; }, []); } + +/** + * sorting for embeddable, like getSortArray,but returning a default in the case the given sort or dataView is not valid + */ +export function getSortForEmbeddable( + sort?: SortInput, + dataView?: DataView, + uiSettings?: IUiSettingsClient +): SortOrder[] { + if (!sort || !sort.length || !dataView) { + if (!uiSettings) { + return []; + } + const defaultSortOrder = uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'); + const hidingTimeColumn = uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false); + return getDefaultSort(dataView, defaultSortOrder, hidingTimeColumn); + } + return getSortArray(sort, dataView); +} diff --git a/src/plugins/discover/public/components/doc_table/utils/get_sort_for_search_source.test.ts b/src/plugins/discover/public/utils/sorting/get_sort_for_search_source.test.ts similarity index 96% rename from src/plugins/discover/public/components/doc_table/utils/get_sort_for_search_source.test.ts rename to src/plugins/discover/public/utils/sorting/get_sort_for_search_source.test.ts index 729d74cb710fa..dd54b5d2a70a2 100644 --- a/src/plugins/discover/public/components/doc_table/utils/get_sort_for_search_source.test.ts +++ b/src/plugins/discover/public/utils/sorting/get_sort_for_search_source.test.ts @@ -5,9 +5,8 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { getSortForSearchSource } from './get_sort_for_search_source'; -import { SortOrder } from '../components/table_header/helpers'; import { stubDataView, stubDataViewWithoutTimeField } from '@kbn/data-plugin/common/stubs'; describe('getSortForSearchSource function', function () { diff --git a/src/plugins/discover/public/components/doc_table/utils/get_sort_for_search_source.ts b/src/plugins/discover/public/utils/sorting/get_sort_for_search_source.ts similarity index 96% rename from src/plugins/discover/public/components/doc_table/utils/get_sort_for_search_source.ts rename to src/plugins/discover/public/utils/sorting/get_sort_for_search_source.ts index c3f8badc0a536..bcf0ccf4d0e30 100644 --- a/src/plugins/discover/public/components/doc_table/utils/get_sort_for_search_source.ts +++ b/src/plugins/discover/public/utils/sorting/get_sort_for_search_source.ts @@ -8,7 +8,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import type { EsQuerySortValue } from '@kbn/data-plugin/public'; -import { SortOrder } from '../components/table_header/helpers'; +import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { getSort } from './get_sort'; /** diff --git a/src/plugins/discover/public/components/doc_table/index.ts b/src/plugins/discover/public/utils/sorting/index.ts similarity index 59% rename from src/plugins/discover/public/components/doc_table/index.ts rename to src/plugins/discover/public/utils/sorting/index.ts index e79276b0c9687..1d7f3ce6d671a 100644 --- a/src/plugins/discover/public/components/doc_table/index.ts +++ b/src/plugins/discover/public/utils/sorting/index.ts @@ -5,7 +5,7 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - -export { getSort, getSortArray } from './utils/get_sort'; -export { getSortForSearchSource } from './utils/get_sort_for_search_source'; -export { getDefaultSort } from './utils/get_default_sort'; +export { getSort, getSortArray, getSortForEmbeddable } from './get_sort'; +export { getSortForSearchSource } from './get_sort_for_search_source'; +export { getDefaultSort } from './get_default_sort'; +export type { SortPair } from './get_sort'; diff --git a/test/functional/apps/discover/group2/_data_grid_context.ts b/test/functional/apps/discover/group2/_data_grid_context.ts index 549e02f60137f..4903cd446dfc9 100644 --- a/test/functional/apps/discover/group2/_data_grid_context.ts +++ b/test/functional/apps/discover/group2/_data_grid_context.ts @@ -16,6 +16,7 @@ const TEST_FILTER_COLUMN_NAMES = [ ]; export default function ({ getService, getPageObjects }: FtrProviderContext) { + const log = getService('log'); const retry = getService('retry'); const filterBar = getService('filterBar'); const dataGrid = getService('dataGrid'); @@ -114,6 +115,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await retry.waitFor('document table has a length of 6', async () => { const nrOfDocs = (await dataGrid.getBodyRows()).length; + log.debug('document table length', nrOfDocs); return nrOfDocs === 6; }); }); From 081e2d7e30fd1f9dc6729e6570336055fbca0449 Mon Sep 17 00:00:00 2001 From: Sander Philipse <94373878+sphilipse@users.noreply.github.com> Date: Tue, 23 Aug 2022 14:39:29 +0200 Subject: [PATCH 17/41] [Enterprise Search] Align actions according to table defaults (#139284) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Enterprise Search] Align actions according to table defaults * Fix i18n and adjust column width * Update x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.ts Co-authored-by: Efe Gürkan YALAMAN Co-authored-by: Efe Gürkan YALAMAN --- .../search_indices/delete_index_modal.tsx | 33 ++++------- .../search_indices/indices_logic.test.ts | 12 ++-- .../search_indices/indices_logic.ts | 26 ++++++--- .../search_indices/indices_table.tsx | 55 +++++++++---------- 4 files changed, 63 insertions(+), 63 deletions(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/delete_index_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/delete_index_modal.tsx index 99f0e35c352e1..6dbb44d658b8c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/delete_index_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/delete_index_modal.tsx @@ -12,15 +12,22 @@ import { useActions, useValues } from 'kea'; import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { ingestionMethodToText } from '../../utils/indices'; + import { IndicesLogic } from './indices_logic'; export const DeleteIndexModal: React.FC = () => { const { closeDeleteModal, deleteIndex } = useActions(IndicesLogic); - const { deleteModalIndexName: indexName, isDeleteModalVisible } = useValues(IndicesLogic); + const { + deleteModalIndexName: indexName, + deleteModalIngestionMethod: ingestionMethod, + isDeleteModalVisible, + } = useValues(IndicesLogic); return isDeleteModalVisible ? ( { closeDeleteModal(); @@ -48,31 +55,13 @@ export const DeleteIndexModal: React.FC = () => { 'xpack.enterpriseSearch.content.searchIndices.deleteModal.delete.description', { defaultMessage: - 'You are about to delete the index {indexName}. This will also delete any associated connector documents or crawlers.', + 'Deleting this index will also delete all of its data and its {ingestionMethod} configuration. Any associated search engines will no longer be able to access any data stored in this index.This can not be undone.', values: { - indexName, + ingestionMethod: ingestionMethodToText(ingestionMethod), }, } )}

-

- {i18n.translate( - 'xpack.enterpriseSearch.content.searchIndices.deleteModal.searchEngine.description', - { - defaultMessage: - 'Any associated search engines will no longer be able to access any data stored in this index.', - } - )} -

-

- {i18n.translate( - 'xpack.enterpriseSearch.content.searchIndices.deleteModal.irrevokable.description', - { - defaultMessage: - "You can't recover a deleted index, connector or crawler configuration. Make sure you have appropriate backups.", - } - )} -

) : ( <> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts index 2574af68ce50c..a636199dd1e47 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.test.ts @@ -22,13 +22,15 @@ import { DEFAULT_META } from '../../../shared/constants'; import { FetchIndicesAPILogic } from '../../api/index/fetch_indices_api_logic'; -import { IngestionStatus } from '../../types'; +import { IngestionMethod, IngestionStatus } from '../../types'; import { IndicesLogic } from './indices_logic'; const DEFAULT_VALUES = { data: undefined, + deleteModalIndex: null, deleteModalIndexName: '', + deleteModalIngestionMethod: IngestionMethod.API, hasNoIndices: false, indices: [], isDeleteModalVisible: false, @@ -76,17 +78,19 @@ describe('IndicesLogic', () => { }); describe('openDeleteModal', () => { it('should set deleteIndexName and set isDeleteModalVisible to true', () => { - IndicesLogic.actions.openDeleteModal('delete'); + IndicesLogic.actions.openDeleteModal(connectorIndex); expect(IndicesLogic.values).toEqual({ ...DEFAULT_VALUES, - deleteModalIndexName: 'delete', + deleteModalIndex: connectorIndex, + deleteModalIndexName: 'connector', + deleteModalIngestionMethod: IngestionMethod.CONNECTOR, isDeleteModalVisible: true, }); }); }); describe('closeDeleteModal', () => { it('should set deleteIndexName to empty and set isDeleteModalVisible to false', () => { - IndicesLogic.actions.openDeleteModal('delete'); + IndicesLogic.actions.openDeleteModal(connectorIndex); IndicesLogic.actions.closeDeleteModal(); expect(IndicesLogic.values).toEqual(DEFAULT_VALUES); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.ts index eb09425c1faca..5b90b26dba002 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_logic.ts @@ -25,8 +25,8 @@ import { DeleteIndexApiLogicArgs, } from '../../api/index/delete_index_api_logic'; import { FetchIndicesAPILogic } from '../../api/index/fetch_indices_api_logic'; -import { ElasticsearchViewIndex } from '../../types'; -import { indexToViewIndex } from '../../utils/indices'; +import { ElasticsearchViewIndex, IngestionMethod } from '../../types'; +import { getIngestionMethod, indexToViewIndex } from '../../utils/indices'; export interface IndicesActions { apiError(error: HttpError): HttpError; @@ -64,12 +64,14 @@ export interface IndicesActions { }): { meta: Meta; returnHiddenIndices: boolean; searchQuery?: string }; makeRequest: typeof FetchIndicesAPILogic.actions.makeRequest; onPaginate(newPageIndex: number): { newPageIndex: number }; - openDeleteModal(indexName: string): { indexName: string }; + openDeleteModal(index: ElasticsearchViewIndex): { index: ElasticsearchViewIndex }; setIsFirstRequest(): void; } export interface IndicesValues { data: typeof FetchIndicesAPILogic.values.data; + deleteModalIndex: ElasticsearchViewIndex | null; deleteModalIndexName: string; + deleteModalIngestionMethod: IngestionMethod; hasNoIndices: boolean; indices: ElasticsearchViewIndex[]; isDeleteModalVisible: boolean; @@ -89,7 +91,7 @@ export const IndicesLogic = kea>({ searchQuery, }), onPaginate: (newPageIndex) => ({ newPageIndex }), - openDeleteModal: (indexName) => ({ indexName }), + openDeleteModal: (index) => ({ index }), setIsFirstRequest: true, }, connect: { @@ -108,7 +110,7 @@ export const IndicesLogic = kea>({ flashSuccessToast( i18n.translate('xpack.enterpriseSearch.content.indices.deleteIndex.successToast.title', { defaultMessage: - 'Your index {indexName} and any associated connectors or crawlers were successfully deleted', + 'Your index {indexName} and any associated ingestion configurations were successfully deleted', values: { indexName: values.deleteModalIndexName, }, @@ -125,11 +127,11 @@ export const IndicesLogic = kea>({ }), path: ['enterprise_search', 'content', 'indices_logic'], reducers: () => ({ - deleteModalIndexName: [ - '', + deleteModalIndex: [ + null, { - closeDeleteModal: () => '', - openDeleteModal: (_, { indexName }) => indexName, + closeDeleteModal: () => null, + openDeleteModal: (_, { index }) => index, }, ], isDeleteModalVisible: [ @@ -163,6 +165,12 @@ export const IndicesLogic = kea>({ ], }), selectors: ({ selectors }) => ({ + deleteModalIndexName: [() => [selectors.deleteModalIndex], (index) => index?.name ?? ''], + deleteModalIngestionMethod: [ + () => [selectors.deleteModalIndex], + (index: ElasticsearchViewIndex | null) => + index ? getIngestionMethod(index) : IngestionMethod.API, + ], hasNoIndices: [ // We need this to show the landing page on the overview page if there are no indices // We can't rely just on there being no indices, because user might have entered a search query diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx index 0462613b247d8..8ff7550b61ffd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/indices_table.tsx @@ -7,11 +7,12 @@ import React from 'react'; +import { useValues } from 'kea'; + import { CriteriaWithPagination, EuiBasicTable, EuiBasicTableColumn, - EuiButtonIcon, EuiIcon, EuiText, } from '@elastic/eui'; @@ -19,7 +20,8 @@ import { i18n } from '@kbn/i18n'; import { Meta } from '../../../../../common/types'; import { generateEncodedPath } from '../../../shared/encode_path_params'; -import { EuiLinkTo, EuiButtonIconTo } from '../../../shared/react_router_helpers'; +import { KibanaLogic } from '../../../shared/kibana'; +import { EuiLinkTo } from '../../../shared/react_router_helpers'; import { EuiBadgeTo } from '../../../shared/react_router_helpers/eui_components'; import { convertMetaToPagination } from '../../../shared/table_pagination'; import { SEARCH_INDEX_PATH } from '../../routes'; @@ -43,7 +45,7 @@ interface IndicesTableProps { isLoading?: boolean; meta: Meta; onChange: (criteria: CriteriaWithPagination) => void; - onDelete: (indexName: string) => void; + onDelete: (index: ElasticsearchViewIndex) => void; } export const IndicesTable: React.FC = ({ @@ -53,6 +55,7 @@ export const IndicesTable: React.FC = ({ onChange, onDelete, }) => { + const { navigateToUrl } = useValues(KibanaLogic); const columns: Array> = [ { field: 'name', @@ -140,42 +143,38 @@ export const IndicesTable: React.FC = ({ } }, truncateText: true, - width: '10%', + width: '15%', }, { actions: [ { - render: ({ name }) => ( - - ), + description: 'View this index', + icon: 'eye', + isPrimary: false, + name: (index) => `View ${index.name}`, + onClick: (index) => + navigateToUrl( + generateEncodedPath(SEARCH_INDEX_PATH, { + indexName: index.name, + }) + ), + type: 'icon', }, { - render: (index) => - // We don't have a way to delete crawlers yet - isCrawlerIndex(index) ? ( - <> - ) : ( - onDelete(index.name)} - /> - ), + available: (index) => !isCrawlerIndex(index), + color: 'danger', + description: 'Delete this index', + icon: 'trash', + isPrimary: false, + name: (index) => `Delete ${index.name}`, + onClick: (index) => onDelete(index), + type: 'icon', }, ], name: i18n.translate('xpack.enterpriseSearch.content.searchIndices.actions.columnTitle', { defaultMessage: 'Actions', }), - width: '5%', + width: '10%', }, ]; return ( From 048e933cb4388060846ba7921b1843794ad0559d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 23 Aug 2022 08:52:43 -0400 Subject: [PATCH 18/41] skip failing test suite (#139295) --- test/functional/apps/console/_comments.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/console/_comments.ts b/test/functional/apps/console/_comments.ts index 783080ac8d45b..9132e0f04b0c8 100644 --- a/test/functional/apps/console/_comments.ts +++ b/test/functional/apps/console/_comments.ts @@ -15,7 +15,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const PageObjects = getPageObjects(['common', 'console', 'header']); - describe('console app', function testComments() { + // Failing: See https://github.com/elastic/kibana/issues/139295 + describe.skip('console app', function testComments() { this.tags('includeFirefox'); before(async () => { log.debug('navigateTo console'); From c5de0a9ff9be8265155bb63d1454daac55828091 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 23 Aug 2022 09:08:59 -0400 Subject: [PATCH 19/41] [Maps] Add ability to disable tooltips for layer (#138275) * Add ability to disable tooltips for layer * Disable Show tooltips switch when no tooltip fields are available * Typo * Review feedback * Fix loop termination --- .../layer_descriptor_types.ts | 1 + .../maps/public/actions/layer_actions.ts | 9 ++++++ .../layers/vector_layer/vector_layer.tsx | 18 ++++++++++++ .../create_layer_descriptor.test.ts | 2 ++ .../security/create_layer_descriptors.test.ts | 9 ++++++ .../edit_layer_panel/layer_settings/index.tsx | 3 ++ .../layer_settings/layer_settings.tsx | 28 +++++++++++++++++++ .../tooltip_control/tooltip_control.test.tsx | 3 ++ .../tooltip_control/tooltip_control.tsx | 8 +++--- 9 files changed, 77 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts index 36325c561b19a..160a34f8bcc0d 100644 --- a/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/layer_descriptor_types.ts @@ -77,6 +77,7 @@ export type VectorLayerDescriptor = LayerDescriptor & { type: LAYER_TYPE.GEOJSON_VECTOR | LAYER_TYPE.MVT_VECTOR | LAYER_TYPE.BLENDED_VECTOR; joins?: JoinDescriptor[]; style: VectorStyleDescriptor; + disableTooltips?: boolean; }; export type HeatmapLayerDescriptor = LayerDescriptor & { diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index 9c2fea2a302d5..7a4377f0bfc27 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -554,6 +554,15 @@ export function updateFittableFlag(id: string, includeInFitToBounds: boolean) { }; } +export function updateDisableTooltips(id: string, disableTooltips: boolean) { + return { + type: UPDATE_LAYER_PROP, + id, + propName: 'disableTooltips', + newValue: disableTooltips, + }; +} + export function setLayerQuery(id: string, query: Query) { return (dispatch: ThunkDispatch) => { dispatch({ diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index 032f2d0384afa..3c78bf954e258 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -98,6 +98,7 @@ export interface IVectorLayer extends ILayer { hasJoins(): boolean; showJoinEditor(): boolean; canShowTooltip(): boolean; + areTooltipsDisabled(): boolean; supportsFeatureEditing(): boolean; getLeftJoinFields(): Promise; addFeature(geometry: Geometry | Position[]): Promise; @@ -115,6 +116,7 @@ export const NO_RESULTS_ICON_AND_TOOLTIPCONTENT = { export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { protected readonly _style: VectorStyle; private readonly _joins: InnerJoin[]; + protected readonly _descriptor: VectorLayerDescriptor; static createDescriptor( options: Partial, @@ -132,6 +134,8 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { layerDescriptor.joins = []; } + layerDescriptor.disableTooltips = options.disableTooltips ?? false; + return layerDescriptor; } @@ -147,6 +151,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { source, }); this._joins = joins; + this._descriptor = AbstractVectorLayer.createDescriptor(layerDescriptor); this._style = new VectorStyle( layerDescriptor.style, source, @@ -932,10 +937,23 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { return allProperties; } + /** + * Check if there are any properties we can display in a tooltip. If `false` the "Show tooltips" switch + * is disabled in Layer settings. + * @returns {boolean} + */ canShowTooltip() { return this.getSource().hasTooltipProperties() || this.getJoins().length > 0; } + /** + * Users can toggle tooltips on hover or click in the Layer settings. Tooltips are enabled by default. + * @returns {boolean} + */ + areTooltipsDisabled(): boolean { + return this._descriptor.disableTooltips ?? false; + } + getFeatureId(feature: Feature): string | number | undefined { throw new Error('Should implement AbstractVectorLayer#getFeatureId'); } diff --git a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/observability/create_layer_descriptor.test.ts b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/observability/create_layer_descriptor.test.ts index 7aaea96a06aed..eff03a29ac99a 100644 --- a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/observability/create_layer_descriptor.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/observability/create_layer_descriptor.test.ts @@ -74,6 +74,7 @@ describe('createLayerDescriptor', () => { label: '[Performance] Duration', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { id: emsWorldLayerId, tooltipProperties: ['name', 'iso2'], @@ -172,6 +173,7 @@ describe('createLayerDescriptor', () => { label: '[Performance] Duration', maxZoom: 24, minZoom: 0, + disableTooltips: false, query: { language: 'kuery', query: 'processor.event:"transaction"', diff --git a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts index 934d5c6eee3ab..2006c3eed6c2a 100644 --- a/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/wizards/solution_layers/security/create_layer_descriptors.test.ts @@ -42,6 +42,7 @@ describe('createLayerDescriptor', () => { label: 'apm-*-transaction* | Source Point', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -118,6 +119,7 @@ describe('createLayerDescriptor', () => { label: 'apm-*-transaction* | Destination point', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -194,6 +196,7 @@ describe('createLayerDescriptor', () => { label: 'apm-*-transaction* | Line', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -259,6 +262,7 @@ describe('createLayerDescriptor', () => { label: 'filebeat-* | Source Point', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -335,6 +339,7 @@ describe('createLayerDescriptor', () => { label: 'filebeat-* | Destination point', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -405,6 +410,7 @@ describe('createLayerDescriptor', () => { label: 'filebeat-* | Line', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -470,6 +476,7 @@ describe('createLayerDescriptor', () => { label: 'traces-apm-opbean-node | Source Point', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -546,6 +553,7 @@ describe('createLayerDescriptor', () => { label: 'traces-apm-opbean-node | Destination point', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, @@ -616,6 +624,7 @@ describe('createLayerDescriptor', () => { label: 'traces-apm-opbean-node | Line', maxZoom: 24, minZoom: 0, + disableTooltips: false, sourceDescriptor: { applyGlobalQuery: true, applyGlobalTime: true, diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/index.tsx b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/index.tsx index 44336a5bbaf56..e2cb962f4dd51 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/index.tsx +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/index.tsx @@ -18,6 +18,7 @@ import { updateLayerAlpha, updateLabelsOnTop, updateFittableFlag, + updateDisableTooltips, } from '../../../actions'; import { Attribution } from '../../../../common/descriptor_types'; @@ -35,6 +36,8 @@ function mapDispatchToProps(dispatch: Dispatch) { dispatch(updateLabelsOnTop(id, areLabelsOnTop)), updateIncludeInFitToBounds: (id: string, includeInFitToBounds: boolean) => dispatch(updateFittableFlag(id, includeInFitToBounds)), + updateDisableTooltips: (id: string, DisableTooltips: boolean) => + dispatch(updateDisableTooltips(id, DisableTooltips)), }; } diff --git a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/layer_settings.tsx b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/layer_settings.tsx index 4ae95b9dc5c48..794064e09d3c6 100644 --- a/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/layer_settings.tsx +++ b/x-pack/plugins/maps/public/connected_components/edit_layer_panel/layer_settings/layer_settings.tsx @@ -24,6 +24,7 @@ import { Attribution } from '../../../../common/descriptor_types'; import { AUTOSELECT_EMS_LOCALE, NO_EMS_LOCALE, MAX_ZOOM } from '../../../../common/constants'; import { AlphaSlider } from '../../../components/alpha_slider'; import { ILayer } from '../../../classes/layers/layer'; +import { isVectorLayer, IVectorLayer } from '../../../classes/layers/vector_layer'; import { AttributionFormRow } from './attribution_form_row'; export interface Props { @@ -37,6 +38,7 @@ export interface Props { updateAlpha: (layerId: string, alpha: number) => void; updateLabelsOnTop: (layerId: string, areLabelsOnTop: boolean) => void; updateIncludeInFitToBounds: (layerId: string, includeInFitToBounds: boolean) => void; + updateDisableTooltips: (layerId: string, disableTooltips: boolean) => void; supportsFitToBounds: boolean; } @@ -68,6 +70,10 @@ export function LayerSettings(props: Props) { props.updateLabelsOnTop(layerId, event.target.checked); }; + const onShowTooltipsChange = (event: EuiSwitchEvent) => { + props.updateDisableTooltips(layerId, !event.target.checked); + }; + const includeInFitToBoundsChange = (event: EuiSwitchEvent) => { props.updateIncludeInFitToBounds(layerId, event.target.checked); }; @@ -162,6 +168,27 @@ export function LayerSettings(props: Props) { ); }; + const renderDisableTooltips = () => { + if (!isVectorLayer(props.layer)) { + return null; + } else { + const layer = props.layer as unknown as IVectorLayer; + return ( + + + + ); + } + }; + const renderShowLocaleSelector = () => { if (!props.layer.supportsLabelLocales()) { return null; @@ -234,6 +261,7 @@ export function LayerSettings(props: Props) { {renderShowLocaleSelector()} {renderIncludeInFitToBounds()} + {renderDisableTooltips()} diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx index 736d7810757c5..cda7a4a2739b5 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.test.tsx @@ -38,6 +38,9 @@ const mockLayer = { canShowTooltip: () => { return true; }, + areTooltipsDisabled: () => { + return false; + }, getMbTooltipLayerIds: () => { return ['foo', 'bar']; }, diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx index 41a69b4d3c065..70def963d01dd 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/tooltip_control/tooltip_control.tsx @@ -178,13 +178,13 @@ export class TooltipControl extends Component { for (let i = 0; i < mbFeatures.length; i++) { const mbFeature = mbFeatures[i]; const layer = this._getLayerByMbLayerId(mbFeature.layer.id); - if (!layer) { - break; + if (!layer || !layer.canShowTooltip() || layer.areTooltipsDisabled()) { + continue; } const featureId = layer.getFeatureId(mbFeature); if (featureId === undefined) { - break; + continue; } const layerId = layer.getId(); let match = false; @@ -192,7 +192,7 @@ export class TooltipControl extends Component { const uniqueFeature = uniqueFeatures[j]; if (featureId === uniqueFeature.id && layerId === uniqueFeature.layerId) { match = true; - break; + continue; } } if (!match) { From a0b506e2dc93e1d9d1eb639d616390090a13fdb4 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Tue, 23 Aug 2022 09:16:44 -0400 Subject: [PATCH 20/41] [Maps] Add UI counters for custom icons (#139240) * Add UI counters for custom icons * Only report events when adding a new custom icon, not when editing an existing icon * Fix jest test --- x-pack/plugins/maps/common/telemetry/index.ts | 1 + .../symbol/custom_icon_modal.test.tsx | 8 ++++++++ .../components/symbol/custom_icon_modal.tsx | 17 +++++++++++++++++ .../routes/map_page/saved_map/saved_map.ts | 7 ++++++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/common/telemetry/index.ts b/x-pack/plugins/maps/common/telemetry/index.ts index c5ca2b05c6b52..6c5941db23d5b 100644 --- a/x-pack/plugins/maps/common/telemetry/index.ts +++ b/x-pack/plugins/maps/common/telemetry/index.ts @@ -6,6 +6,7 @@ */ export { LayerStatsCollector } from './layer_stats_collector'; +export { MapSettingsCollector } from './map_settings_collector'; export type { EMS_BASEMAP_KEYS, JOIN_KEYS, diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.test.tsx index 8e21679405c07..b17eb07756f27 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.test.tsx @@ -10,6 +10,14 @@ import { shallow } from 'enzyme'; import { CustomIconModal } from './custom_icon_modal'; +jest.mock('../../../../../kibana_services', () => ({ + getUsageCollection: () => { + return { + reportUiCounter: () => {}, + }; + }, +})); + const defaultProps = { cutoff: 0.25, onCancel: () => {}, diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.tsx index 9898ac0cd3e93..167672ad536a0 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/symbol/custom_icon_modal.tsx @@ -25,6 +25,7 @@ import { EuiSpacer, EuiToolTip, } from '@elastic/eui'; +import { METRIC_TYPE } from '@kbn/analytics'; import { i18n } from '@kbn/i18n'; import { IconPreview } from './icon_preview'; // @ts-expect-error @@ -32,6 +33,8 @@ import { getCustomIconId } from '../../symbol_utils'; // @ts-expect-error import { ValidatedRange } from '../../../../../components/validated_range'; import { CustomIcon } from '../../../../../../common/descriptor_types'; +import { APP_ID } from '../../../../../../common'; +import { getUsageCollection } from '../../../../../kibana_services'; const strings = { getAdvancedOptionsLabel: () => @@ -314,6 +317,7 @@ export class CustomIconModal extends Component { } public render() { + const usageCollector = getUsageCollection(); const { symbolId, onSave, onCancel, onDelete, title } = this.props; const { label, svg, cutoff, radius, isFileInvalid } = this.state; const isComplete = label.length !== 0 && svg.length !== 0 && !isFileInvalid; @@ -365,6 +369,11 @@ export class CustomIconModal extends Component { { + usageCollector?.reportUiCounter( + APP_ID, + METRIC_TYPE.CLICK, + 'settings_custom_icons_delete' + ); onDelete(symbolId); }} data-test-subj="mapsCustomIconForm-submit" @@ -377,6 +386,14 @@ export class CustomIconModal extends Component { { + if (!onDelete) { + // Only report events when adding a new custom icon, not when editing an existing icon + usageCollector?.reportUiCounter( + APP_ID, + METRIC_TYPE.CLICK, + 'settings_custom_icons_add' + ); + } onSave({ symbolId: symbolId ?? getCustomIconId(), label, svg, cutoff, radius }); }} data-test-subj="mapsCustomIconForm-submit" diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts index 2dd45ff50a2f7..181fe6c56e1ef 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts @@ -52,7 +52,7 @@ import { createBasemapLayerDescriptor } from '../../../classes/layers/create_bas import { whenLicenseInitialized } from '../../../licensed_features'; import { SerializedMapState, SerializedUiState } from './types'; import { setAutoOpenLayerWizardId } from '../../../actions/ui_actions'; -import { LayerStatsCollector } from '../../../../common/telemetry'; +import { LayerStatsCollector, MapSettingsCollector } from '../../../../common/telemetry'; function setMapSettingsFromEncodedState(settings: Partial) { const decodedCustomIcons = settings.customIcons @@ -281,6 +281,8 @@ export class SavedMap { return; } + const mapSettingsStatsCollector = new MapSettingsCollector(this._attributes); + const layerStatsCollector = new LayerStatsCollector(this._attributes); const uiCounterEvents = { @@ -289,6 +291,9 @@ export class SavedMap { resolution: layerStatsCollector.getResolutionCounts(), join: layerStatsCollector.getJoinCounts(), ems_basemap: layerStatsCollector.getBasemapCounts(), + settings: { + custom_icons_count: mapSettingsStatsCollector.getCustomIconsCount(), + }, }; for (const [eventType, eventTypeMetrics] of Object.entries(uiCounterEvents)) { From 8f9bfe17b545805868b1ec01d7e5167b099c4407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Kopyci=C5=84ski?= Date: Tue, 23 Aug 2022 15:24:18 +0200 Subject: [PATCH 21/41] Bump react-hook-form (#139229) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- package.json | 2 +- renovate.json | 11 +++++++++++ yarn.lock | 8 ++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 62e4361441794..c0effd409918a 100644 --- a/package.json +++ b/package.json @@ -521,7 +521,7 @@ "react-fast-compare": "^2.0.4", "react-focus-on": "^3.6.0", "react-grid-layout": "^1.3.4", - "react-hook-form": "^7.30.0", + "react-hook-form": "^7.34.2", "react-intl": "^2.8.0", "react-is": "^17.0.2", "react-markdown": "^6.0.3", diff --git a/renovate.json b/renovate.json index 5668714d4271c..7f60faf4a0a62 100644 --- a/renovate.json +++ b/renovate.json @@ -180,6 +180,17 @@ "matchBaseBranches": ["main"], "labels": ["release_note:skip", "backport:skip", "ci:all-cypress-suites"], "enabled": true + }, + { + "groupName": "react-hook-form", + "packageNames": ["react-hook-form"], + "reviewers": [ + "team:security-asset-management", + "team:uptime" + ], + "matchBaseBranches": ["main"], + "labels": ["release_note:skip", "backport:skip", "ci:all-cypress-suites"], + "enabled": true } ] } diff --git a/yarn.lock b/yarn.lock index 1c92135bf60bc..99870a98f4fa7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23609,10 +23609,10 @@ react-helmet-async@^1.0.7: react-fast-compare "^3.2.0" shallowequal "^1.1.0" -react-hook-form@^7.30.0: - version "7.30.0" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.30.0.tgz#c9e2fd54d3627e43bd94bf38ef549df2e80c1371" - integrity sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ== +react-hook-form@^7.34.2: + version "7.34.2" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.34.2.tgz#9ac6d1a309a7c4aaa369d1269357a70e9e9bf4de" + integrity sha512-1lYWbEqr0GW7HHUjMScXMidGvV0BE2RJV3ap2BL7G0EJirkqpccTaawbsvBO8GZaB3JjCeFBEbnEWI1P8ZoLRQ== react-input-autosize@^3.0.0: version "3.0.0" From 6e5bc57648c46ee8f7d2c59693b0643d6533b1cf Mon Sep 17 00:00:00 2001 From: VSpoon <38534966+VSpoon@users.noreply.github.com> Date: Tue, 23 Aug 2022 06:35:22 -0700 Subject: [PATCH 22/41] Update v3_windows_anomalous_script.json (#139109) Fixed file.Path as it prevents the ML job from running. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Pete Harverson --- .../security_windows/ml/v3_windows_anomalous_script.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_windows/ml/v3_windows_anomalous_script.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_windows/ml/v3_windows_anomalous_script.json index 022695bcf5a7d..af8bd86005dd9 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_windows/ml/v3_windows_anomalous_script.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_windows/ml/v3_windows_anomalous_script.json @@ -21,7 +21,7 @@ "influencers": [ "host.name", "user.name", - "file.Path" + "file.path" ] }, "allow_lazy_open": true, From 84e8e54a6e27b68aebe722448186f8a7a7e4fd3a Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Tue, 23 Aug 2022 15:50:22 +0200 Subject: [PATCH 23/41] Bump undici sub-dependency from v5.5.1 to v5.8.2 (#138877) --- packages/kbn-test/jest_integration_node/jest-preset.js | 7 +++++-- packages/kbn-test/jest_node/jest-preset.js | 7 +++++-- yarn.lock | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/kbn-test/jest_integration_node/jest-preset.js b/packages/kbn-test/jest_integration_node/jest-preset.js index 8f5f433139ab7..ff50c2de40961 100644 --- a/packages/kbn-test/jest_integration_node/jest-preset.js +++ b/packages/kbn-test/jest_integration_node/jest-preset.js @@ -8,10 +8,14 @@ const preset = require('../jest-preset'); +const presetClone = { ...preset }; + +delete presetClone.testEnvironment; // simply redefining as `testEnvironment: 'node'` has some weird side-effects (https://github.com/elastic/kibana/pull/138877) + /** @typedef {import("@jest/types").Config.InitialOptions} JestConfig */ /** @type {JestConfig} */ module.exports = { - ...preset, + ...presetClone, testMatch: ['**/integration_tests**/*.test.{js,mjs,ts,tsx}'], testPathIgnorePatterns: preset.testPathIgnorePatterns.filter( (pattern) => !pattern.includes('integration_tests') @@ -40,7 +44,6 @@ module.exports = { ? [['json', { file: 'jest-integration.json' }]] : ['html', 'text'], - testEnvironment: 'node', snapshotSerializers: [], setupFiles: ['/node_modules/@kbn/test/target_node/jest/setup/babel_polyfill.js'], haste: { diff --git a/packages/kbn-test/jest_node/jest-preset.js b/packages/kbn-test/jest_node/jest-preset.js index 78d20414b9389..a28456e0da1f5 100644 --- a/packages/kbn-test/jest_node/jest-preset.js +++ b/packages/kbn-test/jest_node/jest-preset.js @@ -8,9 +8,12 @@ const preset = require('../jest-preset'); +const presetClone = { ...preset }; + +delete presetClone.testEnvironment; // simply redefining as `testEnvironment: 'node'` has some weird side-effects (https://github.com/elastic/kibana/pull/138877#issuecomment-1222366247) + module.exports = { - ...preset, - testEnvironment: 'node', + ...presetClone, snapshotSerializers: [], setupFiles: ['/node_modules/@kbn/test/target_node/jest/setup/babel_polyfill.js'], haste: { diff --git a/yarn.lock b/yarn.lock index 99870a98f4fa7..2781871209895 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27577,9 +27577,9 @@ undefsafe@^2.0.5: integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== 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== + version "5.8.2" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.2.tgz#071fc8a6a5d24db0ad510ad442f607d9b09d5eec" + integrity sha512-3KLq3pXMS0Y4IELV045fTxqz04Nk9Ms7yfBBHum3yxsTR4XNn+ZCaUbf/mWitgYDAhsplQ0B1G4S5D345lMO3A== unfetch@^4.2.0: version "4.2.0" From 6aa29cbed0da39b6d36be95f830d3bf07ed132ae Mon Sep 17 00:00:00 2001 From: doakalexi <109488926+doakalexi@users.noreply.github.com> Date: Tue, 23 Aug 2022 09:52:44 -0400 Subject: [PATCH 24/41] [ResponseOps][Alerting] Ability to bulk update API keys for alerting rules (#139036) * Adding bulk update api keys * Adding tests --- .../rule_quick_edit_buttons.test.tsx | 86 +++++++++++++++++++ .../components/rule_quick_edit_buttons.tsx | 36 ++++++++ .../rules_list/components/rules_list.tsx | 1 + 3 files changed, 123 insertions(+) create mode 100644 x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.test.tsx diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.test.tsx new file mode 100644 index 0000000000000..37c00fab8b6fa --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.test.tsx @@ -0,0 +1,86 @@ +/* + * 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 React from 'react'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { RuleTableItem } from '../../../../types'; +import { RuleQuickEditButtonsWithApi as RuleQuickEditButtons } from './rule_quick_edit_buttons'; + +jest.mock('../../../../common/lib/kibana', () => ({ + useKibana: jest.fn().mockReturnValue({ + services: { + notifications: { toast: { addDanger: jest.fn() } }, + }, + }), +})); + +describe('rule_quick_edit_buttons', () => { + it('renders buttons', async () => { + const mockRule: RuleTableItem = { + id: '1', + enabled: true, + muteAll: false, + } as RuleTableItem; + + const wrapper = mountWithIntl( + {}} + onActionPerformed={() => {}} + setRulesToDelete={() => {}} + setRulesToUpdateAPIKey={() => {}} + /> + ); + + expect(wrapper.find('[data-test-subj="muteAll"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="unmuteAll"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="enableAll"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="disableAll"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="updateAPIKeys"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="deleteAll"]').exists()).toBeTruthy(); + }); + + it('renders muteAll if rules are all muted', async () => { + const mockRule: RuleTableItem = { + id: '1', + muteAll: true, + } as RuleTableItem; + + const wrapper = mountWithIntl( + {}} + onActionPerformed={() => {}} + setRulesToDelete={() => {}} + setRulesToUpdateAPIKey={() => {}} + /> + ); + + expect(wrapper.find('[data-test-subj="muteAll"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="unmuteAll"]').exists()).toBeTruthy(); + }); + + it('renders enableAll if rules are all disabled', async () => { + const mockRule: RuleTableItem = { + id: '1', + enabled: false, + } as RuleTableItem; + + const wrapper = mountWithIntl( + {}} + onActionPerformed={() => {}} + setRulesToDelete={() => {}} + setRulesToUpdateAPIKey={() => {}} + /> + ); + + expect(wrapper.find('[data-test-subj="enableAll"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="disableAll"]').exists()).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.tsx index 9ecaed9775e68..c6b0a92a91055 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/rule_quick_edit_buttons.tsx @@ -23,6 +23,7 @@ export type ComponentOpts = { onPerformingAction?: () => void; onActionPerformed?: () => void; setRulesToDelete: React.Dispatch>; + setRulesToUpdateAPIKey: React.Dispatch>; } & BulkOperationsComponentOpts; export const RuleQuickEditButtons: React.FunctionComponent = ({ @@ -34,6 +35,7 @@ export const RuleQuickEditButtons: React.FunctionComponent = ({ enableRules, disableRules, setRulesToDelete, + setRulesToUpdateAPIKey, }: ComponentOpts) => { const { notifications: { toasts }, @@ -44,6 +46,7 @@ export const RuleQuickEditButtons: React.FunctionComponent = ({ const [isEnablingRules, setIsEnablingRules] = useState(false); const [isDisablingRules, setIsDisablingRules] = useState(false); const [isDeletingRules, setIsDeletingRules] = useState(false); + const [isUpdatingRuleAPIKeys, setIsUpdatingRuleAPIKeys] = useState(false); const allRulesMuted = selectedItems.every(isRuleMuted); const allRulesDisabled = selectedItems.every(isRuleDisabled); @@ -154,6 +157,26 @@ export const RuleQuickEditButtons: React.FunctionComponent = ({ } } + async function updateAPIKeysClick() { + onPerformingAction(); + setIsUpdatingRuleAPIKeys(true); + try { + setRulesToUpdateAPIKey(selectedItems.map((selected: any) => selected.id)); + } catch (e) { + toasts.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToUpdateRuleAPIKeysMessage', + { + defaultMessage: 'Failed to update API keys for rule(s)', + } + ), + }); + } finally { + setIsUpdatingRuleAPIKeys(false); + onActionPerformed(); + } + } + return ( {!allRulesMuted && ( @@ -216,6 +239,19 @@ export const RuleQuickEditButtons: React.FunctionComponent = ({
)} + + + + + From 284418dc0b598dbb9c228488562251bcc722df5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20C=C3=B4t=C3=A9?= Date: Tue, 23 Aug 2022 10:37:51 -0400 Subject: [PATCH 25/41] Create test configs for Kibana running dedicated processes (#136677) * Create test configs for Kibana running dedicated processes * Fix TS issues * Fix tests relying on backend responses * Only run dedicated task process on spaces_and_security suite group2 * Fix ftr_configs * Use dedicated task runner by default * fix typo * Remove exclusive test suite Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .buildkite/ftr_configs.yml | 1 + .../alerting_api_integration/basic/config.ts | 1 + .../alerting_api_integration/common/config.ts | 3 +++ .../security_and_spaces/group1/config.ts | 1 + .../security_and_spaces/group2/config.ts | 1 + .../config_non_dedicated_task_runner.ts | 19 +++++++++++++++++++ .../group2/tests/actions/config.ts | 1 + .../group2/tests/telemetry/config.ts | 1 + .../spaces_only/config.ts | 1 + .../tests/alerting/monitoring_collection.ts | 10 +++++++--- .../spaces_only_legacy/config.ts | 1 + 11 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index c10bf18e5e917..eb7daad21b0f0 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -117,6 +117,7 @@ enabled: - x-pack/test/alerting_api_integration/basic/config.ts - x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts - x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts + - x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.ts - x-pack/test/alerting_api_integration/spaces_only/config.ts - x-pack/test/api_integration_basic/config.ts - x-pack/test/api_integration/config_security_basic.ts diff --git a/x-pack/test/alerting_api_integration/basic/config.ts b/x-pack/test/alerting_api_integration/basic/config.ts index 1295171510988..576584c05dc33 100644 --- a/x-pack/test/alerting_api_integration/basic/config.ts +++ b/x-pack/test/alerting_api_integration/basic/config.ts @@ -13,4 +13,5 @@ export default createTestConfig('basic', { license: 'basic', ssl: true, enableActionsProxy: false, + useDedicatedTaskRunner: true, }); diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index db51582fb2d9e..80b879534323b 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -26,6 +26,7 @@ interface CreateTestConfigOptions { rejectUnauthorized?: boolean; // legacy emailDomainsAllowed?: string[]; testFiles?: string[]; + useDedicatedTaskRunner: boolean; } // test.not-enabled is specifically not enabled @@ -69,6 +70,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) rejectUnauthorized = true, // legacy emailDomainsAllowed = undefined, testFiles = undefined, + useDedicatedTaskRunner, } = options; return async ({ readConfigFile }: FtrConfigProviderContext) => { @@ -163,6 +165,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) }, kbnTestServer: { ...xPackApiIntegrationTestsConfig.get('kbnTestServer'), + useDedicatedTaskRunner, serverArgs: [ ...xPackApiIntegrationTestsConfig.get('kbnTestServer.serverArgs'), ...(options.publicBaseUrl ? ['--server.publicBaseUrl=https://localhost:5601'] : []), diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts index 9b90a4c18fdf0..f999da061b90b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/config.ts @@ -15,4 +15,5 @@ export default createTestConfig('security_and_spaces', { enableActionsProxy: true, publicBaseUrl: true, testFiles: [require.resolve('./tests')], + useDedicatedTaskRunner: true, }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts index 9b90a4c18fdf0..f999da061b90b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/config.ts @@ -15,4 +15,5 @@ export default createTestConfig('security_and_spaces', { enableActionsProxy: true, publicBaseUrl: true, testFiles: [require.resolve('./tests')], + useDedicatedTaskRunner: true, }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.ts new file mode 100644 index 0000000000000..7aed7501bc012 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/config_non_dedicated_task_runner.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createTestConfig } from '../../common/config'; + +// eslint-disable-next-line import/no-default-export +export default createTestConfig('security_and_spaces', { + disabledPlugins: [], + license: 'trial', + ssl: true, + enableActionsProxy: true, + publicBaseUrl: true, + testFiles: [require.resolve('./tests')], + useDedicatedTaskRunner: false, +}); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/config.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/config.ts index 506d0016af4f6..e6336b7092087 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/config.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/config.ts @@ -15,4 +15,5 @@ export default createTestConfig('security_and_spaces', { enableActionsProxy: true, publicBaseUrl: true, testFiles: [require.resolve('.')], + useDedicatedTaskRunner: true, }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/config.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/config.ts index 506d0016af4f6..e6336b7092087 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/config.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/telemetry/config.ts @@ -15,4 +15,5 @@ export default createTestConfig('security_and_spaces', { enableActionsProxy: true, publicBaseUrl: true, testFiles: [require.resolve('.')], + useDedicatedTaskRunner: true, }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/config.ts b/x-pack/test/alerting_api_integration/spaces_only/config.ts index dcf1c70cf8dca..988a6effd5639 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/config.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/config.ts @@ -18,4 +18,5 @@ export default createTestConfig('spaces_only', { customizeLocalHostSsl: true, preconfiguredAlertHistoryEsIndex: true, emailDomainsAllowed: EmailDomainsAllowed, + useDedicatedTaskRunner: true, }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring_collection.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring_collection.ts index aae8090ed08b3..381607361ec42 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring_collection.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/monitoring_collection.ts @@ -31,8 +31,12 @@ export default function alertingMonitoringCollectionTests({ getService }: FtrPro const es = getService('es'); const log = getService('log'); const retry = getService('retry'); + const dedicatedTaskRunner = getService('dedicatedTaskRunner'); const esTestIndexTool = new ESTestIndexTool(es, retry); const waitForExecutionCount = createWaitForExecutionCount(supertest, Spaces.space1.id); + const backgroundNodeSupertest = dedicatedTaskRunner.enabled + ? dedicatedTaskRunner.getSupertest() + : supertest; describe('monitoring_collection', () => { let endDate: string; @@ -63,7 +67,7 @@ export default function alertingMonitoringCollectionTests({ getService }: FtrPro // so we can't get an accurate count of executions/failures/timeouts but // we can test that they are at least there - const getResponse = await supertest.get(NODE_RULES_MONITORING_COLLECTION_URL); + const getResponse = await backgroundNodeSupertest.get(NODE_RULES_MONITORING_COLLECTION_URL); expect(getResponse.status).to.eql(200); expect(getResponse.body.node_rules.executions).to.greaterThan(0); }); @@ -91,7 +95,7 @@ export default function alertingMonitoringCollectionTests({ getService }: FtrPro // so we can't get an accurate count of executions/failures/timeouts but // we can test that they are at least there - const getResponse = await supertest.get(NODE_RULES_MONITORING_COLLECTION_URL); + const getResponse = await backgroundNodeSupertest.get(NODE_RULES_MONITORING_COLLECTION_URL); expect(getResponse.status).to.eql(200); expect(getResponse.body.node_rules.failures).to.greaterThan(0); }); @@ -142,7 +146,7 @@ export default function alertingMonitoringCollectionTests({ getService }: FtrPro // so we can't get an accurate count of executions/failures/timeouts but // we can test that they are at least there - const getResponse = await supertest.get(NODE_RULES_MONITORING_COLLECTION_URL); + const getResponse = await backgroundNodeSupertest.get(NODE_RULES_MONITORING_COLLECTION_URL); expect(getResponse.status).to.eql(200); expect(getResponse.body.node_rules.timeouts).to.greaterThan(0); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts b/x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts index b322b8dffbf95..0bac779b37795 100644 --- a/x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts +++ b/x-pack/test/alerting_api_integration/spaces_only_legacy/config.ts @@ -16,4 +16,5 @@ export default createTestConfig('spaces_only', { verificationMode: undefined, customizeLocalHostSsl: true, preconfiguredAlertHistoryEsIndex: true, + useDedicatedTaskRunner: true, }); From 4a1e3e32d46adcc7ae6e683c280ef9f789d2933f Mon Sep 17 00:00:00 2001 From: "Joey F. Poon" Date: Tue, 23 Aug 2022 09:41:25 -0500 Subject: [PATCH 26/41] [Security Solution] fix flaky metadata transforms test (#139224) --- .../apis/metadata.ts | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts index 047b21827c5c3..508aa8884fcfe 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts @@ -525,6 +525,8 @@ export default function ({ getService }: FtrProviderContext) { }); describe('get metadata transforms', () => { + const testRegex = /endpoint\.metadata_(united|current)-default-*/; + it('should respond forbidden if no fleet access', async () => { await getService('supertestWithoutAuth') .get(METADATA_TRANSFORMS_STATUS_ROUTE) @@ -541,19 +543,22 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .expect(200); - expect(body.count).to.eql(2); + const transforms = (body.transforms as TransformGetTransformStatsTransformStats[]).filter( + (transform) => + testRegex.test(transform.id) && transform.state === TRANSFORM_STATES.STOPPED + ); + + expect(transforms.length).to.eql(2); - const transforms: TransformGetTransformStatsTransformStats[] = body.transforms.sort( - ( - a: TransformGetTransformStatsTransformStats, - b: TransformGetTransformStatsTransformStats - ) => a.id > b.id + const currentTransform = transforms.find((transform) => + transform.id.startsWith(metadataTransformPrefix) ); + expect(currentTransform).to.be.ok(); - expect(transforms[0].id).to.contain(metadataTransformPrefix); - expect(transforms[0].state).to.eql(TRANSFORM_STATES.STOPPED); - expect(transforms[1].id).to.contain(METADATA_UNITED_TRANSFORM); - expect(transforms[1].state).to.eql(TRANSFORM_STATES.STOPPED); + const unitedTransform = transforms.find((transform) => + transform.id.startsWith(METADATA_UNITED_TRANSFORM) + ); + expect(unitedTransform).to.be.ok(); await startTransform(getService, metadataTransformPrefix); await startTransform(getService, METADATA_UNITED_TRANSFORM); @@ -565,19 +570,22 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .expect(200); - expect(body.count).to.eql(2); + const transforms = (body.transforms as TransformGetTransformStatsTransformStats[]).filter( + (transform) => + testRegex.test(transform.id) && transform.state === TRANSFORM_STATES.STARTED + ); + + expect(transforms.length).to.eql(2); - const transforms: TransformGetTransformStatsTransformStats[] = body.transforms.sort( - ( - a: TransformGetTransformStatsTransformStats, - b: TransformGetTransformStatsTransformStats - ) => a.id > b.id + const currentTransform = transforms.find((transform) => + transform.id.startsWith(metadataTransformPrefix) ); + expect(currentTransform).to.be.ok(); - expect(transforms[0].id).to.contain(metadataTransformPrefix); - expect(transforms[0].state).to.eql(TRANSFORM_STATES.STARTED); - expect(transforms[1].id).to.contain(METADATA_UNITED_TRANSFORM); - expect(transforms[1].state).to.eql(TRANSFORM_STATES.STARTED); + const unitedTransform = transforms.find((transform) => + transform.id.startsWith(METADATA_UNITED_TRANSFORM) + ); + expect(unitedTransform).to.be.ok(); }); }); }); From 201820d71823d7833824b5a22a501c841d042b17 Mon Sep 17 00:00:00 2001 From: nastasha-solomon <79124755+nastasha-solomon@users.noreply.github.com> Date: Tue, 23 Aug 2022 11:12:29 -0400 Subject: [PATCH 27/41] [DOCS] New option for users to run a query pack (#138853) Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com> --- docs/osquery/images/enter-query.png | Bin 58839 -> 187998 bytes docs/osquery/osquery.asciidoc | 70 ++++++++++++++-------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/docs/osquery/images/enter-query.png b/docs/osquery/images/enter-query.png index efcf8fa58a7a8b5f0c8b8dfb60ae2c00270a3923..6043eb36329821658f0c34ea0d9886e94f7b38b5 100644 GIT binary patch literal 187998 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%0A+)VI0scMh z;^`AFt^m{FxMyjEAMpR-pZ|+9{Oy^ezF-#f(c1bY?2p%Zj;ljCW2hA_r}VUdghAe=^8W<`qX8$1 zBTEDw@f^GGjbpPTU3tm}5mR+rJ9m7HP1-0=!`L{2e$xpkj$Xaoo0OAMXFK@YdO+u; zdF)pu`KlQCK!j1X{dH%7+q6Ju5!OiavueoZCzK=2NeE zDVP27C#&rZf#_GreSh56Owo(BcYf^VCer=Vq~DCo-K~A`Q0({&y=;|BZ6Dc5@$x;K z3lLH068-uXG*I5b<{YKmm5KUSZu`vUNkM`BE5QN9J}Ba${Wc!x&~dBCVJY-$tLjUI zpr0_3*`zQ&Lpn64k{I=8^vGhRDS5f_|PE zKe#ORfYl`|Pp8;ubk>)syAED^;yvv~+`uRb8AmcDhY<|_MJ5JM)7U7oOQVaQeX&V%rdxwEKxB6}cEy~hYhA&h z8seQAdC3_!iM@atW`i7^O ziE2}fnA7Aqu&)`p=1o&VMZMzyU`lsxbuly zuTnYc&1Ni*CPaMpnj;V>s<0c*GX`$$R0uIPS|2Mec1TDy#Wy@}*>Mvpe-c|9RN8BD5{QFaY?}DN9)@ic>Kz>sTpCbE5spWPe$)vYTWL->_6F|L<5I}* zqcdx4Imehnk&U)KGWH_fwv&L?U(t1AIo z{b$^empx$oI5_D4xTyzdMi(;^)L}~9QSF8cnh!(%tMJd*1MCtXlxyT&F-^Z%eKW7( z(IUfP%sYhW3UQ0!nb4}IY!30>m!JY9{<=*nE9-lGcABAd_qA2*YKM~g?l2*nod}|r z`B9o1Sdaik-*wbtz%+*J$dOdoLDTKgY&M#*_(UKaI_uK6yW5svra|4VqIqpGm-1OD z9`o_DkhwE&s=LvoMI($-lxbz6um-e!ByE{>1}1bM8FYAFyMMpd^EeSfhGx0WDS4AL z*pZ%{5~Pq$)P|IwJ)y_OFOmaEloa%MB$FUL#O}wv_#FT+QWlx~(3 zFf%%63IUYb&6q`tz!pX4M@Z~sX^bpxLwl@Vw{UT$e7%(3UzYn?>FcB6bLo#)=Q)zk zvYs--RO7!Z=d3wLuDq(*8o$SFgQ1cKn(R0d`lOTngDG1Pb)2IfUp%7@`Kez0OuWA5 z8)J6d1tPknT~H-rG)DGjdQ>IyXE|4lj98A%;j3h4dsCBAFy_`DJmeo36Z>!VevyWk z)S{CD8FW#HnHovXa~mFl!sJs~PvSX&82FRbr3@eM`LKlF8PpB?)|-4b$3)wl$ID{0 z(7q_BsI1r_y(r7hF3*8e;BP0?2y4Ojl|lJD8UIiUhg|W1-QMPM>rFt7-k7>c0y22y z!yWhwx*9U;8@t-wZzt1Dn8w87r+~cX43*vFXF?hC@W9ZS87zvkKGS(Yy?^bZ0>5xR}oMR z0^Ys{Kq(2ipID%7UinA)_cU-~%Vy2Yi-nFON7&I}XexMCGRPxX9%zu%6qiP*hs~#h zUkX9@i$KIB8whSTfM>B3Kd9^W(cGV~>2oFg1AK?(HG@CqQSu(afUvwi59!#FMfdRV z5+Z8-&cp^(;!xmAgO(JJ#afkB^alSb( zyj-8CX!ay)03(gvk5gg?Z*Wdc_Nr)}@>cnh$u1beu+TKu!}47GoDl5Snhc^UTniqv zEC6n&!%lPGOm_@ycS(sZ$u6@kfS_hg8}dLwH`W}ESW6r%+kYC)*N4YxYVc<{PrOpU zUS`@*yfNueQU#=ERV6mEV&ou7!w+)Dpf|vWw{J%cm)4`@A)5WrE9ldfYK9{D^}LXZ_4zB_?1gDGx-FqnrYgqg8@ok7O;hMWzF;pd_FE zJOr;sxA;x@S3j?TeYf+|D7q96yW<6>?rmM)YFtlyW90!w|$O zb$r)+_XjdQS{j>J)gX;30}218P=))^ksinbC_g%a@cgusloOlIO>W1RCr$D3Gw1K$ zzGDBbl(tV=dgPmNP06Z?U9~`u`j`8n*H)bY+=tk#s2Ruo#n5d7SeZYj{`vN&p0}ye zE-o}JD%w4tjmN*|vDdVH%-@`ZII+s!vcv;snuYpck8vS6`84;(jX8jzl%5X9xL*Sy7h^{dAPnh-v(5#(-i0@p4n_kO?Tsg z%^{40x;!k)9dpyQlk=_8bY4%w=83oX9?p|7xIXgCY&hf5@Kg8#u|3(jJi*k8;HYIH zS+3i&ue=|YYQLFrj-hjTOoHizVpGV7qba(c&=5Bp_hCPS!_GpF?OaGR^ijx1=ksWL8z*;F~LrmKla32tTNs3o*H(bwer zJajM6E4D}HT0reb`OBv~s@*0k8d0L9>vzm5Zf$O%{mw5CpFjgpNaj#Y(euyFG0?#h zQ?Q6qeKgNWu^&ulHrL5TU#V~AF9;~j)hP(7QEjZ*H@H3iN+A$Oy)_2(SuDS6YP5~^ z`8a*`%SnwywP<1yisFO;w(mN4@(XoY(gGnP`|Bd>NT~~e1^YxK_9MJEy~J#}a=qo(Q;Pyr(hoZT1_> zYx~`epk?B5;ji%Oy_cSH3}QKU(OZ@QAQYFSY;rtL6l>0n*%DJ@>BBN5Z3y#ArC}cR z(695vI`cZavkyiJXU+&S(3czsoNas`hH(%$e&hI?DO_^Y2TLHCxlg9AkG|ItJ^ zpj(@A>%gi>iosbuH(Tk~9Y_tEeZuRO96^p&LF$bNB?d{p>3*_b$=Nl7FVA&a^il_ zCpKx+2iGG1Msshxu42Y4>Y1f+>#zfT{bE(y^4(A3j1&GQoW%NdmkVTrN0~~q0SI>g zeE>Cx$@70%*rD)X#t#X-t%S2n#Ar-;L)g4GUI3u$etLQIHNsq|<>2s(gn+%r#kRFa z;mPV*jQiP~6cON^9P=omWBEkx?I{$LqzC|-dRNYHfv;JU>i0=n(fAHb63z}`M%Ztg z+XZAGa0ah2O0zl(q41wFWZ4Gf>bQE*k@H~V4RS_8Gl zgu{Nl5*(;L`#F+cCL_iaK$YB%NC}t?gSgHgIIN_*pL0AFrr^^GrfZ65^z=cMC+7>Z z0o5wytPTdtyzkbGw~Rze3s&3BOhP6LoTf{Dn}GBPN|WQVXXoVX{L(>$^GX?|hYr@l z%ykI;fqtuKxgkL!ZfSm%MYYtXbk_UG51Hsc5W`N41gh_5Eu)ln(*t>`45YDQBkskojO1v{aQ2gh_cspM12blj zA^U@#--AJ$=FDamY*JN~fLlLFyVdY@uIUqaHi#JgE=?pf z*Bf$Tr$kgXjpI<2U3YuHR>1c@nJn0-mv#)$KbF#a0<0DKYcQ5xcG03?w^k~?cW?U<&_yhOmUp}KZWrw<@>hmEZU zXHAKSlfvXoa0RD=!Ys677K*D3N@ut0mmvgp8|yZYQ(9_!*VE~nLj`TwYUJTl4=4#x zAA}v?Z8@rr4dOdR=pN_2tnhCAsKRb}?8$unq@dJLxD-_Hxp*mJ;?+IqSZoYx+Am-V z3^NlO*M0bVtTNAlW^R50tpVI8>)a102SP!?FaO1@t!taZhr!2o+HthQi0+fWxCv+z zOtkOLTMmN9QPe$-;PC##)MFD@X#~oU-!LNyYUY;yA_gs9C&LbK>JG0E$^t zhD>Km)Y@W~+EW_VG?7|bjD3*@Rg=?`#h_}5dh0{QDlH`duC~{I3#$K2{$p9_>1ojt z`u+jqU_S2!H)A~iRs@ulB)!!XfU2nFTomce%IMgvchC<2?9ZXJk~4e5=P0vh(z~K* z7`vyG7-pFF4Eh&+>579E=-}4wwyr;cvhvBOPO?0VJa_-$9=&tZZMnovO&x|%?@b80 zu-T?A>M{&)OMD>t2@iRmH18*v`}gtd6(x4fQ-7@AFh45BU+P6U@bPOtB^e$Ac`%fiia|-(qP-U$s2@@;N)0LLi&UvCHAfK zEz4y8DrEdGtbX^+@xu9^U=~bqK4)9@SQ<=M|q5pU^GPxxMva+^IWYpipSi&?YUd!rYIZRqBV7m#X}9 zx_mxdPIfc31|gh!McrSMW{hJ9m$9;JQTJjhl;Gg4Z0L{+jk;GWjT z@!$GW`$8P`UiE*ms!|A3?(CQ(oe>kH5kj4V-hJcV_mS@+z%48b!RKK*ik)PA(Ynr1&ipypMy987*#Qx@_5OQqxN zbe&$I-d*O`F806;diVB5+T+TZ)ww;=Hz7$hcMk06W9iQ zOOXJzKTVc*NfSj>)rq={6@B+}`|a-Bv+m^$DTMN8Tsg{*t$Svt2R5K;d^fJ(qE3vGE zQJ3W^kKKwqaZ$={AJ?MuexL9>CL9pl2cu+QeyUOq@jD8^yPc>XfPg>$S^oXOJ-`e# zV{PzWPcmoP_!}rNV}weEu%m(Q_jP;ErGhZTxFiCT2nb{2eYV}S$C`My|Zl|c_xg1 z3C-XZTE1(f4PFlN>qH5=Ot0ypNAn`wlqY2ZaCxVJLi7IFEtOTmNBN5)KMe%MDKCHM zk6Q5Wd9*uX>N$`1?yZLNns@-<-lU+R9MX)xww_00UQfhk81pr`!=9=yH~c%B#{ds_ zXv^mB2%MZJH(B1x*9S0!?BuL2xs{%niZf)^506jJzpR0Cm%peqL|eu`u*NPb%(m%E0w+<0^xN`{+&9-Y*$&nC}*3f)mbjb&BI zlHnr%?$ZMgR>)_1Oy8cqLWa)92q`e&F)nGb0%=~$tKM^GLC2_K2r$2sK|mJF;#vSE z17TkX8T$$faA>e*mHvULEdhjzMoC?hh~0SE*G;I;3#Aai?=MA7b>cDD)w%@T0)xS0 z_KX+MtpM7_i~}X1tpYadBJ84-{tj}@F@0?jXa^3Rmj64I1EaHJzIn~uefH*A{HI;P zil*3Cy<+7g6K^};*#h0dBET8b1F&bV#&%}o*2vVS^451ZXRXAC8U6;rIL2iN{}V1F z;{o->_d0{5itvlW7=zQ^Uv>U;dpC_~Onq??2pe`xjVd7!xos+m;lY@B8DD zyxdBE|B*t*9@Qa0S(v6R`v%9k*AHhN{L@XoQ{34mc5*n@u*+^X?g|OUksV*fIMD@^ z(|G^+{fWq5@DP`<{jVQnluOj@32C^WsizF6IFsOyg2Ltl88XfLp9p5uoe9%Et*Iw7 zT#p0?+$x#8J#p;KUNo2Ec(0i+mi|Hem(=?6zc{yGr<&E5yeY1Z+i~R7-B;cVO_*OK zLvs^|u0AISRpBG;4XAMp896W{W_;oN$(1`p#`?$iw}Lm#Km0i)5;^BhpyTQ#pFd8} z-_<$=h@xM}&Z8sM+7l;kzWz?Z^TFv^nnmF1eh84%XG6VhI0=Y&XL57+_};&P8BI>5 z_btvbc0SSkFm?IQE>x|PoH|||s`FRlZ2mYH!dquV z1g-|UOpBhTm($M!xS#qM3DaVJu_odaas0#KGb!?G6-}N^;#(|#iTeNf@8-E+AW$+9 zBTuwn0H-_dk_;@W?Z?X4e8$@$#q^A0@X3`)hNG}i1Z1~td1W|n5gcAnp|}j!=Afhv_bY`-`E3guwLp^ zv)I^wi^WPSg(~@@YV@~FyVrfOC%KX}>5TO*-DVUsaaYi!YJ966=awvM8a}*Yc1_{Qsrw~K3j2DqNiOseck_SMaDA#BvL7em^Gs1-;!Nr9u9cKH4O6X>>G$G zKW%ALQEajMlB!({ps>2gc9BBD>a0Y5&(rPD!;DqbG{MDl@P%0`&+H!`sceFjg^{$(Z*CI zb?!^%K>T;a!Y?aItU}~~!vUxeUd1S&rmzDQGQ*=WQ|R=F*DKn{te-$|x{pGQk{MJ)S|vy}R9wWA57xd@$)m;?4k zz~WovMv92WV~OZf{uV%_e2oARw6Hp_NIp#!Q2dgB%YZljhzy1;Z<2{3S~ zoxN`H1Mg`R7T6^pw>Y&tdm634Cqfq2+w-%~M2I1?t_?KV_{am+X(LCb%dame+6*+e zvYqt}*?E5H^Iy_X_1ziS#mc}dKyeEHMyDso?j9V{o1cH zus-XQH$LsvH^3mzfZc>5OPb4!j=lrTc>kJ)de|T50&rFGM+UZ8V0>>7-YcayMYJR7 zft~GLam0g8W5!EiPwbyqeHzi~j%sB`iNTbNwI>ru8j9g;Nu(e@Y}vxV=+P zzcX4}mp9SN6Z1d%Gi_z=9E z9N{I>hB>N?ttbm)INJP`T$CG^OduYEYhF{N+=#tT^G1HF*e5)xWbiw*l!%>}anZov z`9l|tBlzHm*Cg$$i2K9WjPY<)X+qUP@n_c5%$q13L@8*u77<5j&|ry2Gj8GV4y?%8 z)HGv{B++j$H{lP)&s1l$;?M;(;0Hii1d0Cauba9uCi7@q1wwIw82`3oD_zzg|H;$4LTg#PnAt+trv z5v!^GboLXgsg}_v8x_OemNw*I-pW_~)jkM9XDLPc6<*D1-t-_zgOa&iiVZ;QQ4>T= zzibm;>g$oj_#8-h0df z5m6O`@+77WDeOwq?e?P-#~zTBP~AqA@6KhyRz&&+r8ul+s}vU$K#md}4v25dO9wkG zfX%JGKBv@?ANxAPgixZGcSxarl0yOW zkk8j8res5X99#ZEH*O+#g)k1PF?AeXPOkNjOW)KVt*b+nMortEiDD5eOZA!VgE&?` zYMLOR%7Wx|IQY_~N)BhcMol-%X2$G#X5|)ENVFcvUWTSD0O<5nhhg$7@pEqb4e}>S za{Cg8M91Z|dF;ku_00)a`u|n|&t4pZYUf5Dygfg0_1SxhMaFOX2gBs=hRGLsYd!WT z>w(7S-cPAI*AK6Y*ieGYd>j#D&M?BqISEoscsB>W)t2>O5b3@3g}45u4+ti(&_Cg^ zJo!3UXyPTV14x`KY01WHDF#nl#mL>V^vM-KF%TbI2qbvC>V;U)-zRUtc`5D^aWlgx z8hO#0so{Po%lW02Cb&kCN?T$Rz$3f4Relo>H%Eb3`AsxD}DN6VW>?aO&0 zxKh_W6YZk}f&!Mxx*IDIAasghNtRF}Nx+b=A zvY?t@WazN+cR?^#aeIq%Kwpx1L%k!6e&4L!!*)Bp5x%7~N(ulFv%-1MlwbairjK+4 zH!P332k@$G+Un;kvpus76Kpscd+<@+0~r$%2cJSI&i$8L#MBrYga-GBndZPu=i>rW zXXNm87b)+K8QNz2^<%hp+eiKnpN3gO5e!Y@EQ*VXSrvsZjTiYtoEw+ShO0B5^dBu~ z!X_PDE|f?1NssDuYHGA?CIreC{bj8d$pgyW&zQN&vBZS22+FzavX`%Ilh{3mYQ%j_ zb^U2M*4=vv6}!d~Xc~dYt*8h79zxFgk(1bceJxZCP2odTAsiP7BlNPq^6P^jW^mV> zw&JUJugoWOWtgmN3fu(6q6$f-J)V%Rep|l#Wny8LWRIwD%;zhkT`hUnOSFDSJ3>}@ z?9QS2BML5Ldji46900p)w51(1SP>fn+b;ZySW>vi|A454^9gnnb6eHb*<bv##V-ACEq4Ym@() zLiyd|z6N_T+&+)zAOGF7CAQLF0N>T@ORfp(aRc#gfwsHuxZfH78di?h*NNG%6*dd= zWSlP0EoNz4XY(ZAIKrOc0Inj{;p*aWOjgH!+qQN*&ENz3 zy`=81D`L84-!4TAeJ-w{;+M=M>>7>v`AidS4eaLAO;HaSZ>tu(X&9cc-Fx4t<+i`% zCBN|(fSk_=;DuEXptAJ8??nf&(~^|ox;k4rslh_Yg++0P;{JEx>n7li^$uR5I;tjr zSP`=N1xd*rH>yjaM||YDSC&8tW!t+Jy$tn>R1aNOX1%d~11z*gm!hr(YCabulX|f; z?rp!h^=AUR|Io;IEuXex52y>59WW{@(Df*4P-GKYoQ4>zs6s!R&}HKb)XEE<+6o#6 zb{21nho$?>5^Ns|o59CALk4#_f)2048v+e|HAI>wxFMywy%ai+0|-P7H5Q zdQ*W~N-U$hcwEUQtBZ-at<0rjLj7h*gcYpg06dR-1FL5E(u zgg{KSPm4w4*1}L^AJvusYnn%-g9vsI&;B{1;xb*n>25mpG&}#DV{@|8vyq0<9$#pgbI7sHBKS1Sp1az9 ztCD2a?4C>7*X!s;HCAfS&~zV}RBPy?%(*cvZo?@6f=ZZ1H!HGlUGYvj7gEm)!063R%OJT;h`ArbZ!Mshg zFvdtlg@tU7F5(L$0j)uk&ic$_fJ_(!o3G zuD-db5&bv&4vUz4)lXAf{dKPtXdJRwzGIy zwY~Af&$_;&7u{6Yf-J@pl~7n`IG@FQW?M6n9zPcwmv$q}PiV?{M(!}kVJ~XYa$dQ3 zGj$$i+WKpiq(}mPf)Lnm7)4X;SEuQJnjtdCGX}YgM*dp75<>%n+f#k*zFZv#Cq)!o zt34$3MX{ADz;DyT8q;Dxf4M@BcoimOT#U_?0i#0@uEGu;qqCM3uYJA7dQf+%EU-*Z zu?}e#D7&#qT#4I)LNz$a`$eT_0^vv^YtlHey4U97)e(ULg3)WGDN5 z@V~1(dd3!_Ow#t>1Kg<0UBc9IvM9qC!&+sokAGFPm5=yu2K}-Pl!QvWO8-V_*6zq^ z21*eM5FpF-LX#}1m=#-_2@|eZD_ZR>wLbGD0rKV;xnCJ&hw*_=r|Z)+y%?Hq6xl6c zr=boKPwUp~A7lnAOKZ#aSujt_S&*QuMMtjMRQvS5(R?qQeH`qTK0>V+_2lKj&)w3A zd|tLCpQS}@JpalRDLcrLArOQdb^Ag2OBXlffMU1&A_Jpc5A=%O<|(im{^mAFfnEEu zB@JEi(GETcxiw15$A(hoSZP$svoMTe*U`XbiGMSD96flOxZG=g(U*d^7W{zQOjDmB zGoLkXj}4B3u3fXGl>GQsUgu1d<2WRr@um{|UT4VSYD+cN78eQ-E< zOVKphAUPts*r1uTdpkK>A#d4Vn|6k_PnMf1kzmn?9(45xO5C;XNieSJPz-_(-oQ0& z*E!{3shfRM3-vZwE^D;zIqa9McrAUyBXlonH$TG7h3-h{PcgVfT?rf#ww1GM3Xs2$ zMC0A``WJ3p`))93ZPv;3d(f9;fuA+eV}!;Z)jy)JAI2mDYD3F3Tjm!&onxm-fkJrv!1f zw}x4ri%W^ld2@ND=K*oiA3?CZg(1L6i$T^khlfKm}(QWK1o*A(nDM>t>6*a+nu@$I2$IDILGztEl{BxFUqlf=F!OE7;gik0H zXp&~sgK&-6bZ4Ry{BetMr;rGU^`#Gf2PG92AFqV z$W3W-Hth#FM$d0SVJjx<1s=nmpd;yGhk}j(u_xL$ARZVmmPfxfhBc3Cl%#{OlXo|6 zlL*;f7{dvZR*pjDtH6>u74+DmSl)i~_(Ky#N4#bG7zNh_XIE6OHRvF`I~57x&Ax0| zi1md7wqFdI*GILieGrxAh+VbmGOXM+*z%!jGoBwVuuA$+TVH2^oCJ?-x4=vBX*+aO z?J92#l>bi{IQTx#v#;-EH8t2(ipv16|Hg9li#8fKjb~G`ji0K-ol0-)tV`*e40qp$ z(M%)V5`wpHuG8jDFkKdNYI@S-0U0%&+BJcvZG?c6viM`O<>x>{9P0(Q-Z~FAE!IsD zcf8g|=>7SSqMABYmn}Xer>h2o(!Dn;vh3&`a$Kex4Fk4jdr>rUumgWn1+y^e^bxLc zUPcNp4!0-d>eY#QY6!dGvAuA(+nQ|g&99$A!UvgtG`CliY$asK6GtD)Ol4=RbUt_3 z(vG?oEm`2=$W(A`V4FDDPFYUL}5#b1CF z>SBH~x}7nj=MaQs^o5JY)5~QfK=-?in=8U0a1ys_&kQLh=nWO))~E;f@ZKnVJ@>W5 zR-#go{iv4``GL&h*IC*Ga}S3yyC3563YCot(MdGLb3Uh5(p5)V=LvR)K(UMn!+iONLAD%0)BB8Xz7e5vy@mEDs` zs%nbgS1!&U)wTo{$gIVNq;+9#Oy*TA9TB!JedZwU)E)eMR43#wR3P$JAV4|htudC1 zwIFb^WAtqscdvQLN2;+=<6gSF$3+HirqDrni6e7r$N(}&dF@fWj+w4XLT$EtIqLAM zdyUX;I~(f^PX`cjV?O-7hF1uvLnE>uwAN4%zHR?H%}MKf0FrG1nW1m`Rk`Y!u*s6I zI%9tHJyjZCAD^r{YrLk%kiS}op~d|93Z}!yj7D;Mb0Dkrhh9-&(*Zjm`JMmqzpNkKB*2ckyJL|%H-c1Ke5sym?T<#Si*R zuU)p;umOk4q({+{gbIQ$Y2kPy7kiNtG|T1vqh z1Je#haKpH0{hqCr>CnN2svA!4?+=QSy;b`nqc-j5HpL=tCT|_t9=XVKIHU)P|6cU?9gJ>-%I299X5DGYO_f;zNMBvZKM#74ANuK2N%8Fd>QK_{ z-*%6jZ(l^^Q9c88=Qwvqu52HzqF+h>PiSWn2<_P5DKH&K(FF5r^gAg_tJgV7st$m0G6RR@h;C^~?0@eIAUmxfwmYbz{G9GQu|{OcfW8GYW?*epkz8 zC&)1nw_@)FptoV!Hyff&E6gn{p4#%FRBS;0QusB*i(U0lrtd7G3cFTLCNAnOWah&9 zax?Yb8l8fZRx`La8WJ~OJwkqi*N1G-GMB9H%sR%l-%}}_(i!+#!&IEg^;FW157#)< z{;{3Kk4^srD6AUT4P`G|!g-mIs(&}tdxEpD2()k^H4Y)Ionc_0nTZ)v@je7s{ zV_>0Y1x&YY_&N;G2%Tdd@Fv?}dQ?b*r;#=L>&x2Q` z7hQa-v3oHgqKR;1$Si1d`6x&w=B^-YMfPu7jmmBZcIFQD{**ePZoDMekqPYU`;qavXL?F@2G4B+^ni$5HN&r%2J z2yV=UKuvunIKLsfut)bLn*eDI{T>@51bdEOR5vUpm0NrT9kq!of|8{^Uwzc=5`084bh5kt`w}{UBA1}toNU<-DKF$<||1$aS zEMG=8b#~0b=PGH_7@P+NEciH4?TLq%so#u~;+&D9RW%vbL$I`Cs=F&kN1=8JLfK+D z7AvAFq(cneAdLfd2;$(glhGt2Ne)f{mAge%LIA3m^}`OC4sA;+DmA3#zUo){H_B~y z4$r6P9LbRKE$d!x8RvFjAn*ZWmQQL=S|c6kg~|J1?EepYZypcz+CGk#(n6vIMV3+t zA$xWmMJ4-|bwc)ioiJlk(PAxY#3=hVvhOoxkC1&gvW+nqhB1a2^L_U`pXZ#@Ip@h= zzrTLZe_rE#Z`Xa@*S-|nwJEZO8&-u~M(fMf2*=neMup~vZR+K)NsRkR7TrZWhu+ZJ z;P6xpP+u>YrOUV#$KY%jy)#;li@c#?iLu+(TCeRQ%;8J}oDo};H(yyHmgNDR-xB?+~q!KPl-+7r2TJP|mHGMh;$bq)w2ON-8JM<~7G=Y>P`Zk@yZ=1|M0aiQZh- z{*tke^C5wv;Xd4>e$L==sqF7jURNxD+9+NEl`H zfl}=W*RVLBUe!xQJf1QGU5GbEpeL~4YTzv_@cxsLfQKIm4U znT~?<$n$R)Uyxd(;7)PbK=!Cw(AI27NOMvqGL7K;}pp2#Y;t2EKt2E zi#vR5TiiTOx<&CzyCe-h(8FYd#3Ax7EwrwS6yfO;uGZ9M*d7N$tUQPO;iDTosv`}e z*?QAtYLrBQ1S4NjzNpNFx+(v2fWvVCjg_$PJo+RAE1r1b?OjB?^ObkFSxw1}N0xWy z)Imz^xT?BMVH1M=(n^l{jYSb_iB2z@vU6G6Nl3u&qCL#&S82$}8q6|U(;TdsMAuoLK1fqI!!~3I9PHwa> ztx=m^ah0e}S(5c`v(y_$(g--P8LY>4^?R~Nnl%N_npS-8H5Yap` zpMoS8-a?8(%I|iG#`s43mKMq;SoVXubjZjxnFaybESO~N9`JHy+_P@;diKuR1z^@u0$E!WZ~Hcm3M?Zhs75aqP_ysjo!D>!%*e`69p3zbm<(Q@xz zhfBsrAm6h@EEC^f#c;~<-&4sQoo}_gZLfu zUH$PO_~Jm}47>LxR)VUw0vPr=(E% zWuQo$Jb2g*H>IwhEpR=byYDUb5{clA`^>=*KaBd=FnOyKzLR+;e;vCW2MOvKvVA#HRr%YEhgDlwL zhokQcren~N?&d*Uvt8FRD>}=iVXUkE%*Sz(LNC41*!?7Q6&u;JX-ogk?QWkfd1EDz zhd;KF>IdygQsjT9rZIPtNa^%l{D#y_oU6sdPK)r1)&cFAH!Q!5l>_0oHQ(*xDyQFY z4DY=E979TY<`t$U;xZqaWZb)97xb!hHgKROpe~=1I-YJ8aRTYp$8db-(W7=phQU0o zR_%~1d@<7glH#rB6Zj=HyKrgbDhVNXN%YTfK&W`6K{3iOpZfWehM3Kl%GWtlE`=9oV%CbpDQGKbxzkEe)ZREgudkw%{x z{?Qf60hzhk3zOe6){@c?A`(zFi2Dk&#d`-rtS>Cb-dm%)#%hHJvVrCGppJ5?>S@K@ zDpM~B%_Zc18BN88u?fF)eVza0hGmEuJnG34B&mSm5%L-*Q~!<)aiqQ6a+B$lWNUpW zE=uEvPtn1_qg63#RFR~7g8Rc{F5*E5Z}EKGeT8e0Zl=g8K9_d?G&$iV$Z~`E` zHwYFNRC|9&nQX4*JP((4b?L*igjXFaEl#OlUK?ZFe#@u~g{20r`37#S+4pTa2rN)N zx&NbvJXXmAXqZ9FLVQDPClL6wb1mQ4+(TGoArFgPsUzuf&bCu&_2ksF^8Th-&`jm(s9BeSZ3U-hzYXEsz0^an%Kn)1c`VPIl`W3EXW&l`y#GjbDQmO zixu;oJA89~hR7fw2uQDj-KTM%@$>H;xE=*=&Q-|$!&zEKkO+;|n>h5enx*+tXampG zVp4Br3Lok~k{0g-{_&!VBu5q@EC|y#7if-BZRp}#gwj6o9nfFw-v~s=0sX_FSG$k1 zViBMH{_}#(o22K zbx~0d#SFvYZ#age{d`9ZQ?R0ZtCsrR6bw%Cfu#CL{W2I}$SJ}@j{UL9=?-sg1 z_vypZa3*7w&ZmxHr0u?LJs9>>zF5O>2su=FPOc_(QE;JSZrg07*sa#5Lb|Z>qjG`> z(|nq7(Ay;J_<0`4yHA{j1}|20Sk|6+YZr66*Na}MQkY=~7uVTmE<9|TX*q-1l~z(H z#7x$PbeLYB{-)$dB!Ul)Z5%VU1SjWyLZ}duEDyjB7jB-?YWK30vCkJcC8?0gan^hW zk!>|0SB4h9KXi?nM3OJcpi3MdC^ddc#$nnLyRBDCP~UXki^Po^srHK*hVo2$UQUSCWF^v`QaW9w_tf3WlPn8#`;AN z#RNgONg$kK6%6a1s2v&P8YISkndKmJ#W1204l^AWI&`_Zy&P9meG%1B!t;k+m<0&W zT5l1$H&S82*9Nd!Q&#o=5qAY&5nz>f+*dIkohsAYBOx`^TUU1JvGM+ftovMGLO9crN|coxZ{!`DIGC@ zb!i_mi#|~v9HfKc&G#YRs=iWr5v_k?P^z1RKb4)xVUU0CQL|L#p+>m-%9GvzZB$L@ z(Z$SVoO?gnx^LcDEvJuIQ+r}{(qydB)H@GXn}=^l(^H@3?JKC9uVQ#|aD70I2=C21hRborLyBoLimH)^3{yQ!o(fFo7>w zG=gGY7q3{-0*TE=*?yF=6J(1h>VMp0DxN@Hyly=ZJwlC%^Wc6X)@zo5>x%L~h>?{D z!)(yj7xo)CJJ)`mCZ4KK_1YYA^?^ev_f#j@)#Vl*Ti#%HpQsH;!STyFKKi)8L-?}O zSC|j3VQ3Xh6o8V6;LqBGHHLj~uW8+*$pg_hT7{+x;8Rh{;LywGPSqFH?S8~hubk(I zHtyIqm2$o~%W9#E#H9MZnef9jezq&$h;UxcPpJ>sJQCQnqhN4N_WN+7%coCLg)a@o z-VfH|w+{>kIYlDCp^(HfsZv8GtgjtyW~ri<`#6VO&SOD)_hoP0YZ4Z>9uuy&K#dLk zr}VuT0n-S#3xmiu-ACmv7~5bwCT2N1OYVhI0@7J({ZaPY*`mlS!t%}Z(V!=gxn z(UN0QDFUjeBe(g(K0t+-pkP%H=>**V4cc znn}=A@}%0h!d3$n`etii#&vKj(qvKWb~EOg|_S>-9|x`P8oDeh+o8J5ldBaCkfPYCNn! zF2Jd(K$rJ)nvqgBYD29`u_lcaqfif*bI2*KhuL#*=_~hS^jwxI$#y?;aw6N73eS%` z=6>9Az4qM-EkuiJYy^o|x!Pw?@Ac`55hgRp$Y*)<`xAgXdkhNHlTJLxPe(NV8{ zw{vCQ;w9Pm$HnuDHbJ@lxAuP@al&$>oYDxM)(}xpbP&jk@9fE_juMrtL>WdN^|%!! z)NV^0MJ~N5eHvf$Wk@&8Jc6-=+$bx{OfSle8=0gr$lf2#f@Ds#?Nsh)Q*Q| zB0$xIyc?^d-4+RVxEH?{ahD1vO8W%Qav4j-(>GlR5TgLb z{3o_dm%v|j4`SA&ESQ< z+pA}`o0a!)15yzX9n-#Th-kHBFOAb_8S(zgM3d*|D@V3rxx7sG8N5OCYi8Aiq6diD zDu%>{aYoF)5`j(^((Z-t|4%J|A2qeZHtA*~Rk-QwVKrF^R-OqjVchZ)yPl*Gq;H?X zO2r2LgG(xOWE|x?(g~-jf8(sN>y*;J-yD%K7p1*xP&DSh0*Ua7*Bp_P<%v6tsq#t= zSY6x}bQjV=BKtrH%Jq)8)`S|2-adV%Eok&E+Ial*Mzpc&Gn%EZ=crkq#8*G!p*&m; zW>JwscGP|`q8sg{aZfsAG-I1{K#1~Q{GEpHgwC{}hP~eNnQp@gU7+~1$&aXUfqe|V zs+Xo_Lm1h|`mqvE#Fv3~9|As&bP*X-flqDn4bB>*oaygVh{^D(Tr4oi z&e%?~6KN~LUMacLQxfQJtezfF>$2Xq832S%_DkmR{0o`VTo|sJ?HZ3juBGM~9J!Y$ z&VS}pjzwfglgPZE>1p2D%V9kdCSA9AtED{D_zSb28ay_PB7V5dup)SS=|J;{x$5W2 zPH9)5fr7UsB65IdD}>AkqQ}o#?yIhmfk({)hUO~LSSi`y!0Re*>d36_{rr1HQoWt( zS?%nXBGjUB`w9ga4IW<=a)j0=moFd9pi{rX*K`Qo=XV+_yj=+t>}B}pbHpd#cRA_?ZU?PQ=3Ri zK)IaIui8K*l{{8K3ZS_#Y7YeHM=PD#aU@Hbyu7>*Ljky}bCa6cW;XLpBrWs`8pZ?wjDpvcGM;~Ei@%JTup5gbl#HJsCQ`4g% z30nWiC;Ae=*4?bJUrf?NRsjYga?p~%6w6o%DKSW$zAkECYm1y^m*!~Nh z(o~!3BB?#Z=m8_dvC0-!nreRyO>+@dxxrGq8)T+DY+Tg<D0p;5d zp!5~%FVz`!FO9mLTT_!Q(nbGiO90xW-8ph>$Kf7C(k5V&*2o&!|#hKqn9mgDo{Jxv!TGnY)IBM`}Nw z<9UjDHdcm_tG6aBnXDCkcfZLnr>>QH`mp;)$AX@q&$0d*!xMIYzHWd`WzeT`%1G}7 z%7mnraVTWbPdwmBY#oQ+;XXJytGIWAk3S@iguj!>};*2zx4N{nY+C9sC!QfX7 z9$S){)T#z_9oBuFJ0JXV1HAf5(9x)7MuXYN(9rh|cKeknH|2YvCmAPddjy+UTU76M z?0&ks%dl!K|*gT<%)$SY#p~rK>F4 zOH1yflB(wV$7VEMUk(yiRD($h*R{eK`=~&}f#ZW9Q3GoAR;1^N=qHT;;cqLrsYGW5w zqF>jBO3GQjy{@FDnfxZ=^6kFESN`%k1Q-Ei{*3Rfa4i6+%WxfTu^37!Pu64s^-0mM z$7FYfJ4)C!7c_WrXr}!{gjHsa+`fy$r*d!JF0CsUdWO&UabUNQD+isw0a-hie2W*P zVDguz_%nU`0o=6eBmKu_`^*Cve#VQxypA7x{`d}%i8{_2fPX%~-{<^4G4Q9&{zRw$ zb*n080ZGSJW#H0Y3$wKCFzqqdzF_eqfE4jKPvhtJ@uwU6zYXw4lQ{q3Y(IZ!3kcu| z`wbKJI;aXSUgqbK|1hGR7ZAV>tf3y|6NGge&l?Zch;i z?d03(KUagJaRFT>+C{8}Ec_ycD~9W2L6P2jSp-ZECK>S3fOaV&CtI?;wfN?Zvs895 zs4d%jDRRQKT=^-LNh-*Ao-Dy%GkZyJ@MYq0vOK=7)~K7)z2?$ebxBK=&)*dlvG4;^3PVP$0{ z@8ofU9KzKLy}Ut8FO@2-y!u0$(l?o>VBz@B*E6!T4zf0#@tZpT`Ec;WYl%c zc-2OUP*^PnZEWdz$J}#nAmk%;tzacK232~S7lwzDT1i@p^`<(OOH*cOxvN3su+ns2 zoKbV$qZKmy^fPyOY++Gx%c5uNa%Izgkis?PA?rp(rP@FWHVV_am=EsA3nJ|(H%W9K z6L#xD($>0hd{Di!#Fa7sZ@W`ZnVZ4dyOxERvd@R0)7>FKhmS45moYrQ#s(IL06I;( zMB*}dJPzlxSax@*Y$nok$`~0tH1VjfQ_Q~W9i-mpdqdc+sq-25=sD=uqiZdk?y=HE z6_ln^+AU(OsrQ{%Q#dRGmz8HW@U(05T`9({sOh@_52jx5MOs`8*B;~9#y5Hnj-akc z7m~n9HMAG$k%jB;)WXl4MPFZ9eS}E?<0i60_rSl8*7Qj?d6mH{<5jyLT2~Pz?Evac z#BDSTMJ3b#b*r1xqnN%7g)v4c$z2QzoFq37+_u^^vEP;44OpZ1Y&#F?TntNJT33UM z)Dbtw)&^9McjouKSa&X}7GJ4ZSN3dSM!|>BKI?^Rt;!bBMMLI4-tC15Q`%>eb{J5^ zwsdsfjOHB}evYhVL`nux#dm!t$_FZVz)L+Q7I~sts<4j2$~o8GBNS&u&4o~fZFJR? zHmVyT>Uxjc7_<{rmqNeSO_XF~G;ad`SJvTCU9`M`Ax$jP@~*7ztFV&)d6OTm#2Ql>&3n-&F-PT z2B0oyVi5^9B*Q!t76+$Ej*B7^f|$8B&5;4a@6j*(*XQl2*)|#7Ncb2(I+bqYHNGyU zC_&^LWHs3T417_8q=Dm!PyfLOp zfFCBqycp&R{aFqEn{2Prcfw&qB?xFZ;|UP3xeK*Rb>87TG|zA@dFh>FOK4?uJRA2p zh3g==GA!uWS;8ZvrS}G8^cyU>aD6$G(Gd;QX_qUineFYci9wnf?6_1DKS2Ubw;qkR z4h)6~jls6}-SC7KmIpjc$A#gr_cin*Ww+bv`~z5~#z8>cm~ns7LhXo=C*>&mrDP_x zz@(HQy(h4-MZ<{f>-TZ;Pty0aw0MK1W&5cya6LNh{d)1!#uHE}}tl zhac``3L!?T+I&qc4lC2W@ps=?6iuxQG7aOr7Y=iuId|&vy>Ot*dW&Gb zPxxegKyxj=K4E!#*e0s=wK^oGfFV3@mn@srf#6AT`!CKwBRNg7LLu2 z_YbJ!65PyEI||Jz+p{v1=NHnaVNnVkjSTuYWqBV5h4ruBDA#gV_>~nU5OvdU>bmIu zcDX;JsU%mh8q+MlX3}ZLn~-9clC_rNFIk-I#_M>=Lh96KTIW!o(sQnDq6@Tk`OthY zBo8hRb}MtMUoFwQ4OfdFGE!Q9%QYP-ztS$92_C{%;6%bCH853+dHF_x>XZu+96Gu~ zKAS-Q3X!_jAg3i18dIVz*R+F&u>dW8oVdTD!L$P-{lt#IXF&%0_KWtCA*z2<)u%MORrY%oB zJW!EB} z^fjE)R$@)w924Jm8J5{*9zV}{9^~?IrA9Gd69wnK;4t9yz436f-(M_{Kf@ScxoKqLk=K1q*Z-yNuJ3} zu{Hr(ZOp&N>$k@P#UpAQ{-TFxv^@U<9{f zz-eR7jTAe&t*x0g6CRlfh;tovbM>l&G7XG+>FT8Lzyo+#Ul7ozOxq8c&%`D{=Y&8a zUk`oDyMeLZ%MEiSN+mranny9<-j8=5WC+@x-XF%40Bk*TuB&#X%Sax)czVdv+jdig z+`HU7*Y6JW3$J*?O}91VJJd4jTomVy+)jesnyT!`U7~89?;3?s zw1r5kIo~Tu1Vp13%I{#7NJY&`SaY0lvo_4nC^mGhK9KloCQ??=-Tr6W|KDkGQoIUa zFMfJh*+6r89gZ#<4d{%Ml!7{XSVBmFPL=Z<&Q0~Caqb@?%sKCk*FVIhY0i*uJEH8= z>Q%D7fl)v7tzsbJl+1(&^qj{hj5D{mneuK``V2zeErK|Nx4>;0n3$O8Vk$6bq`GcCV5cr z4FrPCH83=^(5sm=k7vYidCz}+S>ZY+;?+KOd{nIW1;wCi>pRx7{R`S6Lo+W?2^uiy z)*dTRJfGxjr{AC8eRs>JiwC-)`@KryLm+9TxLuHoUAAaiRx?Ffco07!WMttxaBDQ@ z50&R1rTyR*_MDuY>+d(NauB%)nfxUM9kjsNo~q*2<79On&XYj$W7ycPw~Y_B_Y!{P zJx%G|^R?U(@cDj3zR%LIXGo-+=y>=gWJ1s_xW0w-;vROe2iSv2P+qtQX^=LaYC&w} ziHcgTKnrY6I(Ii5AxTZY$x-$}X_Y91T ze&`WDMCQ)rlkY_LqT#B+uU@@6byvG~MB4-uAm%7bzluYQmD-j2?jecse*BHz=#>D@ zI4AMxiM`Mu05GxQf-{cpu^X2Aru%~_y{{a#e`1FJ0NTa#ywOF6-(3EOfBp2DA2^K+-v1DZom#1!0Y&zxQL&2_pejN8>#T3 z%B)BC5UlnE2OKFws3)^dJ{)}KFBUjBo@lX^s=xI$Sy?$R&uGi>I`1B5l;i{M`h`(k zTu+u}zC*IovZ;D)1K1|+GHY9RlA>r5i{)Pv3S^keW-D1J8_(6Ry`O0_c4?^|A|vxsCCKai3%Izi zowP8NVOqYhSL+B0f-jx?JB4f|GO6}3~Og&5}n&!z4oivU9( zfrINpd4M>Gdhn3)0FjxPdY{IOLjrP=2G>Xg25no zhMoXda{Y#|z?Fb94(z%9MV+rX_C=3LZ8E03%9uVCB;bZz*(-#D<^FlP=J1+ClZ5rO zh?8x`hK9{`WS}&ixCKxqtp8xP{GO;y%BQ?)6nd(rX&F zm~Wc+lBcEWtiHA70HvkoV(TRx_h2K|xMI8KT|JdJIkBA9L&QmK)nDRZ5+JS76FQzc z^cG+}ciODP?6&zk(&eEn_pRu#pI>j(YQi_JePQ1@_F`bv*W9WV%=^pf+C{$=WEZfv zB+w2|ADLsn{T{L{{L5gpBL(Jkozl_Tef^wgQC`$DW`uzZwAZ%g9)lGAJqRLn(CG4h z6gCd)R>StIjhz72;E}O;wWIzZ^WWv*Lx*q@xyf4MurZ4Nm=_BULgP@)rxdyL+= z>nm?@>=$%5c%HMZc2BQongC;&TRT5y{MV1_+evz$!2oCaBoC*J5(m!=zg8q*)M+gk z@fLptnEGyJYjN2S5f;{kEBWe0zJWKBr9Ysvw&XpHlcp^^wSLL4%5De0jLB-scMlJj zc^;LwzO8>v*|~uq@Q({rj6G~5T9<0>+#DK^8>)sg30VRRYr2!`^{+8K?1;kpxbqsp znU5{ENc$GUe4l+-5NDGgb!Why-PP#vW0fF!Uin`HGya%<@#O9FX&xvc#HA_F!gbLM zPDkyrX>ApecX2I)KzrJU5hdYJT+*+1a*&Ph+GhGu&+ez%R}-!wA0!F3lOJ-_tl7xmW*O|xapc)j+N$6vZv{(A!W4)l1?Lx&8TD-rw;+PCGFo-42a zcC31(0)pGGtRPl{m{0^2Rj)3TS2nd-iP{f<6mk6vRi+6p)rjq+9kXAWu+wahW;iZ( zoM>TZweL*gieioQ{DhQe&xaKK2-@SC(w=+-t`nObfjHxLcwSCKZaD$=6RVA6zV%Is zY|ZWimfEZUcv;hQR1`KZl{g;@eKjZk7qEABZ;aBnd zov_panaSKtKWsjr?fzyS)I6YpnmM_7#Tcb=-DN~3xdh2JZ3PxN$Ap@ZL7s^M!2$;t zn|HWhrb1=%Y@-MUoyih1N)Vfy;Q{1`L>aJ~bm5NL7%6HqMNVY%aVdlTd=z9Q?u^AS zIKmRww0)rBMOQw!bDR8dsdWTtwp6WO2n`R!PzxqzJ!jI*y31|qg=Gr8<;Xsk&AZZL z(C2`L6kg0X83AT!MdanZT7eFRDTUY=S2)G-IQJ%cuI&oB+qGUXLK0`a#ehXe;-4x*qf9R}d@7WQ*l*@~ve6PE5sF*| z$|&OcvZ`jx_|%%yf~g-gakfz}^jTnYaYLtT!)>BuFM!x1CylJVydWh zsOFBR -H5nzvrdubt2W4j1eYR#;c9+|UTAQXuiIgm_DyN=}GKYHCty6?XD!k#A ztI;=#zmJc2Pq&or>fpp;8g<#J7mUoDJFVB3c3#5JXGOQdEnMec*4zat4>MfaM zOKutJqTb+ML~XX|dt%55@zO787EpbpWq>7KiRMIE4+p6ea!jNrtyJEl@#@dJQk>lK zNC9H^wQmFpHWQP$j?6f}y8nx3ecvcp7e9pe?Ggyr&fKz)h!qW8YnGO(w3kny#2o5J z8eiWG#gVS&TGTY3j%PnWo(8L`l6$WyrF4F@>Mk+}t`opHQ(7zoR*UPhXc*Fq%@pI8 zoupy0e2vemtM;I;l?gUhD@!AuSWo3Vw(v^a@cYsCEA>-&v5m;X`2(48@?EtVgV&T? zYv;>AO$##4Fy>nWl)S3BcZ`b)c1Z|YuTA%hmtp=xJIb)F{96rMKI4+Fl!z(22edN{ zaUtn*rLW$=jIcFM$j!;HqSnk-T8`-%loLscummeYeL_$=y)$_Gf!ITk=wws};xA;95gHbE_+g?EE!Ji4SdAv-)jr2*Wqg_hM6& zHe1_c^K>%Ak$`DRADZM~wj^|K&8A1qbuufU6X>|!mf-E5-ZU!soIJ)9$JCw zwdyQw~3!%AKG7?{QCXzgaj01`H(9Uyfm<#y97*YGYo#V|#g-qVE4x#q)ckpwhx z^{I7~4T{@!v@+}{KI-M^-Rzmno?U@eZOnMI-np|N?~J-@$n$xdzhGlInhzS9zLXn^ z>KUI~vpjbmMA2f>NMM)Agm!B2_lryTc1mlQiXNJ8K0(0lkTIa}FcAv%jbCAfV#u1K zB&4_?+zL`79Sm7J&W==mL|s-mrj5S>g4X+%6ecfSzveErgm^yvm?!m&t9)5EE*{hH zxFLrkd5e;h0E*h(!JlwOpxg$b9G7TsRgo-DMXN;^2lZJ}vfjE+RA^RE%hgl6v}c5r zm)$Gt*n7*CseW9icOaNmg>dcGL|I$Yy7loVBoup;EHx%XyBp|2sb`e(WXBa% z1unj`TTi{QGvATP7^4P@je3U;Ku-{^AMM3`xNDc}Wiv^7R-`s9W*W7Y;YLw(6wXq?G z>WQy|Kc6q>av@Z$kvA>Pi1~$gd=`3T^@f!TTO?2O#2#F7WFSvV63YGba^8sty}#p_ z+~w>eWYHNvv{e7V2WI+K*?srI7`t(?w^bR{nHDJM{DxclijqgPozU>3=lhGv-0+vZ z;C4}j=-4kM@B6!S8uEI`%#gJ^=Daj4-tEzMMNB6CK5eW=IcJ@nJU^pq)82Y2eVxMs z=Tch0X?HL6q;aZ`-T4G7ro$? z>;r?4Y)H__U;4JLrmNI82<0Z&#Zmw+Ubxw{HEk7!e=Vxz3@QMPgU7T%&+DtCHEIi$ z-cvqeEMIIO$nmRPTS-B5WbIp)btIUSD_iYuJB%la>-a9kdhBXPOYN?QKX*&^iRA;# z!$Q&=WttfRVbc+zPqGcgYDv%>9M|y0pd3MOMH)${{#itk&oE&&T#%Dms=0gY(TL(NG{wq=XbocVdfFThv zBzG{x)e7RcYI$rX44pZ)cmZd0hQ%DAcWk)t_Lg<-*{1C6_|q-fIMz0H7E9R1+lQ~? zHX;cCnbtKg+)SBV-fbI@vF9u6izUoVo@E6{w`I9BlgV4aXRDM6NlHbI0ew+%BJ?Yn zeU%Ar_ul)ArnVPiEKfh*-Bf>_m7{Gty$}VUuSJsZ5QRUYK^t#P`@t4pa;}6gqiSH^ zlh}|uish(f8CZlQpGr~Tb_)V6cV!1L(%p;rA^76oOxmFBr{c*0a_F%js3&BrWp(NE zlNnK(D`4QZ8yoX;;K8{e?{K$ur%1`8-A&jQ8D_$uN9V#${>sD?|NN8bgmIM2b5V$` zw*{2#>1LT?M7Su^cvwfXG`9A>u`w(+XqkJ0t+M*_nBEoT2cM*M%~;?-L8|$~8|a$P zt&Un;S8vNE_nl4nZVs;v{JyYNNE#{c;>%$19}~sLxWm?h>C?;BUmX(3_*RW}8?&#^ z05_unA!GXK&}3v3n#v1!UVsAerE*ap$6g<{{~X|SZF+=#27LJ3siD-}j;bFL8W|*4 zF^F9ZOIZ$V*KKaz!oALJ)t8yDIMS$olLMOCu$Apz%^#>URZdehOuT?ppR72~sJP=A zi{EXNl4-S}QMBt69^Ezqip{~E>77w_o#q!?oRgW}MDI$e9S@XksiSHs_|I67B?-Bn zC=2#Sb1A~j4S;H3Z7dLrPG7ylH`k~1tB~$sTh@hgH!7iGdSgSXackOBe;;Tx>po}* zeCyV&0^@F*p#gR1qW)AWJwD_C^1j|}^vT98AF6QBGfHd}e@k){v+yq42fWBr!rUlZ z#js8G8LtV~k*xQXiY$TW)`>Ye1v!OS@d4MJ=6XJQbZ!Q(0`#s%(ko;IsR?YE?tE^& z(tAb}tsuqu8L$QbEL09nlmN-6T}z?nlXtM|Od%nKnHsOG5˂FX?oT2Y@oPJ4@y) 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 OLsMPve(_z~-~J!0Lc@~) literal 58839 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

Uo?x!4#4_G*OQIEm9qs_Ll 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 diff --git a/docs/osquery/osquery.asciidoc b/docs/osquery/osquery.asciidoc index 88f8f768df0de..66edbc95526eb 100644 --- a/docs/osquery/osquery.asciidoc +++ b/docs/osquery/osquery.asciidoc @@ -37,26 +37,25 @@ To inspect hosts, run a query against one or more agents or policies, then view the results. . Open the main menu, and then click *Osquery*. - . In the *Live queries* view, click **New live query**. - +. Choose to run a single query or a query pack. . Select one or more agents or groups to query. Start typing in the search field, and you'll get suggestions for agents by name, ID, platform, and policy. - -. Enter a query or select a query from your saved queries. +. Specify the query or pack to run: +** *Query*: Select a saved query or enter a new one in the text box. After you enter the query, you can expand the **Advanced** section to view or set <> included in the results from the live query. Mapping ECS fields is optional. +** *Pack*: Select from query packs that have been loaded and activated. After you select a pack, all of the queries in the pack are displayed. ++ +TIP: Refer to <> to learn about using and managing Elastic prebuilt packs. + [role="screenshot"] image::images/enter-query.png[Select saved query dropdown name showing query name and description] -. (Optional) Expand the **Advanced** section to view or set <> included in the results from the live query. - -. Click **Submit**. +. Click **Submit**. Queries will timeout after 5 minutes if there are no responses. ++ +TIP: To save a single query for future use, click *Save for later* and define the ID, description, and other <>. -. Review the results in a table, or navigate to *Discover* to dive deeper into the response, -or to the drag-and-drop *Lens* editor to create visualizations. +. Review the results. Next, navigate to *Discover* to dive deeper into the response or to *Lens* to create visualizations. . To view more information about the request, such as failures, open the *Status* tab. -. To save the query for future use, click *Save for later* and define the ID, -description, and other <>. [float] [[osquery-view-history]] @@ -72,17 +71,17 @@ Each query has the following options: [role="screenshot"] image::images/live-query-check-results.png[Results of OSquery] - [float] [[osquery-schedule-query]] == Schedule queries with packs -Create packs to organize sets of queries. For example, you might create one pack that checks -for IT compliance-type issues, and another pack that monitors for evidence of malware. -You can schedule packs to run for one or more agent policies. When scheduled, queries in the pack are run at the set intervals for all agents in those policies. Scheduling packs is optional. +A pack is a set of grouped queries that perform similar functions or address common use cases. <> are available to download and can help you get started using the Osquery integration. -. Open the **Packs** tab. +You can also create a custom pack with one or more queries. For example, when creating custom packs, you might create one pack that checks for IT compliance-type issues, and another pack that monitors for evidence of malware. +You can run packs as live queries or schedule packs to run for one or more agent policies. When scheduled, queries in the pack are run at the set intervals for all agents in those policies. + +. Click the **Packs** tab. . Click **Add pack** to create a new pack, or click the name of an existing pack, then **Edit** to add queries to an existing pack. . Provide the following fields: @@ -91,7 +90,7 @@ You can schedule packs to run for one or more agent policies. When scheduled, qu * A short description of the pack. -* The agent policies where this pack should run. If no agent policies are set, then the pack is not scheduled. +* The agent policies where this pack should run. If no agent policies are set, the pack is not scheduled. . Add queries to schedule: @@ -159,28 +158,13 @@ Once you save a query, you can only edit it from the *Saved queries* tab: [float] [[osquery-prebuilt-packs-queries]] == Prebuilt Elastic packs and queries -Osquery Manager includes a set of prebuilt Osquery packs and saved queries -that can help you get started using the integration. - -[float] -[[osquery-prebuilt-queries]] -=== Prebuilt queries -A set of saved queries are included with the integration and available to run as a live query. -Note the following about the prebuilt queries: - -* The queries are not editable. - -* Several of the queries include default ECS mappings to standardize the results. - -* The prebuilt Elastic queries all follow the same naming convention and identify -what type of information is being queried, what operating system it supports if it's limited to one or more, -and that these are Elastic queries. For example, `firewall_rules_windows_elastic`. +The prebuilt Osquery packs are included with the integration. Once you add a pack, you can activate and schedule it. [float] [[osquery-prebuilt-packs]] === Prebuilt packs -The prebuilt Osquery packs are included with the integration and can be optionally loaded. -Once added, you can then activate and schedule the packs. +The prebuilt Osquery packs are included with the integration and can be optionally loaded. +Once added, you can then activate and schedule the packs. You can modify the scheduled agent policies for a prebuilt pack, but you cannot edit queries in the pack. To edit the queries, you must first create a copy of the pack. @@ -194,7 +178,7 @@ For information about the prebuilt packs that are available, refer to < Date: Tue, 23 Aug 2022 17:16:53 +0200 Subject: [PATCH 28/41] [Lens] Wait for up 5 seconds for the Lens app to come up (#139163) * wait for up 5 seconds for the Lens app to come up * retry click on filter to get popover to remove * Revert "retry click on filter to get popover to remove" This reverts commit 0817f4634326fc0720ecbbcd4a4217eacb8806d1. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/test/functional/page_objects/lens_page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 2d9eff8fefd9c..7eddf00431fc4 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -45,7 +45,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont }, async isLensPageOrFail() { - return await testSubjects.existOrFail('lnsApp', { timeout: 1000 }); + return await testSubjects.existOrFail('lnsApp', { timeout: 5000 }); }, /** From 9358fdce71710f162bc16bf39ef56f0631b7b909 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Tue, 23 Aug 2022 17:17:21 +0200 Subject: [PATCH 29/41] wait for loading before asserting filters (#139162) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- test/functional/apps/visualize/group5/_tsvb_time_series.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/functional/apps/visualize/group5/_tsvb_time_series.ts b/test/functional/apps/visualize/group5/_tsvb_time_series.ts index 409b2b3610f5c..f9e016ff1f635 100644 --- a/test/functional/apps/visualize/group5/_tsvb_time_series.ts +++ b/test/functional/apps/visualize/group5/_tsvb_time_series.ts @@ -193,6 +193,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); await testSubjects.click('applyFiltersPopoverButton'); + await dashboard.waitForRenderComplete(); }; const cleanup = async () => { From b65996a1b76ea42216f5ccd1264ffef8c5bea375 Mon Sep 17 00:00:00 2001 From: Andrew Tate Date: Tue, 23 Aug 2022 10:27:10 -0500 Subject: [PATCH 30/41] [Lens] add display-infinity option to custom palette editor (#139061) --- .../coloring/assets/infinity.tsx | 17 +++++++++++++++++ .../color_ranges/color_ranges.test.tsx | 1 + .../coloring/color_ranges/color_ranges.tsx | 4 ++++ .../color_ranges/color_ranges_item.tsx | 19 +++++++++++++++---- .../color_ranges_item_buttons.tsx | 17 ++++++++++++++--- .../coloring/palette_configuration.tsx | 5 +++++ .../legacy_metric/dimension_editor.tsx | 1 + .../metric/dimension_editor.tsx | 1 + 8 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 packages/kbn-coloring/src/shared_components/coloring/assets/infinity.tsx diff --git a/packages/kbn-coloring/src/shared_components/coloring/assets/infinity.tsx b/packages/kbn-coloring/src/shared_components/coloring/assets/infinity.tsx new file mode 100644 index 0000000000000..8e28d98f579bd --- /dev/null +++ b/packages/kbn-coloring/src/shared_components/coloring/assets/infinity.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 React from 'react'; +import { EuiIconProps } from '@elastic/eui'; + +export const InfinityIcon = (props: Omit) => ( + + + + +); diff --git a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.test.tsx b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.test.tsx index 20a694a59283e..ce2f4f3e6a9fe 100644 --- a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.test.tsx +++ b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.test.tsx @@ -59,6 +59,7 @@ describe('Color Ranges', () => { continuity: 'none', }, showExtraActions: true, + displayInfinity: false, dispatch, }; }); diff --git a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.tsx b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.tsx index b8d8b3aa604d1..99055f904d2ea 100644 --- a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.tsx +++ b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges.tsx @@ -26,6 +26,7 @@ export interface ColorRangesProps { colorRanges: ColorRange[]; paletteConfiguration: CustomPaletteParams | undefined; showExtraActions: boolean; + displayInfinity: boolean; dispatch: Dispatch; } @@ -33,6 +34,7 @@ export function ColorRanges({ colorRanges, paletteConfiguration, showExtraActions, + displayInfinity, dispatch, }: ColorRangesProps) { const [colorRangesValidity, setColorRangesValidity] = useState< @@ -65,6 +67,7 @@ export function ColorRanges({ index={index} validation={colorRangesValidity[index]} accessor="start" + displayInfinity={displayInfinity} /> ))} @@ -79,6 +82,7 @@ export function ColorRanges({ index={colorRanges.length - 1} validation={colorRangesValidity.last} accessor="end" + displayInfinity={displayInfinity} /> ) : null} diff --git a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item.tsx b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item.tsx index 99bb66b116647..33caaece5cfcf 100644 --- a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item.tsx +++ b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item.tsx @@ -52,6 +52,7 @@ export interface ColorRangesItemProps { continuity: PaletteContinuity; accessor: ColorRangeAccessor; validation?: ColorRangeValidation; + displayInfinity: boolean; } type ColorRangeItemMode = 'value' | 'auto' | 'edit'; @@ -67,10 +68,18 @@ const getMode = ( return (isLast ? checkIsMaxContinuity : checkIsMinContinuity)(continuity) ? 'auto' : 'edit'; }; -const getPlaceholderForAutoMode = (isLast: boolean) => +const getPlaceholderForAutoMode = (isLast: boolean, displayInfinity: boolean) => isLast - ? i18n.translate('coloring.dynamicColoring.customPalette.maxValuePlaceholder', { - defaultMessage: 'Max. value', + ? displayInfinity + ? i18n.translate('coloring.dynamicColoring.customPalette.extentPlaceholderInfinity', { + defaultMessage: 'Infinity', + }) + : i18n.translate('coloring.dynamicColoring.customPalette.maxValuePlaceholder', { + defaultMessage: 'Max. value', + }) + : displayInfinity + ? i18n.translate('coloring.dynamicColoring.customPalette.extentPlaceholderNegativeInfinity', { + defaultMessage: '-Infinity', }) : i18n.translate('coloring.dynamicColoring.customPalette.minValuePlaceholder', { defaultMessage: 'Min. value', @@ -102,6 +111,7 @@ export function ColorRangeItem({ validation, continuity, dispatch, + displayInfinity, }: ColorRangesItemProps) { const { dataBounds, palettes } = useContext(ColorRangesContext); const [popoverInFocus, setPopoverInFocus] = useState(false); @@ -220,7 +230,7 @@ export function ColorRangeItem({ } disabled={isDisabled} onChange={onValueChange} - placeholder={mode === 'auto' ? getPlaceholderForAutoMode(isLast) : ''} + placeholder={mode === 'auto' ? getPlaceholderForAutoMode(isLast, displayInfinity) : ''} append={getAppend(rangeType, mode)} onBlur={onLeaveFocus} data-test-subj={`lnsPalettePanel_dynamicColoring_range_value_${index}`} @@ -241,6 +251,7 @@ export function ColorRangeItem({ continuity={continuity} rangeType={rangeType} colorRanges={colorRanges} + displayInfinity={displayInfinity} dispatch={dispatch} accessor={accessor} /> diff --git a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item_buttons.tsx b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item_buttons.tsx index 41e1d56712b8c..e8f0d8269d0bd 100644 --- a/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item_buttons.tsx +++ b/packages/kbn-coloring/src/shared_components/coloring/color_ranges/color_ranges_item_buttons.tsx @@ -20,6 +20,7 @@ import { TooltipWrapper } from '../tooltip_wrapper'; import type { ColorRangesActions, ColorRange, ColorRangeAccessor } from './types'; import { ColorRangesContext } from './color_ranges_context'; +import { InfinityIcon } from '../assets/infinity'; export interface ColorRangesItemButtonProps { index: number; @@ -28,6 +29,7 @@ export interface ColorRangesItemButtonProps { continuity: PaletteContinuity; dispatch: Dispatch; accessor: ColorRangeAccessor; + displayInfinity: boolean; } const switchContinuity = (isLast: boolean, continuity: PaletteContinuity) => { @@ -117,6 +119,7 @@ export function ColorRangeAutoDetectButton({ continuity, dispatch, accessor, + displayInfinity, }: ColorRangesItemButtonProps) { const { dataBounds, palettes } = useContext(ColorRangesContext); const isLast = isLastItem(accessor); @@ -131,8 +134,16 @@ export function ColorRangeAutoDetectButton({ }, [continuity, dataBounds, dispatch, isLast, palettes]); const tooltipContent = isLast - ? i18n.translate('coloring.dynamicColoring.customPalette.useAutoMaxValue', { - defaultMessage: `Use maximum data value`, + ? displayInfinity + ? i18n.translate('coloring.dynamicColoring.customPalette.useAutoMaxValueInfinity', { + defaultMessage: `Use positive infinity`, + }) + : i18n.translate('coloring.dynamicColoring.customPalette.useAutoMaxValue', { + defaultMessage: `Use maximum data value`, + }) + : displayInfinity + ? i18n.translate('coloring.dynamicColoring.customPalette.useAutoMinValueInfinity', { + defaultMessage: `Use negative infinity`, }) : i18n.translate('coloring.dynamicColoring.customPalette.useAutoMinValue', { defaultMessage: `Use minimum data value`, @@ -141,7 +152,7 @@ export function ColorRangeAutoDetectButton({ return ( { const idPrefix = useMemo(() => htmlIdGenerator()(), []); const colorRangesToShow = toColorRanges( @@ -190,6 +192,9 @@ export const CustomizablePalette = ({ showExtraActions={showExtraActions} paletteConfiguration={localState.activePalette?.params} colorRanges={localState.colorRanges} + displayInfinity={ + displayInfinity && localState.activePalette.params?.rangeType !== 'percent' + } dispatch={dispatch} /> diff --git a/x-pack/plugins/lens/public/visualizations/legacy_metric/dimension_editor.tsx b/x-pack/plugins/lens/public/visualizations/legacy_metric/dimension_editor.tsx index 9dd478712d5d9..3771adf7299e1 100644 --- a/x-pack/plugins/lens/public/visualizations/legacy_metric/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/visualizations/legacy_metric/dimension_editor.tsx @@ -190,6 +190,7 @@ export function MetricDimensionEditor( palettes={props.paletteService} activePalette={activePalette} dataBounds={currentMinMax} + displayInfinity={true} setPalette={(newPalette) => { // if the new palette is not custom, replace the rangeMin with the artificial one if ( diff --git a/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.tsx b/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.tsx index 4439b22cd705f..de285da29b1e3 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.tsx @@ -400,6 +400,7 @@ function PrimaryMetricEditor(props: SubProps) { palettes={props.paletteService} activePalette={activePalette} dataBounds={currentMinMax} + displayInfinity={true} showRangeTypeSelector={Boolean( state.breakdownByAccessor || state.maxAccessor || From 1e82d0409d7bf3644d525490b3944e44ad486e44 Mon Sep 17 00:00:00 2001 From: Wafaa Nasr Date: Tue, 23 Aug 2022 18:00:58 +0200 Subject: [PATCH 31/41] Fix showing toast message when exporting a rule from the rule details page (#139209) * remove onSuccess prop from bulkExportRules call * change the test description Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../rule_actions_overflow/index.test.tsx | 25 +++++++++++++++++++ .../rules/rule_actions_overflow/index.tsx | 1 - 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx index 8e8c6f11975f5..8b736bad37b92 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.test.tsx @@ -11,6 +11,7 @@ import React from 'react'; import { goToRuleEditPage, executeRulesBulkAction, + bulkExportRules, } from '../../../pages/detection_engine/rules/all/actions'; import { RuleActionsOverflow } from '.'; import { mockRule } from '../../../pages/detection_engine/rules/all/__mocks__/mock'; @@ -33,6 +34,8 @@ jest.mock('../../../../common/lib/kibana', () => { jest.mock('../../../pages/detection_engine/rules/all/actions'); const executeRulesBulkActionMock = executeRulesBulkAction as jest.Mock; +const bulkExportRulesMock = bulkExportRules as jest.Mock; + const flushPromises = () => new Promise(setImmediate); describe('RuleActionsOverflow', () => { @@ -233,6 +236,28 @@ describe('RuleActionsOverflow', () => { }); describe('rules details export rule', () => { + test('should call export actions and display toast when export option is clicked', async () => { + bulkExportRulesMock.mockImplementation(() => Promise.resolve({})); + const wrapper = mount( + + ); + wrapper.find('[data-test-subj="rules-details-popover-button-icon"] button').simulate('click'); + wrapper.update(); + wrapper.find('[data-test-subj="rules-details-export-rule"] button').simulate('click'); + wrapper.update(); + await flushPromises(); + + expect(bulkExportRulesMock).toHaveBeenCalledWith( + expect.objectContaining({ action: 'export' }) + ); + expect(bulkExportRulesMock).toHaveBeenCalledWith( + expect.not.objectContaining({ onSuccess: expect.any }) + ); + }); test('it does not open the popover when rules-details-popover-button-icon is clicked and the user does not have permission', () => { const rule = mockRule('id'); const wrapper = mount( diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index 27b776e67c61f..b8e423827edce 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -111,7 +111,6 @@ const RuleActionsOverflowComponent = ({ closePopover(); await bulkExportRules({ action: BulkAction.export, - onSuccess: noop, search: { ids: [rule.id] }, toasts, }); From 81926f04fb3e6730eb7842e1d190fa15d171d74c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Tue, 23 Aug 2022 19:02:58 +0100 Subject: [PATCH 32/41] skip flaky suite (#139300) --- .../functional_with_es_ssl/apps/cases/attachment_framework.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/attachment_framework.ts b/x-pack/test/functional_with_es_ssl/apps/cases/attachment_framework.ts index 72ce196c1ae62..fcab559466a74 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/attachment_framework.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/attachment_framework.ts @@ -107,7 +107,8 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { }); }); - describe('Persistable state attachments', () => { + // FLAKY: https://github.com/elastic/kibana/issues/139300 + describe.skip('Persistable state attachments', () => { const getLensState = (dataViewId: string) => ({ title: '', visualizationType: 'lnsXY', From 3fcd94b28de701e70c56d53e76a2453ac524b0a7 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Tue, 23 Aug 2022 14:15:38 -0400 Subject: [PATCH 33/41] [Dashboard] Test Service Codeowners (#139309) Update .github/CODEOWNERS Co-authored-by: Hannah Mudge --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e6777e5e69f29..d4bf323f938a7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -183,6 +183,7 @@ x-pack/examples/files_example @elastic/kibana-app-services /src/plugins/controls/ @elastic/kibana-presentation /test/functional/apps/dashboard/ @elastic/kibana-presentation /test/functional/apps/dashboard_elements/ @elastic/kibana-presentation +/test/functional/services/dashboard/ @elastic/kibana-presentation /x-pack/plugins/canvas/ @elastic/kibana-presentation /x-pack/plugins/dashboard_enhanced/ @elastic/kibana-presentation /x-pack/test/functional/apps/canvas/ @elastic/kibana-presentation From 33241437b0ed400e9c28365471624191ca61f2f6 Mon Sep 17 00:00:00 2001 From: Karl Godard Date: Tue, 23 Aug 2022 11:52:12 -0700 Subject: [PATCH 34/41] [TTY Output] Zoom In/Out/Fit controls added to TTY Player. (#139253) * progress on fit to text feature * text sizer working guud * major improvements to search (handling of escape codes). Tests added for tty_text_sizer * field rename in mock data * lint fix Co-authored-by: Karl Godard --- .../plugins/session_view/common/constants.ts | 10 +- .../responses/session_view_io_events.mock.ts | 84 ++++++++++- .../common/types/process_tree/index.ts | 11 +- .../public/components/session_view/index.tsx | 4 +- .../components/tty_player/hooks.test.tsx | 15 +- .../public/components/tty_player/hooks.ts | 131 +++++++++++------- .../public/components/tty_player/index.tsx | 31 ++++- .../public/components/tty_player/styles.ts | 45 ++++-- .../components/tty_player/translations.ts | 19 +++ .../components/tty_player/xterm_search.ts | 7 +- .../components/tty_search_bar/index.test.tsx | 17 ++- .../components/tty_search_bar/index.tsx | 77 ++++++---- .../components/tty_text_sizer/index.test.tsx | 76 ++++++++++ .../components/tty_text_sizer/index.tsx | 89 ++++++++++++ .../components/tty_text_sizer/translations.ts | 19 +++ .../session_view/io_events/data.json | 74 +++++++++- 16 files changed, 580 insertions(+), 129 deletions(-) create mode 100644 x-pack/plugins/session_view/public/components/tty_player/translations.ts create mode 100644 x-pack/plugins/session_view/public/components/tty_text_sizer/index.test.tsx create mode 100644 x-pack/plugins/session_view/public/components/tty_text_sizer/index.tsx create mode 100644 x-pack/plugins/session_view/public/components/tty_text_sizer/translations.ts diff --git a/x-pack/plugins/session_view/common/constants.ts b/x-pack/plugins/session_view/common/constants.ts index 5bf0dc53701fc..538605bb591b0 100644 --- a/x-pack/plugins/session_view/common/constants.ts +++ b/x-pack/plugins/session_view/common/constants.ts @@ -43,7 +43,15 @@ export const ALERT_STATUS = { export const LOCAL_STORAGE_DISPLAY_OPTIONS_KEY = 'sessionView:displayOptions'; export const MOUSE_EVENT_PLACEHOLDER = { stopPropagation: () => undefined } as React.MouseEvent; export const DEBOUNCE_TIMEOUT = 500; -export const DEFAULT_TTY_PLAYSPEED_MS = 40; // milli seconds per line of tty output. +export const DEFAULT_TTY_PLAYSPEED_MS = 80; // milli seconds per line of tty output. +export const DEFAULT_TTY_FONT_SIZE = 11; + +// we split terminal output on both newlines and cursor movements. +export const TTY_LINE_SPLITTER_REGEX = /(\r?\n|\x1b\[\d+;\d+[Hf])/gi; + +// used when searching output +export const TTY_STRIP_CONTROL_CODES_REGEX = + /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/gi; // when showing the count of alerts in details panel tab, if the number // exceeds ALERT_COUNT_THRESHOLD we put a + next to it, e.g 999+ diff --git a/x-pack/plugins/session_view/common/mocks/responses/session_view_io_events.mock.ts b/x-pack/plugins/session_view/common/mocks/responses/session_view_io_events.mock.ts index 33b9ac56b035d..c14dccc2bc3d6 100644 --- a/x-pack/plugins/session_view/common/mocks/responses/session_view_io_events.mock.ts +++ b/x-pack/plugins/session_view/common/mocks/responses/session_view_io_events.mock.ts @@ -17,6 +17,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '1', @@ -30,7 +31,15 @@ export const sessionViewIOEventsMock: ProcessEventResults = { total_bytes_captured: 1024, total_bytes_skipped: 0, bytes_skipped: [], - text: "256\n,\n Some Companies Puppet instance\n | | | CentOS Stream release 8 on x86_64\n .=/ = = =| =| = === = Load average: 1.23, 1.01, 0.63\n | || || || || || | | | | \n /= = = =' =' =' ' =' Hostname ********\n \\ Type xyz\n o Datacenter ********\n Cluster ********\n\n\n\n\n,0 loaded units listed. Pass --all to see loaded but inactive units, too.\nTo show all installed unit files use 'systemctl list-unit-files'.\n", + text: "256\n,\n Some Companies Puppet instance\n | | | CentOS Stream release 8 on x86_64\n *********************** Load average: 1.23, 1.01, 0.63\n ************************ \n ************************ Hostname ********\n \\ Type xyz\n o Datacenter ********\n Cluster ********\n\n\n\n\n,0 loaded units listed. Pass --all to see loaded but inactive units, too.\nTo show all installed unit files use 'systemctl list-unit-files'.\n", + }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, }, }, }, @@ -44,6 +53,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '2', @@ -57,7 +67,15 @@ export const sessionViewIOEventsMock: ProcessEventResults = { total_bytes_captured: 1024, total_bytes_skipped: 0, bytes_skipped: [], - text: ',\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H"/usr/local/bin/galera_traffic_start.sh" [readonly] 14L, 397C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for setting the reject of queries in Galera\n\nmysql -h127.0.0.1 -P6033 -uroot -e "set global wsrep_reject_queries=\'NONE\'" 2>&1\nRC=$?\n\nif [[ $RC != 0 ]]; then\n >&2 echo "Failed to unset the reject of queries on Galera node, exiting."\n exit $RC\nelse\n echo "Successfully unset the reject of queries."\nfi\n\u001b[94m~ \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[24;1H~ \u001b[25;1H~ \u001b[26;1H~ \u001b[27;1H~ \u001b[28;1H~ \u001b[29;1H~ \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ \u001b[33;1H~ \u001b[34;1H~ \u001b[35;1H~ \u001b[36;1H~ \u001b[37;1H~ \u001b[38;1H~ \u001b[39;1H~ \u001b[40;1H~ \u001b[41;1H~ \u001b[42;1H~ \u001b[43;1H~ \u001b[44;1H~ \u001b[45;1H~ \u001b[46;1H~ \u001b[47;1H~ \u001b[48;1H~ \u001b[49;1H~ \u001b[50;1H~ \u001b[51;1H~ \u001b[52;1H~ \u001b[53;1H~ \u001b[54;1H~ \u001b[55;1H~ \u001b[56;1H~ \u001b[57;1H~ \u001b[58;1H~ \u001b[1;1H\u001b[?25h\u0007\u001b[?25l\u001b[m\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hq\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H"/usr/local/bin/galera_traffic_stop.sh" [readonly] 115L, 3570C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for rejecting connection on Galera cluster node, either gracefully or not,\n# depending on supplied arguments.\n\nfunction usage() {\n echo "\n This script disables DB connections to Galera node.\n The default is to stop them gracefully.\n\n Usage: $0 [-h] [-w ] [-s ] [-x]\n\n Options:\n -h Prints this help.\n -w Number of seconds for waiting to close the connections.\u001b[17;11HDefault value is to wait for mysql-wait_timeout.\n -s Sleep interval between connections checks.\n -x Kills all connections immediately. Other options are ignored."\n exit\n}\n', + text: ',\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H"/usr/local/bin/script_one.sh" [readonly] 14L, 397C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for setting the reject of queries in Mysql\n\nmysql -h127.0.0.1 -P6033 -uroot -e "set global wsrep_reject_queries=\'NONE\'" 2>&1\nRC=$?\n\nif [[ $RC != 0 ]]; then\n >&2 echo "Failed to unset the reject of queries on Mysql node, exiting."\n exit $RC\nelse\n echo "Successfully unset the reject of queries."\nfi\n\u001b[94m~ \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[24;1H~ \u001b[25;1H~ \u001b[26;1H~ \u001b[27;1H~ \u001b[28;1H~ \u001b[29;1H~ \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ \u001b[33;1H~ \u001b[34;1H~ \u001b[35;1H~ \u001b[36;1H~ \u001b[37;1H~ \u001b[38;1H~ \u001b[39;1H~ \u001b[40;1H~ \u001b[41;1H~ \u001b[42;1H~ \u001b[43;1H~ \u001b[44;1H~ \u001b[45;1H~ \u001b[46;1H~ \u001b[47;1H~ \u001b[48;1H~ \u001b[49;1H~ \u001b[50;1H~ \u001b[51;1H~ \u001b[52;1H~ \u001b[53;1H~ \u001b[54;1H~ \u001b[55;1H~ \u001b[56;1H~ \u001b[57;1H~ \u001b[58;1H~ \u001b[1;1H\u001b[?25h\u0007\u001b[?25l\u001b[m\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hq\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H"/usr/local/bin/script_two.sh" [readonly] 115L, 3570C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for rejecting connection on Mysql cluster node, either gracefully or not,\n# depending on supplied arguments.\n\nfunction usage() {\n echo "\n This script disables DB connections to Mysql node.\n The default is to stop them gracefully.\n\n Usage: $0 [-h] [-w ] [-s ] [-x]\n\n Options:\n -h Prints this help.\n -w Number of seconds for waiting to close the connections.\u001b[17;11HDefault value is to wait for mysql-wait_timeout.\n -s Sleep interval between connections checks.\n -x Kills all connections immediately. Other options are ignored."\n exit\n}\n', + }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, }, }, }, @@ -71,6 +89,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '2', @@ -84,7 +103,15 @@ export const sessionViewIOEventsMock: ProcessEventResults = { total_bytes_captured: 1024, total_bytes_skipped: 0, bytes_skipped: [], - text: '\nfunction get_number_db_connections() {\n # count current\n DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select count(1) from stats_mysql_processlist where user = \'$DB_USER\' and db like \'db\\_%\' escapee\u001b[26;1H \'\\\'")\n}\n\nfunction set_number_grace_seconds() {\n local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select variable_value from global_variables where variable_name = \'mysql-wait_timeout\'")\n GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n}\n\nfunction wait_for_connections() {\n local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\u001b[37;5Hecho "Waiting for connections to close for up to $GRACE_PERIOD seconds"\u001b[39;5Hfor i in $(seq 0 $number_of_loops); do\u001b[40;9Hget_number_db_connections\u001b[41;9Hif [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\u001b[42;13Hecho "No connection found for user $DB_USER to this node"\u001b[43;13Hbreak\u001b[44;9Helse\u001b[45;13Hecho "$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i"\u001b[46;13Hsleep $SLEEP_INTERVAL\u001b[47;9Hfi\n done\n}\n\nfunction parse_args() {\n while getopts \'hs:w:x\' opt; do\u001b[53;9Hcase "$opt" in\u001b[54;9Hh)\u001b[55;13Husage\u001b[56;13H;;\u001b[57;9Hs)\u001b[58;13Hif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\u001b[1;1H\u001b[?25h\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hset number\r\u001b[?25l\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on Galera cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo "\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to Galera node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m Default value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored."\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select count(1) from stats_mysql_processlist where user = \'$DB_USER\' and db like \'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m\' escape \'\\\'")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select variable_value from global_variables where variable_name = \'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout\'")\u001b[31;16H\u001b[K\u001b[32;1H\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \u001b[m\u001b[34;10H\u001b[K\u001b[35;1H\u001b[38;5;130m 33 \u001b[mfunction wait_for_connections() {\u001b[35;42H\u001b[K\u001b[36;1H\u001b[38;5;130m 34 \u001b[m local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\n\u001b[38;5;130m 35 \u001b[m\u001b[37;10H\u001b[K\u001b[38;1H\u001b[38;5;130m 36 \u001b[m echo "Waiting for connections to close for up to $GRACE_PERIOD seconds"\n\u001b[38;5;130m 37 \u001b[m\u001b[39;9H\u001b[K\u001b[40;1H\u001b[38;5;130m 38 \u001b[m for i in $(seq 0 $number_of_loops); do\n', + text: '\nfunction get_number_db_connections() {\n # count current\n DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select count(1) from stats_mysql_processlist where user = \'$DB_USER\' and db like \'db\\_%\' escapee\u001b[26;1H \'\\\'")\n}\n\nfunction set_number_grace_seconds() {\n local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select variable_value from global_variables where variable_name = \'mysql-wait_timeout\'")\n GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n}\n\nfunction wait_for_connections() {\n local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\u001b[37;5Hecho "Waiting for connections to close for up to $GRACE_PERIOD seconds"\u001b[39;5Hfor i in $(seq 0 $number_of_loops); do\u001b[40;9Hget_number_db_connections\u001b[41;9Hif [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\u001b[42;13Hecho "No connection found for user $DB_USER to this node"\u001b[43;13Hbreak\u001b[44;9Helse\u001b[45;13Hecho "$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i"\u001b[46;13Hsleep $SLEEP_INTERVAL\u001b[47;9Hfi\n done\n}\n\nfunction parse_args() {\n while getopts \'hs:w:x\' opt; do\u001b[53;9Hcase "$opt" in\u001b[54;9Hh)\u001b[55;13Husage\u001b[56;13H;;\u001b[57;9Hs)\u001b[58;13Hif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\u001b[1;1H\u001b[?25h\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hset number\r\u001b[?25l\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on Mysql cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo "\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to Mysql node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m Default value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored."\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select count(1) from stats_mysql_processlist where user = \'$DB_USER\' and db like \'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m\' escape \'\\\'")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select variable_value from global_variables where variable_name = \'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout\'")\u001b[31;16H\u001b[K\u001b[32;1H\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \u001b[m\u001b[34;10H\u001b[K\u001b[35;1H\u001b[38;5;130m 33 \u001b[mfunction wait_for_connections() {\u001b[35;42H\u001b[K\u001b[36;1H\u001b[38;5;130m 34 \u001b[m local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\n\u001b[38;5;130m 35 \u001b[m\u001b[37;10H\u001b[K\u001b[38;1H\u001b[38;5;130m 36 \u001b[m echo "Waiting for connections to close for up to $GRACE_PERIOD seconds"\n\u001b[38;5;130m 37 \u001b[m\u001b[39;9H\u001b[K\u001b[40;1H\u001b[38;5;130m 38 \u001b[m for i in $(seq 0 $number_of_loops); do\n', + }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, }, }, }, @@ -98,6 +125,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '2', @@ -113,6 +141,14 @@ export const sessionViewIOEventsMock: ProcessEventResults = { bytes_skipped: [], text: '\u001b[38;5;130m 39 \u001b[m get_number_db_connections\u001b[41;42H\u001b[K\u001b[42;1H\u001b[38;5;130m 40 \u001b[m if [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\u001b[42;60H\u001b[K\u001b[43;1H\u001b[38;5;130m 41 \u001b[m echo "No connection found for user $DB_USER to this node"\n\u001b[38;5;130m 42 \u001b[m \u001b[8Cbreak\n\u001b[38;5;130m 43 \u001b[m else\u001b[45;21H\u001b[K\u001b[46;1H\u001b[38;5;130m 44 \u001b[m echo "$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i"\n\u001b[38;5;130m 45 \u001b[m \u001b[10Csleep $SLEEP_INTERVAL\n\u001b[38;5;130m 46 \u001b[m\u001b[8Cfi\n\u001b[38;5;130m 47 \u001b[m done\n\u001b[38;5;130m 48 \u001b[m}\n\u001b[38;5;130m 49 \u001b[m\u001b[51;10H\u001b[K\u001b[52;1H\u001b[38;5;130m 50 \u001b[mfunction parse_args() {\u001b[52;33H\u001b[K\u001b[53;1H\u001b[38;5;130m 51 \u001b[m while getopts \'hs:w:x\' opt; do\n\u001b[38;5;130m 52 \u001b[m case "$opt" in\n\u001b[38;5;130m 53 \u001b[m h)\n\u001b[38;5;130m 54 \u001b[m usage\n\u001b[38;5;130m 55 \u001b[m \u001b[10C;;\n\u001b[38;5;130m 56 \u001b[m s)\u001b[58;19H\u001b[K\u001b[1;9H\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 58 \u001b[m\u001b[16C>&2 echo "Sleep interval (-s) must be a number"\n\u001b[38;5;130m 59 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 60 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 61 \u001b[m\u001b[12CARG_SLEEP_INTERVAL="$OPTARG"\n\u001b[38;5;130m 62 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 63 \u001b[m\u001b[8Cw)\n\u001b[38;5;130m 64 \u001b[m\u001b[12Cif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\n\u001b[38;5;130m 65 \u001b[m\u001b[16C>&2 echo "Wait timeout (-w) must be a number"\n\u001b[38;5;130m 66 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 67 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 68 \u001b[m\u001b[12CARG_GRACE_PERIOD="$OPTARG"\n\u001b[38;5;130m 69 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 70 \u001b[m\u001b[8Cx)\n\u001b[38;5;130m 71 \u001b[m\u001b[12CARG_KILL_IMMEDIATELY=1\n\u001b[38;5;130m 72 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 73 \u001b[m\u001b[8Cesac\n\u001b[38;5;130m 74 \u001b[m done\n\u001b[38;5;130m 75 \n 76 \u001b[m GRACE_PERIOD=${ARG_GRACE_PERIOD:--1}\n\u001b[38;5;130m 77 \u001b[m SLEEP_INTERVAL=${ARG_SLEEP_INTERVAL:-30}\n\u001b[38;5;130m 78 \u001b[m KILL_IMMEDIATELY=${ARG_KILL_IMMEDIATELY:-0}\n\u001b[38;5;130m 79 \u001b[m}\n\u001b[38;5;130m 80 \n 81 \u001b[mDB_USER="rolap01"\n\u001b[38;5;130m 82 \n 83 \u001b[mparse_args $@\n\u001b[38;5;130m 84 \n 85 \u001b[mif [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 86 \u001b[m echo "WARNING: Not waiting for connections to close gracefully"\n\u001b[38;5;130m 87 \u001b[m echo "Press any key to continue... wsrep_reject_queries will be set to \'ALL_KILL\'"\n\u001b[38;5;130m 88 \u001b[m read a\n\u001b[38;5;130m 89 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e "set global wsrep_reject_queries=\'ALL_KILL\'"\n\u001b[38;5;130m 90 \u001b[melse\n\u001b[38;5;130m 91 \u001b[m # Stop accepting queries in mariadb, do not kill opened connections\n\u001b[38;5;130m 92 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e "set global wsrep_reject_queries=\'ALL\'"\n\u001b[38;5;130m 93 \u001b[mfi\n\u001b[38;5;130m 94 \n 95 \u001b[mexit_code=$?\n', }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, + }, }, }, }, @@ -125,6 +161,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '2', @@ -138,7 +175,15 @@ export const sessionViewIOEventsMock: ProcessEventResults = { total_bytes_captured: 1024, total_bytes_skipped: 0, bytes_skipped: [], - text: '\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo "Failed to set the reject of queries on Galera node, exiting."\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo "Successfully stopped accepting queries."\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo "ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections."\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on Galera cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo "\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to Galera node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m\u001b[10CDefault value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored."\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select count(1) from stats_mysql_processlist where user = \'$DB_USER\' and db like \'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m\' escape \'\\\'")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select variable_value from global_variables where variable_name = \'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout\'")\n\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \n', + text: '\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo "Failed to set the reject of queries on Mysql node, exiting."\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo "Successfully stopped accepting queries."\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo "ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections."\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on Mysql cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo "\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to Mysql node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m\u001b[10CDefault value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored."\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select count(1) from stats_mysql_processlist where user = \'$DB_USER\' and db like \'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m\' escape \'\\\'")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e "select variable_value from global_variables where variable_name = \'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout\'")\n\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \n', + }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, }, }, }, @@ -152,6 +197,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '2', @@ -167,6 +213,14 @@ export const sessionViewIOEventsMock: ProcessEventResults = { bytes_skipped: [], text: ' 33 \u001b[mfunction wait_for_connections() {\n\u001b[38;5;130m 34 \u001b[m local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\n\u001b[38;5;130m 35 \n 36 \u001b[m echo "Waiting for connections to close for up to $GRACE_PERIOD seconds"\n\u001b[38;5;130m 37 \n 38 \u001b[m for i in $(seq 0 $number_of_loops); do\n\u001b[38;5;130m 39 \u001b[m\u001b[8Cget_number_db_connections\n\u001b[38;5;130m 40 \u001b[m\u001b[8Cif [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\n\u001b[38;5;130m 41 \u001b[m\u001b[12Cecho "No connection found for user $DB_USER to this node"\n\u001b[38;5;130m 42 \u001b[m\u001b[12Cbreak\n\u001b[38;5;130m 43 \u001b[m\u001b[8Celse\n\u001b[38;5;130m 44 \u001b[m\u001b[12Cecho "$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i"\n\u001b[38;5;130m 45 \u001b[m\u001b[12Csleep $SLEEP_INTERVAL\n\u001b[38;5;130m 46 \u001b[m\u001b[8Cfi\n\u001b[38;5;130m 47 \u001b[m done\n\u001b[38;5;130m 48 \u001b[m}\n\u001b[38;5;130m 49 \n 50 \u001b[mfunction parse_args() {\n\u001b[38;5;130m 51 \u001b[m while getopts \'hs:w:x\' opt; do\n\u001b[38;5;130m 52 \u001b[m\u001b[8Ccase "$opt" in\n\u001b[38;5;130m 53 \u001b[m\u001b[8Ch)\n\u001b[38;5;130m 54 \u001b[m\u001b[12Cusage\n\u001b[38;5;130m 55 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 56 \u001b[m\u001b[8Cs)\u001b[1;9H\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 58 \u001b[m\u001b[16C>&2 echo "Sleep interval (-s) must be a number"\n\u001b[38;5;130m 59 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 60 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 61 \u001b[m\u001b[12CARG_SLEEP_INTERVAL="$OPTARG"\n\u001b[38;5;130m 62 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 63 \u001b[m\u001b[8Cw)\n\u001b[38;5;130m 64 \u001b[m\u001b[12Cif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\n\u001b[38;5;130m 65 \u001b[m\u001b[16C>&2 echo "Wait timeout (-w) must be a number"\n\u001b[38;5;130m 66 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 67 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 68 \u001b[m\u001b[12CARG_GRACE_PERIOD="$OPTARG"\n\u001b[38;5;130m 69 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 70 \u001b[m\u001b[8Cx)\n\u001b[38;5;130m 71 \u001b[m\u001b[12CARG_KILL_IMMEDIATELY=1\n\u001b[38;5;130m 72 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 73 \u001b[m\u001b[8Cesac\n\u001b[38;5;130m 74 \u001b[m done\n\u001b[38;5;130m 75 \n 76 \u001b[m GRACE_PERIOD=${ARG_GRACE_PERIOD:--1}\n\u001b[38;5;130m 77 \u001b[m SLEEP_INTERVAL=${ARG_SLEEP_INTERVAL:-30}\n\u001b[38;5;130m 78 \u001b[m KILL_IMMEDIATELY=${ARG_KILL_IMMEDIATELY:-0}\n\u001b[38;5;130m 79 \u001b[m}\n\u001b[38;5;130m 80 \n 81 \u001b[mDB_USER="rolap01"\n\u001b[38;5;130m 82 \n 83 \u001b[mparse_args $@\n', }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, + }, }, }, }, @@ -179,6 +233,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '2', @@ -192,7 +247,15 @@ export const sessionViewIOEventsMock: ProcessEventResults = { total_bytes_captured: 1024, total_bytes_skipped: 0, bytes_skipped: [], - text: '\u001b[38;5;130m 84 \n 85 \u001b[mif [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 86 \u001b[m echo "WARNING: Not waiting for connections to close gracefully"\n\u001b[38;5;130m 87 \u001b[m echo "Press any key to continue... wsrep_reject_queries will be set to \'ALL_KILL\'"\n\u001b[38;5;130m 88 \u001b[m read a\n\u001b[38;5;130m 89 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e "set global wsrep_reject_queries=\'ALL_KILL\'"\n\u001b[38;5;130m 90 \u001b[melse\n\u001b[38;5;130m 91 \u001b[m # Stop accepting queries in mariadb, do not kill opened connections\n\u001b[38;5;130m 92 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e "set global wsrep_reject_queries=\'ALL\'"\n\u001b[38;5;130m 93 \u001b[mfi\n\u001b[38;5;130m 94 \n 95 \u001b[mexit_code=$?\n\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo "Failed to set the reject of queries on Galera node, exiting."\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo "Successfully stopped accepting queries."\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo "ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections."\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\nType :qa! and press to abandon all changes and exit Vim\u0007\u001b[58;9H\u001b[?25h\u0007\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hqa!\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001bkroot@staging-host:~\u001b\\\n', + text: '\u001b[38;5;130m 84 \n 85 \u001b[mif [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 86 \u001b[m echo "WARNING: Not waiting for connections to close gracefully"\n\u001b[38;5;130m 87 \u001b[m echo "Press any key to continue... wsrep_reject_queries will be set to \'ALL_KILL\'"\n\u001b[38;5;130m 88 \u001b[m read a\n\u001b[38;5;130m 89 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e "set global wsrep_reject_queries=\'ALL_KILL\'"\n\u001b[38;5;130m 90 \u001b[melse\n\u001b[38;5;130m 91 \u001b[m # Stop accepting queries in mariadb, do not kill opened connections\n\u001b[38;5;130m 92 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e "set global wsrep_reject_queries=\'ALL\'"\n\u001b[38;5;130m 93 \u001b[mfi\n\u001b[38;5;130m 94 \n 95 \u001b[mexit_code=$?\n\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo "Failed to set the reject of queries on Mysql node, exiting."\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo "Successfully stopped accepting queries."\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo "ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections."\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\nType :qa! and press to abandon all changes and exit Vim\u0007\u001b[58;9H\u001b[?25h\u0007\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hqa!\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001bkroot@staging-host:~\u001b\\\n', + }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, }, }, }, @@ -206,6 +269,7 @@ export const sessionViewIOEventsMock: ProcessEventResults = { message: 'hello world security', event: { action: 'text_output', + id: '1', }, process: { entity_id: '1', @@ -219,7 +283,15 @@ export const sessionViewIOEventsMock: ProcessEventResults = { total_bytes_captured: 1024, total_bytes_skipped: 0, bytes_skipped: [], - text: '\u001bkroot@staging-host:~\u001b\\\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\b\b\b\b\b\n\u001bkroot@staging-host:~\u001b\\\b\u001b[K\b\u001b[K\b\u001b[K\n,\n22/05/26 09:24:09 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/galera_traffic_start.sh\u0007\n22/05/26 09:25:32 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/galera_traffic_start.sh.sh.sh.sho.shp.sh\n22/05/26 09:30:08 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] exi\u0007\u0007\u0007exitlogout\n,\u001bec2-user@staging-host:~\u001b\\\n\u001bec2-user@staging-host:~\u001b\\\n,\n22/05/26 09:24:01 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] sudo -i\n22/05/26 10:11:37 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] exitlogout\n\n', + text: '\u001bkroot@staging-host:~\u001b\\\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\b\b\b\b\b\n\u001bkroot@staging-host:~\u001b\\\b\u001b[K\b\u001b[K\b\u001b[K\n,\n22/05/26 09:24:09 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/script_one.sh\u0007\n22/05/26 09:25:32 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/script_one.sh.sh.sh.sho.shp.sh\n22/05/26 09:30:08 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] exi\u0007\u0007\u0007exitlogout\n,\u001bec2-user@staging-host:~\u001b\\\n\u001bec2-user@staging-host:~\u001b\\\n,\n22/05/26 09:24:01 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] sudo -i\n22/05/26 10:11:37 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] exitlogout\n\n', + }, + tty: { + char_device: { + major: 4, + minor: 1, + }, + rows: 59, + columns: 173, }, }, }, diff --git a/x-pack/plugins/session_view/common/types/process_tree/index.ts b/x-pack/plugins/session_view/common/types/process_tree/index.ts index e620b654db16f..a2b40347f1b5f 100644 --- a/x-pack/plugins/session_view/common/types/process_tree/index.ts +++ b/x-pack/plugins/session_view/common/types/process_tree/index.ts @@ -60,16 +60,13 @@ export interface Teletype { major?: number; minor?: number; }; + rows?: number; + columns?: number; } -// used by tty_player component to split process.io.text into lines of IO export interface IOLine { - value?: string; - - // the following is only set client side for caching purposes - process_name?: string; - process_entity_id?: string; - process_entity_cursor?: string; + event: ProcessEvent; + value: string; } export interface IOFields { diff --git a/x-pack/plugins/session_view/public/components/session_view/index.tsx b/x-pack/plugins/session_view/public/components/session_view/index.tsx index e2d795283c7ce..921a3f7ce8b9c 100644 --- a/x-pack/plugins/session_view/public/components/session_view/index.tsx +++ b/x-pack/plugins/session_view/public/components/session_view/index.tsx @@ -133,8 +133,8 @@ export const SessionView = ({ } = useFetchSessionViewAlerts(sessionEntityId, investigatedAlertId); const handleRefresh = useCallback(() => { - refetch({ refetchPage: (page, index, allPages) => allPages.length - 1 === index }); - refetchAlerts({ refetchPage: (page, index, allPages) => allPages.length - 1 === index }); + refetch({ refetchPage: (_page, index, allPages) => allPages.length - 1 === index }); + refetchAlerts({ refetchPage: (_page, index, allPages) => allPages.length - 1 === index }); }, [refetch, refetchAlerts]); const alerts = useMemo(() => { diff --git a/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx b/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx index 23f81d7941439..fb90951874385 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx +++ b/x-pack/plugins/session_view/public/components/tty_player/hooks.test.tsx @@ -8,7 +8,9 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { sessionViewIOEventsMock } from '../../../common/mocks/responses/session_view_io_events.mock'; import { useIOLines, useXtermPlayer, XtermPlayerDeps } from './hooks'; import { ProcessEventsPage } from '../../../common/types/process_tree'; -import { DEFAULT_TTY_PLAYSPEED_MS } from '../../../common/constants'; +import { DEFAULT_TTY_FONT_SIZE, DEFAULT_TTY_PLAYSPEED_MS } from '../../../common/constants'; + +const VIM_LINE_START = 19; describe('TTYPlayer/hooks', () => { beforeAll(() => { @@ -66,10 +68,11 @@ describe('TTYPlayer/hooks', () => { initialProps = { ref: mockRef, isPlaying: false, + setIsPlaying: jest.fn(), lines, hasNextPage: false, fetchNextPage: () => null, - isFullscreen: false, + fontSize: DEFAULT_TTY_FONT_SIZE, }; }); @@ -88,7 +91,7 @@ describe('TTYPlayer/hooks', () => { expect(currentLine).toBe(0); act(() => { - seekToLine(17); // line where vim output starts + seekToLine(VIM_LINE_START); // line where vim output starts }); jest.advanceTimersByTime(100); @@ -102,14 +105,14 @@ describe('TTYPlayer/hooks', () => { }); act(() => { - xTermResult.current.seekToLine(17); // line where vim output starts + xTermResult.current.seekToLine(VIM_LINE_START); // line where vim output starts }); jest.advanceTimersByTime(100); const { terminal, currentLine } = xTermResult.current; - expect(currentLine).toBe(17); + expect(currentLine).toBe(VIM_LINE_START); expect(terminal.buffer.active.getLine(0)?.translateToString(true)).toBe('#!/bin/env bash'); }); @@ -152,7 +155,7 @@ describe('TTYPlayer/hooks', () => { act(() => { jest.advanceTimersByTime(DEFAULT_TTY_PLAYSPEED_MS * initialProps.lines.length + 100); }); - expect(result.current.currentLine).toBe(initialProps.lines.length); + expect(result.current.currentLine).toBe(initialProps.lines.length - 1); }); it('will allow a plain text search highlight on the last line printed', async () => { diff --git a/x-pack/plugins/session_view/public/components/tty_player/hooks.ts b/x-pack/plugins/session_view/public/components/tty_player/hooks.ts index e122a2dbd0c11..0138775199c6d 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/hooks.ts +++ b/x-pack/plugins/session_view/public/components/tty_player/hooks.ts @@ -6,13 +6,16 @@ */ import { Terminal } from 'xterm'; import 'xterm/css/xterm.css'; -import { FitAddon } from 'xterm-addon-fit'; import { useMemo, useState, useEffect, useCallback } from 'react'; import { useInfiniteQuery } from '@tanstack/react-query'; import { CoreStart } from '@kbn/core/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { SearchAddon } from './xterm_search'; import { useEuiTheme } from '../../hooks'; + +// eslint-disable-next-line @kbn/imports/no_boundary_crossing +import { sessionViewIOEventsMock } from '../../../common/mocks/responses/session_view_io_events.mock'; + import { IOLine, ProcessEvent, @@ -24,8 +27,12 @@ import { IO_EVENTS_PER_PAGE, QUERY_KEY_IO_EVENTS, DEFAULT_TTY_PLAYSPEED_MS, + DEFAULT_TTY_FONT_SIZE, + TTY_LINE_SPLITTER_REGEX, } from '../../../common/constants'; +const MOCK_DEBUG = false; // This code will be removed once we have an agent to test with. + export const useFetchIOEvents = (sessionEntityId: string) => { const { http } = useKibana().services; const cachingKeys = useMemo(() => [QUERY_KEY_IO_EVENTS, sessionEntityId], [sessionEntityId]); @@ -41,13 +48,18 @@ export const useFetchIOEvents = (sessionEntityId: string) => { }, }); + if (MOCK_DEBUG) { + res.events = sessionViewIOEventsMock.events; + res.total = res.events?.length || 0; + } + const events = res.events?.map((event: any) => event._source as ProcessEvent) ?? []; return { events, cursor, total: res.total }; }, { getNextPageParam: (lastPage) => { - if (lastPage.events.length >= IO_EVENTS_PER_PAGE) { + if (!MOCK_DEBUG && lastPage.events.length >= IO_EVENTS_PER_PAGE) { return { cursor: lastPage.events[lastPage.events.length - 1]['@timestamp'], }; @@ -77,9 +89,21 @@ export const useIOLines = (pages: ProcessEventsPage[] | undefined) => { return pages.reduce((previous, current) => { if (current.events) { current.events.forEach((event) => { - if (event?.process?.io?.text) { - const data: IOLine[] = event.process.io.text.split(/\n\r?/).map((line) => { + const { process } = event; + if (process?.io?.text !== undefined) { + const splitLines = process.io.text.split(TTY_LINE_SPLITTER_REGEX); + const combinedLines = [splitLines[0]]; + + // delimiters e.g \r\n or cursor movements are merged with their line text + // we start on an odd number so that cursor movements happen at the start of each line + // this is needed for the search to work accurately + for (let i = 1; i < splitLines.length - 1; i = i + 2) { + combinedLines.push(splitLines[i] + splitLines[i + 1]); + } + + const data: IOLine[] = combinedLines.map((line) => { return { + event, // pointer to the event so it's easy to look up other details for the line value: line, }; }); @@ -99,85 +123,94 @@ export const useIOLines = (pages: ProcessEventsPage[] | undefined) => { export interface XtermPlayerDeps { ref: React.RefObject; isPlaying: boolean; + setIsPlaying(value: boolean): void; lines: IOLine[]; + fontSize: number; hasNextPage?: boolean; fetchNextPage?: () => void; - isFullscreen?: boolean; } export const useXtermPlayer = ({ ref, isPlaying, + setIsPlaying, lines, + fontSize, hasNextPage, fetchNextPage, - isFullscreen, }: XtermPlayerDeps) => { const { euiTheme } = useEuiTheme(); const { font, colors } = euiTheme; const [currentLine, setCurrentLine] = useState(0); - const [userSeeked, setUserSeeked] = useState(false); const [playSpeed] = useState(DEFAULT_TTY_PLAYSPEED_MS); // potentially configurable + const tty = lines?.[currentLine]?.event.process?.tty; - const [terminal, fitAddon, searchAddon] = useMemo(() => { + const [terminal, searchAddon] = useMemo(() => { const term = new Terminal({ theme: { - background: 'rgba(0,0,0,0)', selection: colors.warning, }, fontFamily: font.familyCode, - fontSize: 11, - allowTransparency: true, + fontSize: DEFAULT_TTY_FONT_SIZE, + scrollback: 0, + convertEol: true, }); - const fitInstance = new FitAddon(); const searchInstance = new SearchAddon(); - - term.loadAddon(fitInstance); term.loadAddon(searchInstance); - return [term, fitInstance, searchInstance]; - }, [colors, font]); + return [term, searchInstance]; + }, [font, colors]); useEffect(() => { - if (ref.current) { + if (ref.current && !terminal.element) { terminal.open(ref.current); } }, [terminal, ref]); - useEffect(() => { - // isFullscreen check is there just to avoid the necessary "unnecessary" react-hook dep - // When isFullscreen changes, e.g goes from false to true and vice versa, we need to call fit. - if (isFullscreen !== undefined) { - fitAddon.fit(); - } - }, [isFullscreen, fitAddon]); - const render = useCallback( - (lineNumber: number) => { + (lineNumber: number, clear: boolean) => { if (lines.length === 0) { return; } let linesToPrint; - if (userSeeked) { - linesToPrint = lines.slice(0, lineNumber); + if (clear) { + linesToPrint = lines.slice(0, lineNumber + 1); + terminal.reset(); terminal.clear(); - setUserSeeked(false); } else { linesToPrint = [lines[lineNumber]]; } linesToPrint.forEach((line, index) => { if (line?.value !== undefined) { - terminal.writeln(line.value); + terminal.write(line.value); } }); }, - [terminal, lines, userSeeked] + [terminal, lines] ); + useEffect(() => { + const fontChanged = terminal.getOption('fontSize') !== fontSize; + const ttyChanged = tty && (terminal.rows !== tty?.rows || terminal.cols !== tty?.columns); + + if (fontChanged) { + terminal.setOption('fontSize', fontSize); + } + + if (tty?.rows && tty?.columns && ttyChanged) { + terminal.resize(tty.columns, tty.rows); + } + + if (fontChanged || ttyChanged) { + // clear and rerender + render(currentLine, true); + } + }, [currentLine, fontSize, terminal, render, tty]); + useEffect(() => { if (isPlaying) { const timer = setTimeout(() => { @@ -185,29 +218,32 @@ export const useXtermPlayer = ({ return; } - if (currentLine < lines.length) { + if (currentLine < lines.length - 1) { setCurrentLine(currentLine + 1); } + + render(currentLine, false); + + if (hasNextPage && fetchNextPage && currentLine === lines.length - 1) { + fetchNextPage(); + } }, playSpeed); return () => { - clearInterval(timer); + clearTimeout(timer); }; } - }, [lines, currentLine, isPlaying, playSpeed]); + }, [lines, currentLine, isPlaying, playSpeed, render, hasNextPage, fetchNextPage]); - useEffect(() => { - render(currentLine); - - if (hasNextPage && fetchNextPage && currentLine === lines.length - 1) { - fetchNextPage(); - } - }, [fetchNextPage, currentLine, lines, render, hasNextPage]); + const seekToLine = useCallback( + (index) => { + setCurrentLine(index); + setIsPlaying(false); - const seekToLine = useCallback((line) => { - setUserSeeked(true); - setCurrentLine(line); - }, []); + render(index, true); + }, + [setIsPlaying, render] + ); const search = useCallback( (query: string, startCol: number) => { @@ -216,15 +252,10 @@ export const useXtermPlayer = ({ [searchAddon] ); - const fit = useCallback(() => { - fitAddon.fit(); - }, [fitAddon]); - return { terminal, currentLine, seekToLine, search, - fit, }; }; diff --git a/x-pack/plugins/session_view/public/components/tty_player/index.tsx b/x-pack/plugins/session_view/public/components/tty_player/index.tsx index 48dbf82441e42..7d3656d8ba7b7 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/index.tsx +++ b/x-pack/plugins/session_view/public/components/tty_player/index.tsx @@ -7,6 +7,7 @@ import React, { useRef, useState, useCallback, ChangeEvent, MouseEvent } from 'react'; import { EuiPanel, EuiRange, EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elastic/eui'; import { TTYSearchBar } from '../tty_search_bar'; +import { TTYTextSizer } from '../tty_text_sizer'; import { useStyles } from './styles'; import { useFetchIOEvents, useIOLines, useXtermPlayer } from './hooks'; @@ -16,22 +17,31 @@ export interface TTYPlayerDeps { isFullscreen: boolean; } +const DEFAULT_FONT_SIZE = 11; + export const TTYPlayer = ({ sessionEntityId, onClose, isFullscreen }: TTYPlayerDeps) => { - const styles = useStyles(); - const ref = useRef(null); + const ref = useRef(null); + const scrollRef = useRef(null); const { data, fetchNextPage, hasNextPage } = useFetchIOEvents(sessionEntityId); const lines = useIOLines(data?.pages); + + const [fontSize, setFontSize] = useState(DEFAULT_FONT_SIZE); const [isPlaying, setIsPlaying] = useState(false); + const { search, currentLine, seekToLine } = useXtermPlayer({ ref, isPlaying, + setIsPlaying, lines, + fontSize, hasNextPage, fetchNextPage, - isFullscreen, }); + const tty = lines?.[currentLine]?.event?.process?.tty; + const styles = useStyles(tty); + const onLineChange = useCallback( (event: ChangeEvent | MouseEvent) => { const line = parseInt((event?.target as HTMLInputElement).value || '0', 10); @@ -65,7 +75,10 @@ export const TTYPlayer = ({ sessionEntityId, onClose, isFullscreen }: TTYPlayerD -

+ +
+
+
{/* the following will be replaced by a new component */} + + +
diff --git a/x-pack/plugins/session_view/public/components/tty_player/styles.ts b/x-pack/plugins/session_view/public/components/tty_player/styles.ts index c4061c8a64dce..e1d18e3075027 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/styles.ts +++ b/x-pack/plugins/session_view/public/components/tty_player/styles.ts @@ -7,15 +7,14 @@ import { useMemo } from 'react'; import { CSSObject, css } from '@emotion/react'; -import { transparentize, useEuiScrollBar } from '@elastic/eui'; +import { transparentize } from '@elastic/eui'; import { useEuiTheme } from '../../hooks'; +import { Teletype } from '../../../common/types/process_tree'; -export const useStyles = () => { +export const useStyles = (tty?: Teletype) => { const { euiTheme } = useEuiTheme(); - const euiScrollBar = useEuiScrollBar(); - const cached = useMemo(() => { - const { size, colors, border } = euiTheme; + const { size, font, colors, border } = euiTheme; const container: CSSObject = { position: 'absolute', @@ -23,6 +22,7 @@ export const useStyles = () => { width: '100%', height: '100%', overflow: 'hidden', + zIndex: 10, borderRadius: size.s, backgroundColor: colors.ink, '.euiRangeLevel--warning': { @@ -36,20 +36,47 @@ export const useStyles = () => { }, }; + const windowBoundsColor = transparentize(colors.ghost, 0.6); + const terminal: CSSObject = { + minHeight: '100%', + '.xterm': css` + display: inline-block; + `, + '.xterm-screen': css` + overflow-y: visible; + border: ${border.width.thin} dotted ${windowBoundsColor}; + border-top: 0; + border-left: 0; + box-sizing: content-box; + `, + }; + + if (tty?.rows) { + terminal['.xterm-screen:after'] = css` + position: absolute; + right: ${size.s}; + top: ${size.s}; + content: '${tty?.columns}x${tty?.rows}'; + color: ${windowBoundsColor}; + font-family: ${font.familyCode}; + font-size: ${size.m}; + `; + } + + const scrollPane: CSSObject = { width: '100%', height: 'calc(100% - 142px)', - '.xterm-viewport': css` - ${euiScrollBar} - `, border: border.thin, + overflow: 'auto', }; return { container, terminal, + scrollPane, }; - }, [euiScrollBar, euiTheme]); + }, [tty, euiTheme]); return cached; }; diff --git a/x-pack/plugins/session_view/public/components/tty_player/translations.ts b/x-pack/plugins/session_view/public/components/tty_player/translations.ts new file mode 100644 index 0000000000000..244a5a355b0ec --- /dev/null +++ b/x-pack/plugins/session_view/public/components/tty_player/translations.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; + +export const BETA = i18n.translate('xpack.sessionView.beta', { + defaultMessage: 'Beta', +}); + +export const REFRESH_SESSION = i18n.translate('xpack.sessionView.refreshSession', { + defaultMessage: 'Refresh session', +}); + +export const OPEN_TTY_PLAYER = i18n.translate('xpack.sessionView.openTTYPlayer', { + defaultMessage: 'Open TTY player', +}); diff --git a/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts b/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts index 258920319676c..3c430d691e3f7 100644 --- a/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts +++ b/x-pack/plugins/session_view/public/components/tty_player/xterm_search.ts @@ -94,7 +94,7 @@ export class SearchAddon implements ITerminalAddon { } if (searchOptions?.lastLineOnly) { - startRow = this._terminal.buffer.active.cursorY - 1; + startRow = this._terminal.buffer.active.cursorY; startCol = searchOptions?.startCol || 0; } @@ -176,10 +176,9 @@ export class SearchAddon implements ITerminalAddon { // Start from selection start if there is a selection startRow = currentSelection.startRow; startCol = currentSelection.startColumn; - } - - if (searchOptions?.lastLineOnly) { + } else if (searchOptions?.lastLineOnly) { startRow = this._terminal.buffer.active.cursorY - 1; + startCol = this._terminal.cols; } this._initLinesCache(); diff --git a/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx b/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx index 4545acf1a4578..77e9c4576c565 100644 --- a/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx +++ b/x-pack/plugins/session_view/public/components/tty_search_bar/index.test.tsx @@ -56,7 +56,9 @@ describe('TTYSearchBar component', () => { // there is a slight delay in the seek in xtermjs, so we wait 100ms before trying to highlight a result. await new Promise((r) => setTimeout(r, 100)); - expect(props.xTermSearchFn).toHaveBeenCalledTimes(1); + expect(props.xTermSearchFn).toHaveBeenCalledTimes(2); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(1, '', 0); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '-h', 6); }); it('calls seekToline and xTermSearchFn when currentMatch changes', async () => { @@ -76,12 +78,13 @@ describe('TTYSearchBar component', () => { // two calls, first instance -h is at line 22, 2nd at line 42 expect(props.seekToLine).toHaveBeenCalledTimes(2); - expect(props.seekToLine).toHaveBeenNthCalledWith(1, 22); - expect(props.seekToLine).toHaveBeenNthCalledWith(2, 42); + expect(props.seekToLine).toHaveBeenNthCalledWith(1, 24); + expect(props.seekToLine).toHaveBeenNthCalledWith(2, 94); - expect(props.xTermSearchFn).toHaveBeenCalledTimes(2); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(1, '-h', 6); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '-h', 13); + expect(props.xTermSearchFn).toHaveBeenCalledTimes(3); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(1, '', 0); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '-h', 6); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(3, '-h', 13); }); it('calls xTermSearchFn with empty query when search is cleared', async () => { @@ -97,6 +100,6 @@ describe('TTYSearchBar component', () => { userEvent.click(renderResult.getByTestId('clearSearchButton')); await new Promise((r) => setTimeout(r, 100)); - expect(props.xTermSearchFn).toHaveBeenNthCalledWith(2, '', 0); + expect(props.xTermSearchFn).toHaveBeenNthCalledWith(3, '', 0); }); }); diff --git a/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx b/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx index af60bdf664f9d..e5081a217dec1 100644 --- a/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx +++ b/x-pack/plugins/session_view/public/components/tty_search_bar/index.tsx @@ -4,9 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect, useMemo, useState, useCallback } from 'react'; +import React, { useMemo, useState, useCallback } from 'react'; import { SessionViewSearchBar } from '../session_view_search_bar'; import { IOLine } from '../../../common/types/process_tree'; +import { TTY_STRIP_CONTROL_CODES_REGEX } from '../../../common/constants'; interface SearchResult { line: IOLine; @@ -24,50 +25,71 @@ export const TTYSearchBar = ({ lines, seekToLine, xTermSearchFn }: TTYSearchBarD const [currentMatch, setCurrentMatch] = useState(null); const [searchQuery, setSearchQuery] = useState(''); - useEffect(() => { - if (currentMatch) { - const goToLine = lines.indexOf(currentMatch.line); - seekToLine(goToLine); - } + const jumpToMatch = useCallback( + (match) => { + if (match) { + const goToLine = lines.indexOf(match.line); + seekToLine(goToLine); + } - const timeout = setTimeout(() => { - return xTermSearchFn(searchQuery, currentMatch?.index || 0); - }, 100); + const timeout = setTimeout(() => { + return xTermSearchFn(searchQuery, match?.index || 0); + }, 100); - return () => { - clearTimeout(timeout); - }; - }, [currentMatch, searchQuery, lines, xTermSearchFn, seekToLine]); + return () => { + clearTimeout(timeout); + }; + }, + [lines, seekToLine, xTermSearchFn, searchQuery] + ); const searchResults = useMemo(() => { - if (searchQuery) { - const matches: SearchResult[] = []; + const matches: SearchResult[] = []; + if (searchQuery) { lines.reduce((previous: SearchResult[], current: IOLine) => { if (current.value) { + // check for cursor movement at the start of the line + const cursorMovement = current.value.match(/^\x1b\[\d+;(\d+)(H|d)/); const regex = new RegExp(searchQuery.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'ig'); - const lineMatches = current.value.matchAll(regex); + const lineMatches = current.value + .replace(TTY_STRIP_CONTROL_CODES_REGEX, '') + .replace(/^\r?\n/, '') + .matchAll(regex); + if (lineMatches) { for (const match of lineMatches) { - previous.push({ line: current, match: match[0], index: match.index || 0 }); + let matchOffset = 0; + + if (cursorMovement) { + // the column position 1 based e.g \x1b[39;5H means row 39 column 5 + matchOffset = parseInt(cursorMovement[1], 10) - 3; + } + + previous.push({ + line: current, + match: match[0], + index: matchOffset + (match.index || 0), + }); } } } return previous; }, matches); + } - if (matches.length > 0) { - setCurrentMatch(matches[0]); - } else { - setCurrentMatch(null); - } - - return matches; + if (matches.length > 0) { + const firstMatch = matches[0]; + setCurrentMatch(firstMatch); + jumpToMatch(firstMatch); + } else { + setCurrentMatch(null); + xTermSearchFn('', 0); } - return []; - }, [searchQuery, lines]); + return matches; + }, [searchQuery, lines, jumpToMatch, xTermSearchFn]); const onSearch = useCallback((query) => { setSearchQuery(query); @@ -80,9 +102,10 @@ export const TTYSearchBar = ({ lines, seekToLine, xTermSearchFn }: TTYSearchBarD if (match && currentMatch !== match) { setCurrentMatch(match); + jumpToMatch(match); } }, - [currentMatch, searchResults] + [jumpToMatch, currentMatch, searchResults] ); return ( diff --git a/x-pack/plugins/session_view/public/components/tty_text_sizer/index.test.tsx b/x-pack/plugins/session_view/public/components/tty_text_sizer/index.test.tsx new file mode 100644 index 0000000000000..ec9e8ffd3cab2 --- /dev/null +++ b/x-pack/plugins/session_view/public/components/tty_text_sizer/index.test.tsx @@ -0,0 +1,76 @@ +/* + * 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 userEvent from '@testing-library/user-event'; +import { AppContextTestRender, createAppRootMockRenderer } from '../../test'; +import { DEFAULT_TTY_FONT_SIZE } from '../../../common/constants'; +import { TTYTextSizer, TTYTextSizerDeps } from '.'; + +describe('TTYTextSizer component', () => { + let render: () => ReturnType; + let renderResult: ReturnType; + let mockedContext: AppContextTestRender; + let props: TTYTextSizerDeps; + + beforeEach(() => { + mockedContext = createAppRootMockRenderer(); + + props = { + tty: { + rows: 24, + columns: 80, + }, + containerHeight: 200, + fontSize: DEFAULT_TTY_FONT_SIZE, + onFontSizeChanged: jest.fn(), + }; + }); + + it('mounts and renders the text sizer controls', async () => { + renderResult = mockedContext.render(); + expect(renderResult.queryByTestId('sessionView:TTYTextSizer')).toBeTruthy(); + }); + + it('emits a fontSize which will fit the container when ZoomFit clicked', async () => { + renderResult = mockedContext.render(); + + const zoomFitBtn = renderResult.queryByTestId('sessionView:TTYZoomFit'); + + if (zoomFitBtn) { + userEvent.click(zoomFitBtn); + } + + expect(props.onFontSizeChanged).toHaveBeenCalledTimes(1); + expect(props.onFontSizeChanged).toHaveBeenCalledWith(6.41025641025641); + }); + + it('emits a larger fontSize when zoom in clicked', async () => { + renderResult = mockedContext.render(); + + const zoomInBtn = renderResult.queryByTestId('sessionView:TTYZoomIn'); + + if (zoomInBtn) { + userEvent.click(zoomInBtn); + } + + expect(props.onFontSizeChanged).toHaveBeenCalledTimes(1); + expect(props.onFontSizeChanged).toHaveBeenCalledWith(DEFAULT_TTY_FONT_SIZE + 1); + }); + + it('emits a smaller fontSize when zoom out clicked', async () => { + renderResult = mockedContext.render(); + + const zoomOutBtn = renderResult.queryByTestId('sessionView:TTYZoomOut'); + + if (zoomOutBtn) { + userEvent.click(zoomOutBtn); + } + + expect(props.onFontSizeChanged).toHaveBeenCalledTimes(1); + expect(props.onFontSizeChanged).toHaveBeenCalledWith(DEFAULT_TTY_FONT_SIZE - 1); + }); +}); diff --git a/x-pack/plugins/session_view/public/components/tty_text_sizer/index.tsx b/x-pack/plugins/session_view/public/components/tty_text_sizer/index.tsx new file mode 100644 index 0000000000000..463dbbbf80f69 --- /dev/null +++ b/x-pack/plugins/session_view/public/components/tty_text_sizer/index.tsx @@ -0,0 +1,89 @@ +/* + * 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, { useCallback, useMemo } from 'react'; +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { Teletype } from '../../../common/types/process_tree'; +import { DEFAULT_TTY_FONT_SIZE } from '../../../common/constants'; +import { ZOOM_IN, ZOOM_FIT, ZOOM_OUT } from './translations'; + +export interface TTYTextSizerDeps { + tty?: Teletype; + containerHeight: number; + fontSize: number; + onFontSizeChanged(newSize: number): void; +} + +const LINE_HEIGHT_SCALE_RATIO = 1.3; +const MINIMUM_FONT_SIZE = 2; +const MAXIMUM_FONT_SIZE = 20; + +export const TTYTextSizer = ({ + tty, + containerHeight, + fontSize, + onFontSizeChanged, +}: TTYTextSizerDeps) => { + const onFitFontSize = useMemo(() => { + if (tty?.rows && containerHeight) { + const lineHeight = DEFAULT_TTY_FONT_SIZE * LINE_HEIGHT_SCALE_RATIO; + const desiredHeight = tty.rows * lineHeight; + return DEFAULT_TTY_FONT_SIZE * (containerHeight / desiredHeight); + } + + return DEFAULT_TTY_FONT_SIZE; + }, [containerHeight, tty?.rows]); + + const onFit = useCallback(() => { + if (fontSize === onFitFontSize || onFitFontSize > DEFAULT_TTY_FONT_SIZE) { + onFontSizeChanged(DEFAULT_TTY_FONT_SIZE); + } else { + onFontSizeChanged(onFitFontSize); + } + }, [fontSize, onFontSizeChanged, onFitFontSize]); + + const onZoomOut = useCallback(() => { + onFontSizeChanged(Math.max(MINIMUM_FONT_SIZE, fontSize - 1)); + }, [fontSize, onFontSizeChanged]); + + const onZoomIn = useCallback(() => { + onFontSizeChanged(Math.min(MAXIMUM_FONT_SIZE, fontSize + 1)); + }, [fontSize, onFontSizeChanged]); + + return ( + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/session_view/public/components/tty_text_sizer/translations.ts b/x-pack/plugins/session_view/public/components/tty_text_sizer/translations.ts new file mode 100644 index 0000000000000..0bec7775d43c5 --- /dev/null +++ b/x-pack/plugins/session_view/public/components/tty_text_sizer/translations.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; + +export const ZOOM_IN = i18n.translate('xpack.sessionView.zoomIn', { + defaultMessage: 'Zoom in', +}); + +export const ZOOM_FIT = i18n.translate('xpack.sessionView.zoomFit', { + defaultMessage: 'Zoom fit', +}); + +export const ZOOM_OUT = i18n.translate('xpack.sessionView.zoomOut', { + defaultMessage: 'Zoom out', +}); diff --git a/x-pack/test/functional/es_archives/session_view/io_events/data.json b/x-pack/test/functional/es_archives/session_view/io_events/data.json index 0cf008aa6834c..a9553169850f1 100644 --- a/x-pack/test/functional/es_archives/session_view/io_events/data.json +++ b/x-pack/test/functional/es_archives/session_view/io_events/data.json @@ -45,6 +45,14 @@ "total_bytes_skipped": 0, "bytes_skipped": [], "text": "256\n,\n Some host somewhere in the cloud\n | | | CentOS Stream release 8 on x86_64\n .Load average: 1.23, 1.01, 0.63\n\nHostname ********\nType xyz\n o Datacenter ********\n Cluster ********\n\n\n\n\n,0 loaded units listed. Pass --all to see loaded but inactive units, too.\nTo show all installed unit files use 'systemctl list-unit-files'.\n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } @@ -74,7 +82,15 @@ "total_bytes_captured": 1024, "total_bytes_skipped": 0, "bytes_skipped": [], - "text": ",\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H\"/usr/local/bin/galera_traffic_start.sh\" [readonly] 14L, 397C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for setting the reject of queries in Galera\n\nmysql -h127.0.0.1 -P6033 -uroot -e \"set global wsrep_reject_queries='NONE'\" 2>&1\nRC=$?\n\nif [[ $RC != 0 ]]; then\n >&2 echo \"Failed to unset the reject of queries on Galera node, exiting.\"\n exit $RC\nelse\n echo \"Successfully unset the reject of queries.\"\nfi\n\u001b[94m~ \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[24;1H~ \u001b[25;1H~ \u001b[26;1H~ \u001b[27;1H~ \u001b[28;1H~ \u001b[29;1H~ \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ \u001b[33;1H~ \u001b[34;1H~ \u001b[35;1H~ \u001b[36;1H~ \u001b[37;1H~ \u001b[38;1H~ \u001b[39;1H~ \u001b[40;1H~ \u001b[41;1H~ \u001b[42;1H~ \u001b[43;1H~ \u001b[44;1H~ \u001b[45;1H~ \u001b[46;1H~ \u001b[47;1H~ \u001b[48;1H~ \u001b[49;1H~ \u001b[50;1H~ \u001b[51;1H~ \u001b[52;1H~ \u001b[53;1H~ \u001b[54;1H~ \u001b[55;1H~ \u001b[56;1H~ \u001b[57;1H~ \u001b[58;1H~ \u001b[1;1H\u001b[?25h\u0007\u001b[?25l\u001b[m\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hq\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H\"/usr/local/bin/galera_traffic_stop.sh\" [readonly] 115L, 3570C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for rejecting connection on Galera cluster node, either gracefully or not,\n# depending on supplied arguments.\n\nfunction usage() {\n echo \"\n This script disables DB connections to Galera node.\n The default is to stop them gracefully.\n\n Usage: $0 [-h] [-w ] [-s ] [-x]\n\n Options:\n -h Prints this help.\n -w Number of seconds for waiting to close the connections.\u001b[17;11HDefault value is to wait for mysql-wait_timeout.\n -s Sleep interval between connections checks.\n -x Kills all connections immediately. Other options are ignored.\"\n exit\n}\n" + "text": ",\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H\"/usr/local/bin/script_one.sh\" [readonly] 14L, 397C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for setting the reject of queries in MySQL\n\nmysql -h127.0.0.1 -P6033 -uroot -e \"set global wsrep_reject_queries='NONE'\" 2>&1\nRC=$?\n\nif [[ $RC != 0 ]]; then\n >&2 echo \"Failed to unset the reject of queries on MySQL node, exiting.\"\n exit $RC\nelse\n echo \"Successfully unset the reject of queries.\"\nfi\n\u001b[94m~ \u001b[16;1H~ \u001b[17;1H~ \u001b[18;1H~ \u001b[19;1H~ \u001b[20;1H~ \u001b[21;1H~ \u001b[22;1H~ \u001b[23;1H~ \u001b[24;1H~ \u001b[25;1H~ \u001b[26;1H~ \u001b[27;1H~ \u001b[28;1H~ \u001b[29;1H~ \u001b[30;1H~ \u001b[31;1H~ \u001b[32;1H~ \u001b[33;1H~ \u001b[34;1H~ \u001b[35;1H~ \u001b[36;1H~ \u001b[37;1H~ \u001b[38;1H~ \u001b[39;1H~ \u001b[40;1H~ \u001b[41;1H~ \u001b[42;1H~ \u001b[43;1H~ \u001b[44;1H~ \u001b[45;1H~ \u001b[46;1H~ \u001b[47;1H~ \u001b[48;1H~ \u001b[49;1H~ \u001b[50;1H~ \u001b[51;1H~ \u001b[52;1H~ \u001b[53;1H~ \u001b[54;1H~ \u001b[55;1H~ \u001b[56;1H~ \u001b[57;1H~ \u001b[58;1H~ \u001b[1;1H\u001b[?25h\u0007\u001b[?25l\u001b[m\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hq\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001b[?2004h\u001b[?1049h\u001b[22;0;0t\u001b[?1h\u001b=\u001b[?2004h\u001b[1;59r\u001b[?12h\u001b[?12l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[?25l\u001b[59;1H\"/usr/local/bin/galera_traffic_stop.sh\" [readonly] 115L, 3570C\u001b[1;1H#!/bin/env bash\n# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\n# Script for rejecting connection on MySQL cluster node, either gracefully or not,\n# depending on supplied arguments.\n\nfunction usage() {\n echo \"\n This script disables DB connections to MySQL node.\n The default is to stop them gracefully.\n\n Usage: $0 [-h] [-w ] [-s ] [-x]\n\n Options:\n -h Prints this help.\n -w Number of seconds for waiting to close the connections.\u001b[17;11HDefault value is to wait for mysql-wait_timeout.\n -s Sleep interval between connections checks.\n -x Kills all connections immediately. Other options are ignored.\"\n exit\n}\n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } @@ -104,7 +120,15 @@ "total_bytes_captured": 1024, "total_bytes_skipped": 0, "bytes_skipped": [], - "text": "\nfunction get_number_db_connections() {\n # count current\n DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select count(1) from stats_mysql_processlist where user = '$DB_USER' and db like 'db\\_%' escapee\u001b[26;1H '\\'\")\n}\n\nfunction set_number_grace_seconds() {\n local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select variable_value from global_variables where variable_name = 'mysql-wait_timeout'\")\n GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n}\n\nfunction wait_for_connections() {\n local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\u001b[37;5Hecho \"Waiting for connections to close for up to $GRACE_PERIOD seconds\"\u001b[39;5Hfor i in $(seq 0 $number_of_loops); do\u001b[40;9Hget_number_db_connections\u001b[41;9Hif [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\u001b[42;13Hecho \"No connection found for user $DB_USER to this node\"\u001b[43;13Hbreak\u001b[44;9Helse\u001b[45;13Hecho \"$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i\"\u001b[46;13Hsleep $SLEEP_INTERVAL\u001b[47;9Hfi\n done\n}\n\nfunction parse_args() {\n while getopts 'hs:w:x' opt; do\u001b[53;9Hcase \"$opt\" in\u001b[54;9Hh)\u001b[55;13Husage\u001b[56;13H;;\u001b[57;9Hs)\u001b[58;13Hif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\u001b[1;1H\u001b[?25h\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hset number\r\u001b[?25l\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on Galera cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo \"\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to Galera node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m Default value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored.\"\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select count(1) from stats_mysql_processlist where user = '$DB_USER' and db like 'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m' escape '\\'\")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select variable_value from global_variables where variable_name = 'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout'\")\u001b[31;16H\u001b[K\u001b[32;1H\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \u001b[m\u001b[34;10H\u001b[K\u001b[35;1H\u001b[38;5;130m 33 \u001b[mfunction wait_for_connections() {\u001b[35;42H\u001b[K\u001b[36;1H\u001b[38;5;130m 34 \u001b[m local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\n\u001b[38;5;130m 35 \u001b[m\u001b[37;10H\u001b[K\u001b[38;1H\u001b[38;5;130m 36 \u001b[m echo \"Waiting for connections to close for up to $GRACE_PERIOD seconds\"\n\u001b[38;5;130m 37 \u001b[m\u001b[39;9H\u001b[K\u001b[40;1H\u001b[38;5;130m 38 \u001b[m for i in $(seq 0 $number_of_loops); do\n" + "text": "\nfunction get_number_db_connections() {\n # count current\n DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select count(1) from stats_mysql_processlist where user = '$DB_USER' and db like 'db\\_%' escapee\u001b[26;1H '\\'\")\n}\n\nfunction set_number_grace_seconds() {\n local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select variable_value from global_variables where variable_name = 'mysql-wait_timeout'\")\n GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n}\n\nfunction wait_for_connections() {\n local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\u001b[37;5Hecho \"Waiting for connections to close for up to $GRACE_PERIOD seconds\"\u001b[39;5Hfor i in $(seq 0 $number_of_loops); do\u001b[40;9Hget_number_db_connections\u001b[41;9Hif [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\u001b[42;13Hecho \"No connection found for user $DB_USER to this node\"\u001b[43;13Hbreak\u001b[44;9Helse\u001b[45;13Hecho \"$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i\"\u001b[46;13Hsleep $SLEEP_INTERVAL\u001b[47;9Hfi\n done\n}\n\nfunction parse_args() {\n while getopts 'hs:w:x' opt; do\u001b[53;9Hcase \"$opt\" in\u001b[54;9Hh)\u001b[55;13Husage\u001b[56;13H;;\u001b[57;9Hs)\u001b[58;13Hif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\u001b[1;1H\u001b[?25h\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hset number\r\u001b[?25l\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on MySQL cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo \"\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to MySQL node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m Default value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored.\"\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select count(1) from stats_mysql_processlist where user = '$DB_USER' and db like 'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m' escape '\\'\")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select variable_value from global_variables where variable_name = 'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout'\")\u001b[31;16H\u001b[K\u001b[32;1H\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \u001b[m\u001b[34;10H\u001b[K\u001b[35;1H\u001b[38;5;130m 33 \u001b[mfunction wait_for_connections() {\u001b[35;42H\u001b[K\u001b[36;1H\u001b[38;5;130m 34 \u001b[m local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\n\u001b[38;5;130m 35 \u001b[m\u001b[37;10H\u001b[K\u001b[38;1H\u001b[38;5;130m 36 \u001b[m echo \"Waiting for connections to close for up to $GRACE_PERIOD seconds\"\n\u001b[38;5;130m 37 \u001b[m\u001b[39;9H\u001b[K\u001b[40;1H\u001b[38;5;130m 38 \u001b[m for i in $(seq 0 $number_of_loops); do\n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } @@ -135,6 +159,14 @@ "total_bytes_skipped": 0, "bytes_skipped": [], "text": "\u001b[38;5;130m 39 \u001b[m get_number_db_connections\u001b[41;42H\u001b[K\u001b[42;1H\u001b[38;5;130m 40 \u001b[m if [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\u001b[42;60H\u001b[K\u001b[43;1H\u001b[38;5;130m 41 \u001b[m echo \"No connection found for user $DB_USER to this node\"\n\u001b[38;5;130m 42 \u001b[m \u001b[8Cbreak\n\u001b[38;5;130m 43 \u001b[m else\u001b[45;21H\u001b[K\u001b[46;1H\u001b[38;5;130m 44 \u001b[m echo \"$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i\"\n\u001b[38;5;130m 45 \u001b[m \u001b[10Csleep $SLEEP_INTERVAL\n\u001b[38;5;130m 46 \u001b[m\u001b[8Cfi\n\u001b[38;5;130m 47 \u001b[m done\n\u001b[38;5;130m 48 \u001b[m}\n\u001b[38;5;130m 49 \u001b[m\u001b[51;10H\u001b[K\u001b[52;1H\u001b[38;5;130m 50 \u001b[mfunction parse_args() {\u001b[52;33H\u001b[K\u001b[53;1H\u001b[38;5;130m 51 \u001b[m while getopts 'hs:w:x' opt; do\n\u001b[38;5;130m 52 \u001b[m case \"$opt\" in\n\u001b[38;5;130m 53 \u001b[m h)\n\u001b[38;5;130m 54 \u001b[m usage\n\u001b[38;5;130m 55 \u001b[m \u001b[10C;;\n\u001b[38;5;130m 56 \u001b[m s)\u001b[58;19H\u001b[K\u001b[1;9H\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 58 \u001b[m\u001b[16C>&2 echo \"Sleep interval (-s) must be a number\"\n\u001b[38;5;130m 59 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 60 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 61 \u001b[m\u001b[12CARG_SLEEP_INTERVAL=\"$OPTARG\"\n\u001b[38;5;130m 62 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 63 \u001b[m\u001b[8Cw)\n\u001b[38;5;130m 64 \u001b[m\u001b[12Cif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\n\u001b[38;5;130m 65 \u001b[m\u001b[16C>&2 echo \"Wait timeout (-w) must be a number\"\n\u001b[38;5;130m 66 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 67 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 68 \u001b[m\u001b[12CARG_GRACE_PERIOD=\"$OPTARG\"\n\u001b[38;5;130m 69 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 70 \u001b[m\u001b[8Cx)\n\u001b[38;5;130m 71 \u001b[m\u001b[12CARG_KILL_IMMEDIATELY=1\n\u001b[38;5;130m 72 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 73 \u001b[m\u001b[8Cesac\n\u001b[38;5;130m 74 \u001b[m done\n\u001b[38;5;130m 75 \n 76 \u001b[m GRACE_PERIOD=${ARG_GRACE_PERIOD:--1}\n\u001b[38;5;130m 77 \u001b[m SLEEP_INTERVAL=${ARG_SLEEP_INTERVAL:-30}\n\u001b[38;5;130m 78 \u001b[m KILL_IMMEDIATELY=${ARG_KILL_IMMEDIATELY:-0}\n\u001b[38;5;130m 79 \u001b[m}\n\u001b[38;5;130m 80 \n 81 \u001b[mDB_USER=\"rolap01\"\n\u001b[38;5;130m 82 \n 83 \u001b[mparse_args $@\n\u001b[38;5;130m 84 \n 85 \u001b[mif [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 86 \u001b[m echo \"WARNING: Not waiting for connections to close gracefully\"\n\u001b[38;5;130m 87 \u001b[m echo \"Press any key to continue... wsrep_reject_queries will be set to 'ALL_KILL'\"\n\u001b[38;5;130m 88 \u001b[m read a\n\u001b[38;5;130m 89 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e \"set global wsrep_reject_queries='ALL_KILL'\"\n\u001b[38;5;130m 90 \u001b[melse\n\u001b[38;5;130m 91 \u001b[m # Stop accepting queries in mariadb, do not kill opened connections\n\u001b[38;5;130m 92 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e \"set global wsrep_reject_queries='ALL'\"\n\u001b[38;5;130m 93 \u001b[mfi\n\u001b[38;5;130m 94 \n 95 \u001b[mexit_code=$?\n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } @@ -164,7 +196,15 @@ "total_bytes_captured": 1024, "total_bytes_skipped": 0, "bytes_skipped": [], - "text": "\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo \"Failed to set the reject of queries on Galera node, exiting.\"\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo \"Successfully stopped accepting queries.\"\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo \"ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections.\"\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on Galera cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo \"\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to Galera node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m\u001b[10CDefault value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored.\"\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select count(1) from stats_mysql_processlist where user = '$DB_USER' and db like 'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m' escape '\\'\")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select variable_value from global_variables where variable_name = 'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout'\")\n\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \n" + "text": "\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo \"Failed to set the reject of queries on MySQL node, exiting.\"\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo \"Successfully stopped accepting queries.\"\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo \"ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections.\"\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 1 \u001b[m#!/bin/env bash\n\u001b[38;5;130m 2 \u001b[m# Copyright (C) 2022, ********(R) Corporation. All rights reserved.\n\u001b[38;5;130m 3 \n 4 \u001b[m# Script for rejecting connection on MySQL cluster node, either gracefully or not,\n\u001b[38;5;130m 5 \u001b[m# depending on supplied arguments.\n\u001b[38;5;130m 6 \n 7 \u001b[mfunction usage() {\n\u001b[38;5;130m 8 \u001b[m echo \"\n\u001b[38;5;130m 9 \u001b[m This script disables DB connections to MySQL node.\n\u001b[38;5;130m 10 \u001b[m The default is to stop them gracefully.\n\u001b[38;5;130m 11 \n 12 \u001b[m Usage: $0 [-h] [-w ] [-s ] [-x]\n\u001b[38;5;130m 13 \n 14 \u001b[m Options:\n\u001b[38;5;130m 15 \u001b[m -h Prints this help.\n\u001b[38;5;130m 16 \u001b[m -w Number of seconds for waiting to close the connections.\n\u001b[38;5;130m 17 \u001b[m\u001b[10CDefault value is to wait for mysql-wait_timeout.\n\u001b[38;5;130m 18 \u001b[m -s Sleep interval between connections checks.\n\u001b[38;5;130m 19 \u001b[m -x Kills all connections immediately. Other options are ignored.\"\n\u001b[38;5;130m 20 \u001b[m exit\n\u001b[38;5;130m 21 \u001b[m}\n\u001b[38;5;130m 22 \n 23 \u001b[mfunction get_number_db_connections() {\n\u001b[38;5;130m 24 \u001b[m # count current\n\u001b[38;5;130m 25 \u001b[m DB_CONNECTIONS_NUMBER=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select count(1) from stats_mysql_processlist where user = '$DB_USER' and db like 'db\\_%%\u001b[26;1H\u001b[38;5;130m \u001b[m' escape '\\'\")\n\u001b[38;5;130m 26 \u001b[m}\n\u001b[38;5;130m 27 \n 28 \u001b[mfunction set_number_grace_seconds() {\n\u001b[38;5;130m 29 \u001b[m local mysql_wait_timeout_ms=$(mysql -h127.0.0.1 -P6032 -uadmin -N --silent -e \"select variable_value from global_variables where variable_name = 'mysql-wait_timm\u001b[31;1H\u001b[38;5;130m \u001b[meout'\")\n\u001b[38;5;130m 30 \u001b[m GRACE_PERIOD=$((($mysql_wait_timeout_ms+1000-1)/1000))\n\u001b[38;5;130m 31 \u001b[m}\n\u001b[38;5;130m 32 \n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } @@ -195,6 +235,14 @@ "total_bytes_skipped": 0, "bytes_skipped": [], "text": " 33 \u001b[mfunction wait_for_connections() {\n\u001b[38;5;130m 34 \u001b[m local number_of_loops=$(((($GRACE_PERIOD+$SLEEP_INTERVAL-1)/$SLEEP_INTERVAL)))\n\u001b[38;5;130m 35 \n 36 \u001b[m echo \"Waiting for connections to close for up to $GRACE_PERIOD seconds\"\n\u001b[38;5;130m 37 \n 38 \u001b[m for i in $(seq 0 $number_of_loops); do\n\u001b[38;5;130m 39 \u001b[m\u001b[8Cget_number_db_connections\n\u001b[38;5;130m 40 \u001b[m\u001b[8Cif [[ $DB_CONNECTIONS_NUMBER -eq 0 ]]; then\n\u001b[38;5;130m 41 \u001b[m\u001b[12Cecho \"No connection found for user $DB_USER to this node\"\n\u001b[38;5;130m 42 \u001b[m\u001b[12Cbreak\n\u001b[38;5;130m 43 \u001b[m\u001b[8Celse\n\u001b[38;5;130m 44 \u001b[m\u001b[12Cecho \"$DB_CONNECTIONS_NUMBER connection(s) found, waiting for ${SLEEP_INTERVAL}s, round $i\"\n\u001b[38;5;130m 45 \u001b[m\u001b[12Csleep $SLEEP_INTERVAL\n\u001b[38;5;130m 46 \u001b[m\u001b[8Cfi\n\u001b[38;5;130m 47 \u001b[m done\n\u001b[38;5;130m 48 \u001b[m}\n\u001b[38;5;130m 49 \n 50 \u001b[mfunction parse_args() {\n\u001b[38;5;130m 51 \u001b[m while getopts 'hs:w:x' opt; do\n\u001b[38;5;130m 52 \u001b[m\u001b[8Ccase \"$opt\" in\n\u001b[38;5;130m 53 \u001b[m\u001b[8Ch)\n\u001b[38;5;130m 54 \u001b[m\u001b[12Cusage\n\u001b[38;5;130m 55 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 56 \u001b[m\u001b[8Cs)\u001b[1;9H\u001b[?25h\u001b[?25l\u001b[27m\u001b[29m\u001b[m\u001b[H\u001b[2J\u001b[1;1H\u001b[38;5;130m 58 \u001b[m\u001b[16C>&2 echo \"Sleep interval (-s) must be a number\"\n\u001b[38;5;130m 59 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 60 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 61 \u001b[m\u001b[12CARG_SLEEP_INTERVAL=\"$OPTARG\"\n\u001b[38;5;130m 62 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 63 \u001b[m\u001b[8Cw)\n\u001b[38;5;130m 64 \u001b[m\u001b[12Cif ! [[ $OPTARG =~ ^[0-9]+$ ]]; then\n\u001b[38;5;130m 65 \u001b[m\u001b[16C>&2 echo \"Wait timeout (-w) must be a number\"\n\u001b[38;5;130m 66 \u001b[m\u001b[16Cexit 1\n\u001b[38;5;130m 67 \u001b[m\u001b[12Cfi\n\u001b[38;5;130m 68 \u001b[m\u001b[12CARG_GRACE_PERIOD=\"$OPTARG\"\n\u001b[38;5;130m 69 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 70 \u001b[m\u001b[8Cx)\n\u001b[38;5;130m 71 \u001b[m\u001b[12CARG_KILL_IMMEDIATELY=1\n\u001b[38;5;130m 72 \u001b[m\u001b[12C;;\n\u001b[38;5;130m 73 \u001b[m\u001b[8Cesac\n\u001b[38;5;130m 74 \u001b[m done\n\u001b[38;5;130m 75 \n 76 \u001b[m GRACE_PERIOD=${ARG_GRACE_PERIOD:--1}\n\u001b[38;5;130m 77 \u001b[m SLEEP_INTERVAL=${ARG_SLEEP_INTERVAL:-30}\n\u001b[38;5;130m 78 \u001b[m KILL_IMMEDIATELY=${ARG_KILL_IMMEDIATELY:-0}\n\u001b[38;5;130m 79 \u001b[m}\n\u001b[38;5;130m 80 \n 81 \u001b[mDB_USER=\"rolap01\"\n\u001b[38;5;130m 82 \n 83 \u001b[mparse_args $@\n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } @@ -224,7 +272,15 @@ "total_bytes_captured": 1024, "total_bytes_skipped": 0, "bytes_skipped": [], - "text": "\u001b[38;5;130m 84 \n 85 \u001b[mif [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 86 \u001b[m echo \"WARNING: Not waiting for connections to close gracefully\"\n\u001b[38;5;130m 87 \u001b[m echo \"Press any key to continue... wsrep_reject_queries will be set to 'ALL_KILL'\"\n\u001b[38;5;130m 88 \u001b[m read a\n\u001b[38;5;130m 89 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e \"set global wsrep_reject_queries='ALL_KILL'\"\n\u001b[38;5;130m 90 \u001b[melse\n\u001b[38;5;130m 91 \u001b[m # Stop accepting queries in mariadb, do not kill opened connections\n\u001b[38;5;130m 92 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e \"set global wsrep_reject_queries='ALL'\"\n\u001b[38;5;130m 93 \u001b[mfi\n\u001b[38;5;130m 94 \n 95 \u001b[mexit_code=$?\n\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo \"Failed to set the reject of queries on Galera node, exiting.\"\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo \"Successfully stopped accepting queries.\"\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo \"ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections.\"\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\nType :qa! and press to abandon all changes and exit Vim\u0007\u001b[58;9H\u001b[?25h\u0007\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hqa!\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001bkroot@staging-host:~\u001b\\\n" + "text": "\u001b[38;5;130m 84 \n 85 \u001b[mif [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 86 \u001b[m echo \"WARNING: Not waiting for connections to close gracefully\"\n\u001b[38;5;130m 87 \u001b[m echo \"Press any key to continue... wsrep_reject_queries will be set to 'ALL_KILL'\"\n\u001b[38;5;130m 88 \u001b[m read a\n\u001b[38;5;130m 89 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e \"set global wsrep_reject_queries='ALL_KILL'\"\n\u001b[38;5;130m 90 \u001b[melse\n\u001b[38;5;130m 91 \u001b[m # Stop accepting queries in mariadb, do not kill opened connections\n\u001b[38;5;130m 92 \u001b[m mysql -h127.0.0.1 -P3306 -uroot -e \"set global wsrep_reject_queries='ALL'\"\n\u001b[38;5;130m 93 \u001b[mfi\n\u001b[38;5;130m 94 \n 95 \u001b[mexit_code=$?\n\u001b[38;5;130m 96 \u001b[mif [[ $exit_code != 0 ]]; then\n\u001b[38;5;130m 97 \u001b[m >&2 echo \"Failed to set the reject of queries on MySQL node, exiting.\"\n\u001b[38;5;130m 98 \u001b[m exit $exit_code\n\u001b[38;5;130m 99 \u001b[melse\n\u001b[38;5;130m 100 \u001b[m echo \"Successfully stopped accepting queries.\"\n\u001b[38;5;130m 101 \u001b[m if [[ $KILL_IMMEDIATELY == 1 ]]; then\n\u001b[38;5;130m 102 \u001b[m\u001b[8Cexit\n\u001b[38;5;130m 103 \u001b[m fi\n\u001b[38;5;130m 104 \u001b[mfi\n\u001b[38;5;130m 105 \n 106 \u001b[mif [[ $GRACE_PERIOD == -1 ]]; then\n\u001b[38;5;130m 107 \u001b[m set_number_grace_seconds\n\u001b[38;5;130m 108 \u001b[mfi\n\u001b[38;5;130m 109 \n 110 \u001b[mwait_for_connections\n\u001b[38;5;130m 111 \u001b[mif [[ $DB_CONNECTIONS_NUMBER != 0 ]]; then\n\u001b[38;5;130m 112 \u001b[m get_number_db_connections\n\u001b[38;5;130m 113 \u001b[m >&2 echo \"ERROR: There are still $DB_CONNECTIONS_NUMBER opened DB connections.\"\n\u001b[38;5;130m 114 \u001b[m exit 3\n\u001b[38;5;130m 115 \u001b[mfi\b\b\u001b[?25h\u001b[?25l\nType :qa! and press to abandon all changes and exit Vim\u0007\u001b[58;9H\u001b[?25h\u0007\u001b[?25l\u001b[59;1H\u001b[K\u001b[59;1H:\u001b[?2004h\u001b[?25hqa!\r\u001b[?25l\u001b[?2004l\u001b[59;1H\u001b[K\u001b[59;1H\u001b[?2004l\u001b[?1l\u001b>\u001b[?25h\u001b[?1049l\u001b[23;0;0t,\u001bkroot@staging-host:~\u001b\\\n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } @@ -254,7 +310,15 @@ "total_bytes_captured": 1024, "total_bytes_skipped": 0, "bytes_skipped": [], - "text": "\u001bkroot@staging-host:~\u001b\\\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\b\b\b\b\b\n\u001bkroot@staging-host:~\u001b\\\b\u001b[K\b\u001b[K\b\u001b[K\n,\n22/05/26 09:24:09 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/galera_traffic_start.sh\u0007\n22/05/26 09:25:32 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/galera_traffic_start.sh.sh.sh.sho.shp.sh\n22/05/26 09:30:08 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] exi\u0007\u0007\u0007exitlogout\n,\u001bec2-user@staging-host:~\u001b\\\n\u001bec2-user@staging-host:~\u001b\\\n,\n22/05/26 09:24:01 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] sudo -i\n22/05/26 10:11:37 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] exitlogout\n\n" + "text": "\u001bkroot@staging-host:~\u001b\\\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\u001b[1P\b\b\b\b\b\b\b\b\b\n\u001bkroot@staging-host:~\u001b\\\b\u001b[K\b\u001b[K\b\u001b[K\n,\n22/05/26 09:24:09 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/script_one.sh\u0007\n22/05/26 09:25:32 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] vi -R /usr/local/bin/script_one.sh.sh.sh.sho.shp.sh\n22/05/26 09:30:08 rack-na/cl_md (md), Cluster ********\n[root@staging-host:~] exi\u0007\u0007\u0007exitlogout\n,\u001bec2-user@staging-host:~\u001b\\\n\u001bec2-user@staging-host:~\u001b\\\n,\n22/05/26 09:24:01 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] sudo -i\n22/05/26 10:11:37 rack-na/cl_md (md), Cluster ********\n[ec2-user@staging-host:~] exitlogout\n\n" + }, + "tty": { + "char_device": { + "major": 4, + "minor": 1 + }, + "rows": 66, + "columns": 280 } } } From 6f0bfcfd0d528441fdeeb4d2b33936a20e6e82f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 23 Aug 2022 20:56:19 +0200 Subject: [PATCH 35/41] [APM] Use datastreams for API tests (#139283) --- .../client/apm_synthtrace_kibana_client.ts | 7 +- .../kbn-apm-synthtrace/src/lib/apm/index.ts | 2 + .../common/bootstrap_apm_synthtrace.ts | 34 + .../test/apm_api_integration/common/config.ts | 23 +- .../apm_api_integration/common/registry.ts | 1 - .../common/utils/create_and_run_apm_ml_job.ts | 8 +- .../tests/alerts/anomaly_alert.spec.ts | 2 +- .../tests/anomalies/anomaly_charts.spec.ts | 5 +- .../tests/cold_start/cold_start.spec.ts | 230 +++-- .../cold_start_by_transaction_name.spec.ts | 2 +- .../tests/data_view/static.spec.ts | 118 ++- .../dependencies/dependency_metrics.spec.ts | 295 +++---- .../tests/dependencies/metadata.spec.ts | 2 +- .../dependencies/service_dependencies.spec.ts | 84 +- .../dependencies/top_dependencies.spec.ts | 154 ++-- .../tests/dependencies/top_operations.spec.ts | 236 +++-- .../tests/dependencies/top_spans.spec.ts | 2 +- .../dependencies/upstream_services.spec.ts | 36 +- .../tests/error_rate/service_apis.spec.ts | 2 +- .../tests/error_rate/service_maps.spec.ts | 148 ++-- .../tests/errors/distribution.spec.ts | 190 ++-- .../tests/errors/error_group_list.spec.ts | 162 ++-- .../tests/errors/group_id.spec.ts | 46 +- .../top_erroneous_transactions.spec.ts | 212 +++-- .../top_errors_main_stats.spec.ts | 75 +- .../infrastructure_attributes.spec.ts | 52 +- .../tests/latency/service_apis.spec.ts | 2 +- .../tests/latency/service_maps.spec.ts | 109 ++- .../observability_overview.spec.ts | 154 ++-- .../service_nodes/get_service_nodes.spec.ts | 56 +- .../instances_main_statistics.spec.ts | 2 +- .../error_groups_detailed_statistics.spec.ts | 214 +++-- .../error_groups_main_statistics.spec.ts | 69 +- .../get_service_node_metadata.spec.ts | 2 +- .../service_details/service_details.spec.ts | 130 ++- .../service_icons/service_icons.spec.ts | 48 +- .../sorted_and_filtered_services.spec.ts | 158 ++-- .../tests/services/throughput.spec.ts | 360 ++++---- .../tests/services/top_services.spec.ts | 4 +- .../agent_configuration.spec.ts | 108 ++- .../tests/span_links/span_links.spec.ts | 832 +++++++++--------- .../throughput/dependencies_apis.spec.ts | 254 +++--- .../tests/throughput/service_apis.spec.ts | 2 +- .../tests/throughput/service_maps.spec.ts | 117 ++- .../tests/traces/find_traces.spec.ts | 346 ++++---- .../tests/traces/trace_by_id.spec.ts | 2 +- ...actions_groups_detailed_statistics.spec.ts | 298 +++---- 47 files changed, 2635 insertions(+), 2760 deletions(-) create mode 100644 x-pack/test/apm_api_integration/common/bootstrap_apm_synthtrace.ts diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts b/packages/kbn-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts index bf068d7f33185..7bd2443031c80 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/client/apm_synthtrace_kibana_client.ts @@ -54,9 +54,8 @@ export class ApmSynthtraceKibanaClient { }); } async fetchLatestApmPackageVersion(currentKibanaVersion: string) { - const url = - 'https://epr-snapshot.elastic.co/search?package=apm&prerelease=true&all=true&kibana.version='; - const response = await fetch(url + currentKibanaVersion, { method: 'GET' }); + const url = `https://epr-snapshot.elastic.co/search?package=apm&prerelease=true&all=true&kibana.version=${currentKibanaVersion}`; + const response = await fetch(url, { method: 'GET' }); const json = (await response.json()) as Array<{ version: string }>; const packageVersions = (json ?? []).map((item) => item.version).sort(Semver.rcompare); const validPackageVersions = packageVersions.filter((v) => Semver.valid(v)); @@ -71,7 +70,7 @@ export class ApmSynthtraceKibanaClient { async installApmPackage(kibanaUrl: string, version: string, username: string, password: string) { const packageVersion = await this.fetchLatestApmPackageVersion(version); - const response = await fetch(kibanaUrl + '/api/fleet/epm/packages/apm/' + packageVersion, { + const response = await fetch(`${kibanaUrl}/api/fleet/epm/packages/apm/${packageVersion}`, { method: 'POST', headers: { Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'), diff --git a/packages/kbn-apm-synthtrace/src/lib/apm/index.ts b/packages/kbn-apm-synthtrace/src/lib/apm/index.ts index fcb8e078bf02a..a136daabee8f2 100644 --- a/packages/kbn-apm-synthtrace/src/lib/apm/index.ts +++ b/packages/kbn-apm-synthtrace/src/lib/apm/index.ts @@ -13,6 +13,7 @@ import { getChromeUserAgentDefaults } from './defaults/get_chrome_user_agent_def import { getBreakdownMetrics } from './processors/get_breakdown_metrics'; import { getApmWriteTargets } from './utils/get_apm_write_targets'; import { ApmSynthtraceEsClient } from './client/apm_synthtrace_es_client'; +import { ApmSynthtraceKibanaClient } from './client/apm_synthtrace_kibana_client'; import type { ApmException } from './apm_fields'; @@ -25,6 +26,7 @@ export const apm = { getBreakdownMetrics, getApmWriteTargets, ApmSynthtraceEsClient, + ApmSynthtraceKibanaClient, }; export type { ApmSynthtraceEsClient, ApmException }; diff --git a/x-pack/test/apm_api_integration/common/bootstrap_apm_synthtrace.ts b/x-pack/test/apm_api_integration/common/bootstrap_apm_synthtrace.ts new file mode 100644 index 0000000000000..96d0cbf3f8e7b --- /dev/null +++ b/x-pack/test/apm_api_integration/common/bootstrap_apm_synthtrace.ts @@ -0,0 +1,34 @@ +/* + * 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 { apm, createLogger, LogLevel } from '@kbn/apm-synthtrace'; +import { esTestConfig } from '@kbn/test'; +import { APM_TEST_PASSWORD } from './authentication'; +import { InheritedFtrProviderContext } from './ftr_provider_context'; + +export async function bootstrapApmSynthtrace( + context: InheritedFtrProviderContext, + kibanaServerUrl: string +) { + const es = context.getService('es'); + const kibanaVersion = esTestConfig.getVersion(); + + const kibanaClient = new apm.ApmSynthtraceKibanaClient(createLogger(LogLevel.info)); + await kibanaClient.installApmPackage( + kibanaServerUrl, + kibanaVersion, + 'elastic', + APM_TEST_PASSWORD + ); + + const esClient = new apm.ApmSynthtraceEsClient(es, createLogger(LogLevel.info), { + forceLegacyIndices: false, + refreshAfterIndex: true, + }); + + return esClient; +} diff --git a/x-pack/test/apm_api_integration/common/config.ts b/x-pack/test/apm_api_integration/common/config.ts index 3c9e99d645c7b..6bb177ff770b3 100644 --- a/x-pack/test/apm_api_integration/common/config.ts +++ b/x-pack/test/apm_api_integration/common/config.ts @@ -16,7 +16,7 @@ import { createApmUser, APM_TEST_PASSWORD, ApmUsername } from './authentication' import { APMFtrConfigName } from '../configs'; import { createApmApiClient } from './apm_api_supertest'; import { RegistryProvider } from './registry'; -import { synthtraceEsClientService } from './synthtrace_es_client_service'; +import { bootstrapApmSynthtrace } from './bootstrap_apm_synthtrace'; import { MachineLearningAPIProvider } from '../../functional/services/ml/api'; export interface ApmFtrConfig { @@ -80,7 +80,7 @@ export function createTestConfig(config: ApmFtrConfig) { const services = xPackAPITestsConfig.get('services') as InheritedServices; const servers = xPackAPITestsConfig.get('servers'); - const kibanaServer = servers.kibana; + const kibanaServer = servers.kibana as UrlObject; return { testFiles: [require.resolve('../tests')], @@ -90,7 +90,10 @@ export function createTestConfig(config: ApmFtrConfig) { ...services, apmFtrConfig: () => config, registry: RegistryProvider, - synthtraceEsClient: synthtraceEsClientService, + synthtraceEsClient: (context: InheritedFtrProviderContext) => { + const kibanaServerUrl = format(kibanaServer); + return bootstrapApmSynthtrace(context, kibanaServerUrl); + }, apmApiClient: async (context: InheritedFtrProviderContext) => { const security = context.getService('security'); const es = context.getService('es'); @@ -100,49 +103,49 @@ export function createTestConfig(config: ApmFtrConfig) { return { noAccessUser: await getApmApiClient({ - kibanaServer: servers.kibana, + kibanaServer, security, username: ApmUsername.noAccessUser, es, logger, }), readUser: await getApmApiClient({ - kibanaServer: servers.kibana, + kibanaServer, security, username: ApmUsername.viewerUser, es, logger, }), writeUser: await getApmApiClient({ - kibanaServer: servers.kibana, + kibanaServer, security, username: ApmUsername.editorUser, es, logger, }), annotationWriterUser: await getApmApiClient({ - kibanaServer: servers.kibana, + kibanaServer, security, username: ApmUsername.apmAnnotationsWriteUser, es, logger, }), noMlAccessUser: await getApmApiClient({ - kibanaServer: servers.kibana, + kibanaServer, security, username: ApmUsername.apmReadUserWithoutMlAccess, es, logger, }), manageOwnAgentKeysUser: await getApmApiClient({ - kibanaServer: servers.kibana, + kibanaServer, security, username: ApmUsername.apmManageOwnAgentKeys, es, logger, }), createAndAllAgentKeysUser: await getApmApiClient({ - kibanaServer: servers.kibana, + kibanaServer, security, username: ApmUsername.apmManageOwnAndCreateAgentKeys, es, diff --git a/x-pack/test/apm_api_integration/common/registry.ts b/x-pack/test/apm_api_integration/common/registry.ts index 51f4bb6a84e72..7611d054852df 100644 --- a/x-pack/test/apm_api_integration/common/registry.ts +++ b/x-pack/test/apm_api_integration/common/registry.ts @@ -15,7 +15,6 @@ import { FtrProviderContext } from './ftr_provider_context'; type ArchiveName = | 'apm_8.0.0' - | 'apm_mappings_only_8.0.0' | '8.0.0' | 'metrics_8.0.0' | 'ml_8.0.0' diff --git a/x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_job.ts b/x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_job.ts index 3a42456742caa..2302fac7337f6 100644 --- a/x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_job.ts +++ b/x-pack/test/apm_api_integration/common/utils/create_and_run_apm_ml_job.ts @@ -10,11 +10,12 @@ import datafeed from '@kbn/ml-plugin/server/models/data_recognizer/modules/apm_t import { MlApi } from '../../../functional/services/ml/api'; export function createAndRunApmMlJob({ ml, environment }: { ml: MlApi; environment: string }) { + const jobId = `apm-tx-metrics-${environment}`; return ml.createAndRunAnomalyDetectionLookbackJob( // @ts-expect-error not entire job config { ...job, - job_id: `apm-tx-metrics-${environment}`, + job_id: jobId, allow_lazy_open: false, custom_settings: { job_tags: { @@ -25,8 +26,9 @@ export function createAndRunApmMlJob({ ml, environment }: { ml: MlApi; environme }, { ...datafeed, - job_id: `apm-tx-metrics-${environment}`, - indices: ['apm-*'], + indices_options: { allow_no_indices: true }, + job_id: jobId, + indices: ['metrics-apm*', 'apm-*'], datafeed_id: `apm-tx-metrics-${environment}-datafeed`, query: { bool: { diff --git a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts index d1c1c465dc576..43ba70cc100a1 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts @@ -24,7 +24,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'fetching service anomalies with a trial license', - { config: 'trial', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'trial', archives: [] }, () => { const start = '2021-01-01T00:00:00.000Z'; const end = '2021-01-08T00:15:00.000Z'; diff --git a/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts b/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts index b85a96c25869a..0416a0124627a 100644 --- a/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts +++ b/x-pack/test/apm_api_integration/tests/anomalies/anomaly_charts.spec.ts @@ -18,7 +18,6 @@ import { createAndRunApmMlJob } from '../../common/utils/create_and_run_apm_ml_j export default function ApiTest({ getService }: FtrProviderContext) { const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); const ml = getService('ml'); @@ -70,7 +69,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'fetching service anomalies with a basic license', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { it('returns a 501', async () => { const status = await statusOf( @@ -90,7 +89,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'fetching service anomalies with a trial license', - { config: 'trial', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'trial', archives: [] }, () => { const start = '2021-01-01T00:00:00.000Z'; const end = '2021-01-08T00:15:00.000Z'; diff --git a/x-pack/test/apm_api_integration/tests/cold_start/cold_start.spec.ts b/x-pack/test/apm_api_integration/tests/cold_start/cold_start.spec.ts index fad428a96f18a..721f178a6413e 100644 --- a/x-pack/test/apm_api_integration/tests/cold_start/cold_start.spec.ts +++ b/x-pack/test/apm_api_integration/tests/cold_start/cold_start.spec.ts @@ -66,139 +66,135 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Cold start rate when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('without comparison', () => { - let body: ColdStartRate; - let status: number; - - before(async () => { - await generateData({ - synthtraceEsClient, - start, - end, - coldStartRate: 10, - warmStartRate: 30, - }); - const response = await callApi(); - body = response.body; - status = response.status; + registry.when('Cold start rate when data is generated', { config: 'basic', archives: [] }, () => { + describe('without comparison', () => { + let body: ColdStartRate; + let status: number; + + before(async () => { + await generateData({ + synthtraceEsClient, + start, + end, + coldStartRate: 10, + warmStartRate: 30, }); + const response = await callApi(); + body = response.body; + status = response.status; + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - it('returns correct HTTP status', () => { - expect(status).to.be(200); - }); + it('returns correct HTTP status', () => { + expect(status).to.be(200); + }); - it('returns an array of transaction cold start rates', () => { - expect(body).to.have.property('currentPeriod'); - expect(body.currentPeriod.transactionColdstartRate).to.have.length(15); - expect(body.currentPeriod.transactionColdstartRate.every(({ y }) => y === 0.25)).to.be( - true - ); - }); + it('returns an array of transaction cold start rates', () => { + expect(body).to.have.property('currentPeriod'); + expect(body.currentPeriod.transactionColdstartRate).to.have.length(15); + expect(body.currentPeriod.transactionColdstartRate.every(({ y }) => y === 0.25)).to.be( + true + ); + }); - it('returns correct average rate', () => { - expect(body.currentPeriod.average).to.be(0.25); - }); + it('returns correct average rate', () => { + expect(body.currentPeriod.average).to.be(0.25); + }); - it("doesn't have data for the previous period", () => { - expect(body).to.have.property('previousPeriod'); - expect(body.previousPeriod.transactionColdstartRate).to.have.length(0); - expect(body.previousPeriod.average).to.be(null); - }); + it("doesn't have data for the previous period", () => { + expect(body).to.have.property('previousPeriod'); + expect(body.previousPeriod.transactionColdstartRate).to.have.length(0); + expect(body.previousPeriod.average).to.be(null); }); + }); - describe('with comparison', () => { - let body: ColdStartRate; - let status: number; - - before(async () => { - const startDate = moment(start).add(6, 'minutes'); - const endDate = moment(start).add(9, 'minutes'); - const comparisonStartDate = new Date(start); - const comparisonEndDate = moment(start).add(3, 'minutes'); - - await generateData({ - synthtraceEsClient, - start: startDate.valueOf(), - end: endDate.valueOf(), - coldStartRate: 10, - warmStartRate: 30, - }); - await generateData({ - synthtraceEsClient, - start: comparisonStartDate.getTime(), - end: comparisonEndDate.valueOf(), - coldStartRate: 20, - warmStartRate: 20, - }); - - const response = await callApi({ - query: { - start: startDate.toISOString(), - end: endDate.subtract(1, 'seconds').toISOString(), - offset: '6m', - }, - }); - body = response.body; - status = response.status; + describe('with comparison', () => { + let body: ColdStartRate; + let status: number; + + before(async () => { + const startDate = moment(start).add(6, 'minutes'); + const endDate = moment(start).add(9, 'minutes'); + const comparisonStartDate = new Date(start); + const comparisonEndDate = moment(start).add(3, 'minutes'); + + await generateData({ + synthtraceEsClient, + start: startDate.valueOf(), + end: endDate.valueOf(), + coldStartRate: 10, + warmStartRate: 30, }); - - after(() => synthtraceEsClient.clean()); - - it('returns correct HTTP status', () => { - expect(status).to.be(200); + await generateData({ + synthtraceEsClient, + start: comparisonStartDate.getTime(), + end: comparisonEndDate.valueOf(), + coldStartRate: 20, + warmStartRate: 20, }); - it('returns some data', () => { - expect(body.currentPeriod.average).not.to.be(null); - expect(body.currentPeriod.transactionColdstartRate.length).to.be.greaterThan(0); - const hasCurrentPeriodData = body.currentPeriod.transactionColdstartRate.some(({ y }) => - isFiniteNumber(y) - ); - expect(hasCurrentPeriodData).to.equal(true); - - expect(body.previousPeriod.average).not.to.be(null); - expect(body.previousPeriod.transactionColdstartRate.length).to.be.greaterThan(0); - const hasPreviousPeriodData = body.previousPeriod.transactionColdstartRate.some(({ y }) => - isFiniteNumber(y) - ); - expect(hasPreviousPeriodData).to.equal(true); + const response = await callApi({ + query: { + start: startDate.toISOString(), + end: endDate.subtract(1, 'seconds').toISOString(), + offset: '6m', + }, }); + body = response.body; + status = response.status; + }); - it('has same start time for both periods', () => { - expect(first(body.currentPeriod.transactionColdstartRate)?.x).to.equal( - first(body.previousPeriod.transactionColdstartRate)?.x - ); - }); + after(() => synthtraceEsClient.clean()); - it('has same end time for both periods', () => { - expect(last(body.currentPeriod.transactionColdstartRate)?.x).to.equal( - last(body.previousPeriod.transactionColdstartRate)?.x - ); - }); + it('returns correct HTTP status', () => { + expect(status).to.be(200); + }); - it('returns an array of transaction cold start rates', () => { - expect(body.currentPeriod.transactionColdstartRate).to.have.length(3); - expect(body.currentPeriod.transactionColdstartRate.every(({ y }) => y === 0.25)).to.be( - true - ); + it('returns some data', () => { + expect(body.currentPeriod.average).not.to.be(null); + expect(body.currentPeriod.transactionColdstartRate.length).to.be.greaterThan(0); + const hasCurrentPeriodData = body.currentPeriod.transactionColdstartRate.some(({ y }) => + isFiniteNumber(y) + ); + expect(hasCurrentPeriodData).to.equal(true); + + expect(body.previousPeriod.average).not.to.be(null); + expect(body.previousPeriod.transactionColdstartRate.length).to.be.greaterThan(0); + const hasPreviousPeriodData = body.previousPeriod.transactionColdstartRate.some(({ y }) => + isFiniteNumber(y) + ); + expect(hasPreviousPeriodData).to.equal(true); + }); - expect(body.previousPeriod.transactionColdstartRate).to.have.length(3); - expect(body.previousPeriod.transactionColdstartRate.every(({ y }) => y === 0.5)).to.be( - true - ); - }); + it('has same start time for both periods', () => { + expect(first(body.currentPeriod.transactionColdstartRate)?.x).to.equal( + first(body.previousPeriod.transactionColdstartRate)?.x + ); + }); - it('has same average value for both periods', () => { - expect(body.currentPeriod.average).to.be(0.25); - expect(body.previousPeriod.average).to.be(0.5); - }); + it('has same end time for both periods', () => { + expect(last(body.currentPeriod.transactionColdstartRate)?.x).to.equal( + last(body.previousPeriod.transactionColdstartRate)?.x + ); }); - } - ); + + it('returns an array of transaction cold start rates', () => { + expect(body.currentPeriod.transactionColdstartRate).to.have.length(3); + expect(body.currentPeriod.transactionColdstartRate.every(({ y }) => y === 0.25)).to.be( + true + ); + + expect(body.previousPeriod.transactionColdstartRate).to.have.length(3); + expect(body.previousPeriod.transactionColdstartRate.every(({ y }) => y === 0.5)).to.be( + true + ); + }); + + it('has same average value for both periods', () => { + expect(body.currentPeriod.average).to.be(0.25); + expect(body.previousPeriod.average).to.be(0.5); + }); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/cold_start/cold_start_by_transaction_name/cold_start_by_transaction_name.spec.ts b/x-pack/test/apm_api_integration/tests/cold_start/cold_start_by_transaction_name/cold_start_by_transaction_name.spec.ts index ed432f58d47aa..25e4cd208aeb0 100644 --- a/x-pack/test/apm_api_integration/tests/cold_start/cold_start_by_transaction_name/cold_start_by_transaction_name.spec.ts +++ b/x-pack/test/apm_api_integration/tests/cold_start/cold_start_by_transaction_name/cold_start_by_transaction_name.spec.ts @@ -70,7 +70,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'Cold start rate by transaction name when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { describe('without comparison', () => { let body: ColdStartRate; diff --git a/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts b/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts index efe8f37f1c5dc..a77a2e443b9d5 100644 --- a/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts +++ b/x-pack/test/apm_api_integration/tests/data_view/static.spec.ts @@ -59,79 +59,75 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'mappings exists', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is generated', () => { - let response: SupertestReturnType<'POST /internal/apm/data_view/static'>; + registry.when('mappings exists', { config: 'basic', archives: [] }, () => { + describe('when data is generated', () => { + let response: SupertestReturnType<'POST /internal/apm/data_view/static'>; + + before(async () => { + await generateApmData(synthtrace); + response = await createDataViewViaApmApi(); + }); + + after(async () => { + await deleteDataView(); + await synthtrace.clean(); + }); + + it('successfully creates the apm data view', async () => { + expect(response.status).to.be(200); + + expect(response.body.dataView!.id).to.be('apm_static_index_pattern_id'); + expect(response.body.dataView!.name).to.be('APM'); + expect(response.body.dataView!.title).to.be( + 'traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*' + ); + }); + + describe('when fetching the data view', async () => { + let resBody: any; before(async () => { - await generateApmData(synthtrace); - response = await createDataViewViaApmApi(); + const res = await getDataView().expect(200); + resBody = res.body; }); - after(async () => { - await deleteDataView(); - await synthtrace.clean(); + it('has correct id', () => { + expect(resBody.id).to.be('apm_static_index_pattern_id'); }); - it('successfully creates the apm data view', async () => { - expect(response.status).to.be(200); - - expect(response.body.dataView!.id).to.be('apm_static_index_pattern_id'); - expect(response.body.dataView!.name).to.be('APM'); - expect(response.body.dataView!.title).to.be( - 'traces-apm*,apm-*,logs-apm*,apm-*,metrics-apm*,apm-*' - ); + it('has correct title', () => { + expect(resBody.attributes.title).to.be(dataViewPattern); }); - describe('when fetching the data view', async () => { - let resBody: any; - - before(async () => { - const res = await getDataView().expect(200); - resBody = res.body; - }); - - it('has correct id', () => { - expect(resBody.id).to.be('apm_static_index_pattern_id'); - }); - - it('has correct title', () => { - expect(resBody.attributes.title).to.be(dataViewPattern); - }); - - it('has correct attributes', () => { - expect(resBody.attributes.fieldFormatMap).to.be( - JSON.stringify({ - 'trace.id': { - id: 'url', - params: { - urlTemplate: 'apm/link-to/trace/{{value}}', - labelTemplate: '{{value}}', - }, + it('has correct attributes', () => { + expect(resBody.attributes.fieldFormatMap).to.be( + JSON.stringify({ + 'trace.id': { + id: 'url', + params: { + urlTemplate: 'apm/link-to/trace/{{value}}', + labelTemplate: '{{value}}', }, - 'transaction.id': { - id: 'url', - params: { - urlTemplate: 'apm/link-to/transaction/{{value}}', - labelTemplate: '{{value}}', - }, + }, + 'transaction.id': { + id: 'url', + params: { + urlTemplate: 'apm/link-to/transaction/{{value}}', + labelTemplate: '{{value}}', }, - }) - ); - }); - - // this test ensures that the default APM Data View doesn't interfere with suggestions returned in the kuery bar (this has been a problem in the past) - it('can get suggestions for `trace.id`', async () => { - const suggestions = await getDataViewSuggestions('trace.id'); - expect(suggestions.body.length).to.be(10); - }); + }, + }) + ); + }); + + // this test ensures that the default APM Data View doesn't interfere with suggestions returned in the kuery bar (this has been a problem in the past) + it('can get suggestions for `trace.id`', async () => { + const suggestions = await getDataViewSuggestions('trace.id'); + expect(suggestions.body.length).to.be(10); }); }); - } - ); + }); + }); } function generateApmData(synthtrace: ApmSynthtraceEsClient) { diff --git a/x-pack/test/apm_api_integration/tests/dependencies/dependency_metrics.spec.ts b/x-pack/test/apm_api_integration/tests/dependencies/dependency_metrics.spec.ts index 686f6ba313d7e..7d8dab710d7e0 100644 --- a/x-pack/test/apm_api_integration/tests/dependencies/dependency_metrics.spec.ts +++ b/x-pack/test/apm_api_integration/tests/dependencies/dependency_metrics.spec.ts @@ -94,180 +94,125 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Dependency metrics when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - before(async () => { - await generateOperationData({ - synthtraceEsClient, - start, - end, - }); + registry.when('Dependency metrics when data is loaded', { config: 'basic', archives: [] }, () => { + before(async () => { + await generateOperationData({ + synthtraceEsClient, + start, + end, }); + }); - describe('without spanName', () => { - describe('without a kuery or environment', () => { - it('returns the correct latency', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'latency', - }); - - const searchRate = - ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_UNKNOWN_RATE; - const bulkRate = ES_BULK_RATE; - - expect(avg(response.body.currentTimeseries)).to.eql( - roundNumber( - ((ES_SEARCH_DURATION * searchRate + ES_BULK_DURATION * bulkRate) / - (searchRate + bulkRate)) * - 1000 - ) - ); - }); - - it('returns the correct throughput', async () => { - const response = await callApi({ - dependencyName: 'redis', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'throughput', - }); - - expect(avg(response.body.currentTimeseries)).to.eql(REDIS_SET_RATE); + describe('without spanName', () => { + describe('without a kuery or environment', () => { + it('returns the correct latency', async () => { + const response = await callApi({ + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: true, + spanName: '', + metric: 'latency', }); - it('returns the correct failure rate', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'error_rate', - }); + const searchRate = + ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_UNKNOWN_RATE; + const bulkRate = ES_BULK_RATE; - const expectedErrorRate = - ES_SEARCH_FAILURE_RATE / (ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE); + expect(avg(response.body.currentTimeseries)).to.eql( + roundNumber( + ((ES_SEARCH_DURATION * searchRate + ES_BULK_DURATION * bulkRate) / + (searchRate + bulkRate)) * + 1000 + ) + ); + }); - expect(avg(response.body.currentTimeseries)).to.eql(expectedErrorRate); + it('returns the correct throughput', async () => { + const response = await callApi({ + dependencyName: 'redis', + searchServiceDestinationMetrics: true, + spanName: '', + metric: 'throughput', }); + + expect(avg(response.body.currentTimeseries)).to.eql(REDIS_SET_RATE); }); - describe('with a kuery', () => { - it('returns the correct latency', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'latency', - kuery: `event.outcome:unknown`, - }); - - const searchRate = ES_SEARCH_UNKNOWN_RATE; - const bulkRate = ES_BULK_RATE; - - expect(avg(response.body.currentTimeseries)).to.eql( - roundNumber( - ((ES_SEARCH_DURATION * searchRate + ES_BULK_DURATION * bulkRate) / - (searchRate + bulkRate)) * - 1000 - ) - ); + it('returns the correct failure rate', async () => { + const response = await callApi({ + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: true, + spanName: '', + metric: 'error_rate', }); - it('returns the correct throughput', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'throughput', - kuery: `event.outcome:unknown`, - }); + const expectedErrorRate = + ES_SEARCH_FAILURE_RATE / (ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE); - const searchRate = ES_SEARCH_UNKNOWN_RATE; - const bulkRate = ES_BULK_RATE; + expect(avg(response.body.currentTimeseries)).to.eql(expectedErrorRate); + }); + }); - expect(avg(response.body.currentTimeseries)).to.eql(roundNumber(searchRate + bulkRate)); + describe('with a kuery', () => { + it('returns the correct latency', async () => { + const response = await callApi({ + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: true, + spanName: '', + metric: 'latency', + kuery: `event.outcome:unknown`, }); - it('returns the correct failure rate', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'error_rate', - kuery: 'event.outcome:success', - }); + const searchRate = ES_SEARCH_UNKNOWN_RATE; + const bulkRate = ES_BULK_RATE; - expect(avg(response.body.currentTimeseries)).to.eql(0); - }); + expect(avg(response.body.currentTimeseries)).to.eql( + roundNumber( + ((ES_SEARCH_DURATION * searchRate + ES_BULK_DURATION * bulkRate) / + (searchRate + bulkRate)) * + 1000 + ) + ); }); - describe('with an environment', () => { - it('returns the correct latency', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'latency', - environment: 'production', - }); - - const searchRate = ES_SEARCH_UNKNOWN_RATE; - const bulkRate = 0; - - expect(avg(response.body.currentTimeseries)).to.eql( - roundNumber( - ((ES_SEARCH_DURATION * searchRate + ES_BULK_DURATION * bulkRate) / - (searchRate + bulkRate)) * - 1000 - ) - ); + it('returns the correct throughput', async () => { + const response = await callApi({ + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: true, + spanName: '', + metric: 'throughput', + kuery: `event.outcome:unknown`, }); - it('returns the correct throughput', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'throughput', - environment: 'production', - }); + const searchRate = ES_SEARCH_UNKNOWN_RATE; + const bulkRate = ES_BULK_RATE; - const searchRate = - ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_UNKNOWN_RATE; - const bulkRate = 0; + expect(avg(response.body.currentTimeseries)).to.eql(roundNumber(searchRate + bulkRate)); + }); - expect(avg(response.body.currentTimeseries)).to.eql(roundNumber(searchRate + bulkRate)); + it('returns the correct failure rate', async () => { + const response = await callApi({ + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: true, + spanName: '', + metric: 'error_rate', + kuery: 'event.outcome:success', }); - it('returns the correct failure rate', async () => { - const response = await callApi({ - dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: true, - spanName: '', - metric: 'error_rate', - environment: 'development', - }); - - expect(avg(response.body.currentTimeseries)).to.eql(null); - }); + expect(avg(response.body.currentTimeseries)).to.eql(0); }); }); - describe('with spanName', () => { + describe('with an environment', () => { it('returns the correct latency', async () => { const response = await callApi({ dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: false, - spanName: '/_search', + searchServiceDestinationMetrics: true, + spanName: '', metric: 'latency', + environment: 'production', }); - const searchRate = - ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_UNKNOWN_RATE; + const searchRate = ES_SEARCH_UNKNOWN_RATE; const bulkRate = 0; expect(avg(response.body.currentTimeseries)).to.eql( @@ -281,28 +226,78 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('returns the correct throughput', async () => { const response = await callApi({ - dependencyName: 'redis', - searchServiceDestinationMetrics: false, - spanName: 'SET', + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: true, + spanName: '', metric: 'throughput', + environment: 'production', }); - expect(avg(response.body.currentTimeseries)).to.eql(REDIS_SET_RATE); + const searchRate = + ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_UNKNOWN_RATE; + const bulkRate = 0; + + expect(avg(response.body.currentTimeseries)).to.eql(roundNumber(searchRate + bulkRate)); }); it('returns the correct failure rate', async () => { const response = await callApi({ dependencyName: 'elasticsearch', - searchServiceDestinationMetrics: false, - spanName: '/_bulk', + searchServiceDestinationMetrics: true, + spanName: '', metric: 'error_rate', + environment: 'development', }); expect(avg(response.body.currentTimeseries)).to.eql(null); }); }); + }); - after(() => synthtraceEsClient.clean()); - } - ); + describe('with spanName', () => { + it('returns the correct latency', async () => { + const response = await callApi({ + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: false, + spanName: '/_search', + metric: 'latency', + }); + + const searchRate = ES_SEARCH_FAILURE_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_UNKNOWN_RATE; + const bulkRate = 0; + + expect(avg(response.body.currentTimeseries)).to.eql( + roundNumber( + ((ES_SEARCH_DURATION * searchRate + ES_BULK_DURATION * bulkRate) / + (searchRate + bulkRate)) * + 1000 + ) + ); + }); + + it('returns the correct throughput', async () => { + const response = await callApi({ + dependencyName: 'redis', + searchServiceDestinationMetrics: false, + spanName: 'SET', + metric: 'throughput', + }); + + expect(avg(response.body.currentTimeseries)).to.eql(REDIS_SET_RATE); + }); + + it('returns the correct failure rate', async () => { + const response = await callApi({ + dependencyName: 'elasticsearch', + searchServiceDestinationMetrics: false, + spanName: '/_bulk', + metric: 'error_rate', + }); + + expect(avg(response.body.currentTimeseries)).to.eql(null); + }); + }); + + after(() => synthtraceEsClient.clean()); + }); } diff --git a/x-pack/test/apm_api_integration/tests/dependencies/metadata.spec.ts b/x-pack/test/apm_api_integration/tests/dependencies/metadata.spec.ts index 0d7e4f01733e2..006a67f3f7724 100644 --- a/x-pack/test/apm_api_integration/tests/dependencies/metadata.spec.ts +++ b/x-pack/test/apm_api_integration/tests/dependencies/metadata.spec.ts @@ -44,7 +44,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'Dependency metadata when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { after(() => synthtraceEsClient.clean()); diff --git a/x-pack/test/apm_api_integration/tests/dependencies/service_dependencies.spec.ts b/x-pack/test/apm_api_integration/tests/dependencies/service_dependencies.spec.ts index e5d3b8a436086..69e61e52ca1a4 100644 --- a/x-pack/test/apm_api_integration/tests/dependencies/service_dependencies.spec.ts +++ b/x-pack/test/apm_api_integration/tests/dependencies/service_dependencies.spec.ts @@ -47,33 +47,29 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Dependency for services', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded', () => { - before(async () => { - await generateData({ synthtraceEsClient, start, end }); - }); - after(() => synthtraceEsClient.clean()); + registry.when('Dependency for services', { config: 'basic', archives: [] }, () => { + describe('when data is loaded', () => { + before(async () => { + await generateData({ synthtraceEsClient, start, end }); + }); + after(() => synthtraceEsClient.clean()); - it('returns a list of dependencies for a service', async () => { - const { status, body } = await callApi(); + it('returns a list of dependencies for a service', async () => { + const { status, body } = await callApi(); - expect(status).to.be(200); - expect( - body.serviceDependencies.map( - ({ location }) => (location as DependencyNode).dependencyName - ) - ).to.eql([dependencyName]); + expect(status).to.be(200); + expect( + body.serviceDependencies.map( + ({ location }) => (location as DependencyNode).dependencyName + ) + ).to.eql([dependencyName]); - const currentStatsLatencyValues = - body.serviceDependencies[0].currentStats.latency.timeseries; - expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); - }); + const currentStatsLatencyValues = + body.serviceDependencies[0].currentStats.latency.timeseries; + expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); }); - } - ); + }); + }); registry.when( 'Dependency for service breakdown when data is not loaded', @@ -88,31 +84,27 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Dependency for services breakdown', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded', () => { - before(async () => { - await generateData({ synthtraceEsClient, start, end }); - }); - after(() => synthtraceEsClient.clean()); + registry.when('Dependency for services breakdown', { config: 'basic', archives: [] }, () => { + describe('when data is loaded', () => { + before(async () => { + await generateData({ synthtraceEsClient, start, end }); + }); + after(() => synthtraceEsClient.clean()); - it('returns a list of dependencies for a service', async () => { - const { status, body } = await callApi(); + it('returns a list of dependencies for a service', async () => { + const { status, body } = await callApi(); - expect(status).to.be(200); - expect( - body.serviceDependencies.map( - ({ location }) => (location as DependencyNode).dependencyName - ) - ).to.eql([dependencyName]); + expect(status).to.be(200); + expect( + body.serviceDependencies.map( + ({ location }) => (location as DependencyNode).dependencyName + ) + ).to.eql([dependencyName]); - const currentStatsLatencyValues = - body.serviceDependencies[0].currentStats.latency.timeseries; - expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); - }); + const currentStatsLatencyValues = + body.serviceDependencies[0].currentStats.latency.timeseries; + expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/dependencies/top_dependencies.spec.ts b/x-pack/test/apm_api_integration/tests/dependencies/top_dependencies.spec.ts index 5160ea52b094e..c0c67d9bb8f19 100644 --- a/x-pack/test/apm_api_integration/tests/dependencies/top_dependencies.spec.ts +++ b/x-pack/test/apm_api_integration/tests/dependencies/top_dependencies.spec.ts @@ -49,94 +49,90 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Top dependencies', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is generated', () => { - let topDependencies: TopDependencies; + registry.when('Top dependencies', { config: 'basic', archives: [] }, () => { + describe('when data is generated', () => { + let topDependencies: TopDependencies; + + before(async () => { + await generateData({ synthtraceEsClient, start, end }); + const response = await callApi(); + topDependencies = response.body; + }); + + after(() => synthtraceEsClient.clean()); + + it('returns an array of dependencies', () => { + expect(topDependencies).to.have.property('dependencies'); + expect(topDependencies.dependencies).to.have.length(1); + }); - before(async () => { - await generateData({ synthtraceEsClient, start, end }); - const response = await callApi(); - topDependencies = response.body; + it('returns correct dependency information', () => { + const location = topDependencies.dependencies[0].location as DependencyNode; + const { span } = dataConfig; + + expect(location.type).to.be(NodeType.dependency); + expect(location.dependencyName).to.be(span.destination); + expect(location.spanType).to.be(span.type); + expect(location.spanSubtype).to.be(span.subType); + expect(location).to.have.property('id'); + }); + + describe('returns the correct stats', () => { + let dependencies: TopDependencies['dependencies'][number]; + + before(() => { + dependencies = topDependencies.dependencies[0]; }); - after(() => synthtraceEsClient.clean()); + it("doesn't have previous stats", () => { + expect(dependencies.previousStats).to.be(null); + }); - it('returns an array of dependencies', () => { - expect(topDependencies).to.have.property('dependencies'); - expect(topDependencies.dependencies).to.have.length(1); + it('has an "impact" property', () => { + expect(dependencies.currentStats).to.have.property('impact'); }); - it('returns correct dependency information', () => { - const location = topDependencies.dependencies[0].location as DependencyNode; - const { span } = dataConfig; + it('returns the correct latency', () => { + const { + currentStats: { latency }, + } = dependencies; - expect(location.type).to.be(NodeType.dependency); - expect(location.dependencyName).to.be(span.destination); - expect(location.spanType).to.be(span.type); - expect(location.spanSubtype).to.be(span.subType); - expect(location).to.have.property('id'); + const { transaction } = dataConfig; + + expect(latency.value).to.be(transaction.duration * 1000); + expect(latency.timeseries.every(({ y }) => y === transaction.duration * 1000)).to.be( + true + ); + }); + + it('returns the correct throughput', () => { + const { + currentStats: { throughput }, + } = dependencies; + const { rate } = dataConfig; + + expect(roundNumber(throughput.value)).to.be(roundNumber(rate)); + }); + + it('returns the correct total time', () => { + const { + currentStats: { totalTime }, + } = dependencies; + const { rate, transaction } = dataConfig; + + expect( + totalTime.timeseries.every(({ y }) => y === rate * transaction.duration * 1000) + ).to.be(true); }); - describe('returns the correct stats', () => { - let dependencies: TopDependencies['dependencies'][number]; - - before(() => { - dependencies = topDependencies.dependencies[0]; - }); - - it("doesn't have previous stats", () => { - expect(dependencies.previousStats).to.be(null); - }); - - it('has an "impact" property', () => { - expect(dependencies.currentStats).to.have.property('impact'); - }); - - it('returns the correct latency', () => { - const { - currentStats: { latency }, - } = dependencies; - - const { transaction } = dataConfig; - - expect(latency.value).to.be(transaction.duration * 1000); - expect(latency.timeseries.every(({ y }) => y === transaction.duration * 1000)).to.be( - true - ); - }); - - it('returns the correct throughput', () => { - const { - currentStats: { throughput }, - } = dependencies; - const { rate } = dataConfig; - - expect(roundNumber(throughput.value)).to.be(roundNumber(rate)); - }); - - it('returns the correct total time', () => { - const { - currentStats: { totalTime }, - } = dependencies; - const { rate, transaction } = dataConfig; - - expect( - totalTime.timeseries.every(({ y }) => y === rate * transaction.duration * 1000) - ).to.be(true); - }); - - it('returns the correct error rate', () => { - const { - currentStats: { errorRate }, - } = dependencies; - expect(errorRate.value).to.be(0); - expect(errorRate.timeseries.every(({ y }) => y === 0)).to.be(true); - }); + it('returns the correct error rate', () => { + const { + currentStats: { errorRate }, + } = dependencies; + expect(errorRate.value).to.be(0); + expect(errorRate.timeseries.every(({ y }) => y === 0)).to.be(true); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/dependencies/top_operations.spec.ts b/x-pack/test/apm_api_integration/tests/dependencies/top_operations.spec.ts index 1040bd58417f5..8d8de18eb6e01 100644 --- a/x-pack/test/apm_api_integration/tests/dependencies/top_operations.spec.ts +++ b/x-pack/test/apm_api_integration/tests/dependencies/top_operations.spec.ts @@ -65,154 +65,150 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'Top operations when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - before(() => - generateOperationData({ - synthtraceEsClient, - start, - end, - }) - ); - - after(() => synthtraceEsClient.clean()); - - describe('requested for elasticsearch', () => { - let response: TopOperations; - let searchOperation: ValuesType; - let bulkOperation: ValuesType; - - before(async () => { - response = await callApi({ dependencyName: 'elasticsearch' }); - searchOperation = response.find((op) => op.spanName === '/_search')!; - bulkOperation = response.find((op) => op.spanName === '/_bulk')!; - }); + registry.when('Top operations when data is generated', { config: 'basic', archives: [] }, () => { + before(() => + generateOperationData({ + synthtraceEsClient, + start, + end, + }) + ); - it('returns the correct operations', () => { - expect(response.length).to.eql(2); + after(() => synthtraceEsClient.clean()); - expect(searchOperation).to.be.ok(); - expect(bulkOperation).to.be.ok(); - }); + describe('requested for elasticsearch', () => { + let response: TopOperations; + let searchOperation: ValuesType; + let bulkOperation: ValuesType; - it('returns the correct latency', () => { - expect(searchOperation.latency).to.eql(ES_SEARCH_DURATION * 1000); - expect(bulkOperation.latency).to.eql(ES_BULK_DURATION * 1000); - }); + before(async () => { + response = await callApi({ dependencyName: 'elasticsearch' }); + searchOperation = response.find((op) => op.spanName === '/_search')!; + bulkOperation = response.find((op) => op.spanName === '/_bulk')!; + }); - it('returns the correct throughput', () => { - const expectedSearchThroughput = roundNumber( - ES_SEARCH_UNKNOWN_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_FAILURE_RATE - ); - const expectedBulkThroughput = ES_BULK_RATE; + it('returns the correct operations', () => { + expect(response.length).to.eql(2); - expect(roundNumber(searchOperation.throughput)).to.eql(expectedSearchThroughput); - expect(roundNumber(bulkOperation.throughput)).to.eql(expectedBulkThroughput); + expect(searchOperation).to.be.ok(); + expect(bulkOperation).to.be.ok(); + }); - expect( - searchOperation.timeseries.throughput - .map((bucket) => bucket.y) - .every((val) => val === expectedSearchThroughput) - ); - }); + it('returns the correct latency', () => { + expect(searchOperation.latency).to.eql(ES_SEARCH_DURATION * 1000); + expect(bulkOperation.latency).to.eql(ES_BULK_DURATION * 1000); + }); - it('returns the correct failure rate', () => { - const expectedSearchFailureRate = - ES_SEARCH_FAILURE_RATE / (ES_SEARCH_SUCCESS_RATE + ES_SEARCH_FAILURE_RATE); - const expectedBulkFailureRate = null; + it('returns the correct throughput', () => { + const expectedSearchThroughput = roundNumber( + ES_SEARCH_UNKNOWN_RATE + ES_SEARCH_SUCCESS_RATE + ES_SEARCH_FAILURE_RATE + ); + const expectedBulkThroughput = ES_BULK_RATE; - expect(searchOperation.failureRate).to.be(expectedSearchFailureRate); + expect(roundNumber(searchOperation.throughput)).to.eql(expectedSearchThroughput); + expect(roundNumber(bulkOperation.throughput)).to.eql(expectedBulkThroughput); - expect(bulkOperation.failureRate).to.be(expectedBulkFailureRate); + expect( + searchOperation.timeseries.throughput + .map((bucket) => bucket.y) + .every((val) => val === expectedSearchThroughput) + ); + }); - expect( - searchOperation.timeseries.failureRate - .map((bucket) => bucket.y) - .every((val) => val === expectedSearchFailureRate) - ); + it('returns the correct failure rate', () => { + const expectedSearchFailureRate = + ES_SEARCH_FAILURE_RATE / (ES_SEARCH_SUCCESS_RATE + ES_SEARCH_FAILURE_RATE); + const expectedBulkFailureRate = null; - expect( - bulkOperation.timeseries.failureRate - .map((bucket) => bucket.y) - .every((val) => val === expectedBulkFailureRate) - ); - }); + expect(searchOperation.failureRate).to.be(expectedSearchFailureRate); - it('returns the correct impact', () => { - expect(searchOperation.impact).to.eql(0); - expect(bulkOperation.impact).to.eql(100); - }); + expect(bulkOperation.failureRate).to.be(expectedBulkFailureRate); + + expect( + searchOperation.timeseries.failureRate + .map((bucket) => bucket.y) + .every((val) => val === expectedSearchFailureRate) + ); + + expect( + bulkOperation.timeseries.failureRate + .map((bucket) => bucket.y) + .every((val) => val === expectedBulkFailureRate) + ); }); - describe('requested for redis', () => { - let response: TopOperations; - let setOperation: ValuesType; + it('returns the correct impact', () => { + expect(searchOperation.impact).to.eql(0); + expect(bulkOperation.impact).to.eql(100); + }); + }); - before(async () => { - response = await callApi({ dependencyName: 'redis' }); - setOperation = response.find((op) => op.spanName === 'SET')!; - }); + describe('requested for redis', () => { + let response: TopOperations; + let setOperation: ValuesType; - it('returns the correct operations', () => { - expect(response.length).to.eql(1); + before(async () => { + response = await callApi({ dependencyName: 'redis' }); + setOperation = response.find((op) => op.spanName === 'SET')!; + }); - expect(setOperation).to.be.ok(); - }); + it('returns the correct operations', () => { + expect(response.length).to.eql(1); - it('returns the correct latency', () => { - expect(setOperation.latency).to.eql(REDIS_SET_DURATION * 1000); - }); + expect(setOperation).to.be.ok(); + }); - it('returns the correct throughput', () => { - expect(roundNumber(setOperation.throughput)).to.eql(roundNumber(REDIS_SET_RATE)); - }); + it('returns the correct latency', () => { + expect(setOperation.latency).to.eql(REDIS_SET_DURATION * 1000); }); - describe('requested for a specific service', () => { - let response: TopOperations; - let searchOperation: ValuesType; - let bulkOperation: ValuesType | undefined; - - before(async () => { - response = await callApi({ - dependencyName: 'elasticsearch', - kuery: `service.name:"synth-go"`, - }); - searchOperation = response.find((op) => op.spanName === '/_search')!; - bulkOperation = response.find((op) => op.spanName === '/_bulk'); - }); + it('returns the correct throughput', () => { + expect(roundNumber(setOperation.throughput)).to.eql(roundNumber(REDIS_SET_RATE)); + }); + }); - it('returns the correct operations', () => { - expect(response.length).to.eql(1); + describe('requested for a specific service', () => { + let response: TopOperations; + let searchOperation: ValuesType; + let bulkOperation: ValuesType | undefined; - expect(searchOperation).to.be.ok(); - expect(bulkOperation).not.to.be.ok(); + before(async () => { + response = await callApi({ + dependencyName: 'elasticsearch', + kuery: `service.name:"synth-go"`, }); + searchOperation = response.find((op) => op.spanName === '/_search')!; + bulkOperation = response.find((op) => op.spanName === '/_bulk'); }); - describe('requested for a specific environment', () => { - let response: TopOperations; - let searchOperation: ValuesType | undefined; - let bulkOperation: ValuesType; - - before(async () => { - response = await callApi({ - dependencyName: 'elasticsearch', - environment: 'development', - }); - searchOperation = response.find((op) => op.spanName === '/_search'); - bulkOperation = response.find((op) => op.spanName === '/_bulk')!; - }); + it('returns the correct operations', () => { + expect(response.length).to.eql(1); - it('returns the correct operations', () => { - expect(response.length).to.eql(1); + expect(searchOperation).to.be.ok(); + expect(bulkOperation).not.to.be.ok(); + }); + }); - expect(searchOperation).not.to.be.ok(); - expect(bulkOperation).to.be.ok(); + describe('requested for a specific environment', () => { + let response: TopOperations; + let searchOperation: ValuesType | undefined; + let bulkOperation: ValuesType; + + before(async () => { + response = await callApi({ + dependencyName: 'elasticsearch', + environment: 'development', }); + searchOperation = response.find((op) => op.spanName === '/_search'); + bulkOperation = response.find((op) => op.spanName === '/_bulk')!; + }); + + it('returns the correct operations', () => { + expect(response.length).to.eql(1); + + expect(searchOperation).not.to.be.ok(); + expect(bulkOperation).to.be.ok(); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/dependencies/top_spans.spec.ts b/x-pack/test/apm_api_integration/tests/dependencies/top_spans.spec.ts index 97d9846e06f57..06890c0b6fd59 100644 --- a/x-pack/test/apm_api_integration/tests/dependencies/top_spans.spec.ts +++ b/x-pack/test/apm_api_integration/tests/dependencies/top_spans.spec.ts @@ -68,7 +68,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'Top dependency spans when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { const javaInstance = apm.service('java', 'production', 'java').instance('instance-a'); diff --git a/x-pack/test/apm_api_integration/tests/dependencies/upstream_services.spec.ts b/x-pack/test/apm_api_integration/tests/dependencies/upstream_services.spec.ts index 2d3a51054541b..b2ff45685de2e 100644 --- a/x-pack/test/apm_api_integration/tests/dependencies/upstream_services.spec.ts +++ b/x-pack/test/apm_api_integration/tests/dependencies/upstream_services.spec.ts @@ -47,28 +47,24 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Dependency upstream services', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded', () => { - before(async () => { - await generateData({ synthtraceEsClient, start, end }); - }); - after(() => synthtraceEsClient.clean()); + registry.when('Dependency upstream services', { config: 'basic', archives: [] }, () => { + describe('when data is loaded', () => { + before(async () => { + await generateData({ synthtraceEsClient, start, end }); + }); + after(() => synthtraceEsClient.clean()); - it('returns a list of upstream services for the dependency', async () => { - const { status, body } = await callApi(); + it('returns a list of upstream services for the dependency', async () => { + const { status, body } = await callApi(); - expect(status).to.be(200); - expect(body.services.map(({ location }) => (location as ServiceNode).serviceName)).to.eql( - ['synth-go'] - ); + expect(status).to.be(200); + expect(body.services.map(({ location }) => (location as ServiceNode).serviceName)).to.eql([ + 'synth-go', + ]); - const currentStatsLatencyValues = body.services[0].currentStats.latency.timeseries; - expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); - }); + const currentStatsLatencyValues = body.services[0].currentStats.latency.timeseries; + expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/error_rate/service_apis.spec.ts b/x-pack/test/apm_api_integration/tests/error_rate/service_apis.spec.ts index 23cc77320b0eb..fe2f9c8cd2cf8 100644 --- a/x-pack/test/apm_api_integration/tests/error_rate/service_apis.spec.ts +++ b/x-pack/test/apm_api_integration/tests/error_rate/service_apis.spec.ts @@ -114,7 +114,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let errorRateMetricValues: Awaited>; let errorTransactionValues: Awaited>; - registry.when('Services APIs', { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, () => { + registry.when('Services APIs', { config: 'basic', archives: [] }, () => { describe('when data is loaded ', () => { const GO_PROD_LIST_RATE = 75; const GO_PROD_LIST_ERROR_RATE = 25; diff --git a/x-pack/test/apm_api_integration/tests/error_rate/service_maps.spec.ts b/x-pack/test/apm_api_integration/tests/error_rate/service_maps.spec.ts index 5374ddefc946e..8c14a203f7800 100644 --- a/x-pack/test/apm_api_integration/tests/error_rate/service_maps.spec.ts +++ b/x-pack/test/apm_api_integration/tests/error_rate/service_maps.spec.ts @@ -60,87 +60,83 @@ export default function ApiTest({ getService }: FtrProviderContext) { let errorRateMetricValues: Awaited>; let errorTransactionValues: Awaited>; - registry.when( - 'Service maps APIs', - { config: 'trial', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded ', () => { - const GO_PROD_LIST_RATE = 75; - const GO_PROD_LIST_ERROR_RATE = 25; - const GO_PROD_ID_RATE = 50; - const GO_PROD_ID_ERROR_RATE = 50; - before(async () => { - const serviceGoProdInstance = apm - .service(serviceName, 'production', 'go') - .instance('instance-a'); + registry.when('Service maps APIs', { config: 'trial', archives: [] }, () => { + describe('when data is loaded ', () => { + const GO_PROD_LIST_RATE = 75; + const GO_PROD_LIST_ERROR_RATE = 25; + const GO_PROD_ID_RATE = 50; + const GO_PROD_ID_ERROR_RATE = 50; + before(async () => { + const serviceGoProdInstance = apm + .service(serviceName, 'production', 'go') + .instance('instance-a'); - const transactionNameProductList = 'GET /api/product/list'; - const transactionNameProductId = 'GET /api/product/:id'; + const transactionNameProductList = 'GET /api/product/list'; + const transactionNameProductId = 'GET /api/product/:id'; - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(GO_PROD_LIST_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction(transactionNameProductList, 'Worker') - .timestamp(timestamp) - .duration(1000) - .success() - ), - timerange(start, end) - .interval('1m') - .rate(GO_PROD_LIST_ERROR_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction(transactionNameProductList, 'Worker') - .duration(1000) - .timestamp(timestamp) - .failure() - ), - timerange(start, end) - .interval('1m') - .rate(GO_PROD_ID_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction(transactionNameProductId) - .timestamp(timestamp) - .duration(1000) - .success() - ), - timerange(start, end) - .interval('1m') - .rate(GO_PROD_ID_ERROR_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction(transactionNameProductId) - .duration(1000) - .timestamp(timestamp) - .failure() - ), - ]); - }); + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(GO_PROD_LIST_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction(transactionNameProductList, 'Worker') + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval('1m') + .rate(GO_PROD_LIST_ERROR_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction(transactionNameProductList, 'Worker') + .duration(1000) + .timestamp(timestamp) + .failure() + ), + timerange(start, end) + .interval('1m') + .rate(GO_PROD_ID_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction(transactionNameProductId) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval('1m') + .rate(GO_PROD_ID_ERROR_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction(transactionNameProductId) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + ]); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - describe('compare latency value between service inventory and service maps', () => { - before(async () => { - [errorTransactionValues, errorRateMetricValues] = await Promise.all([ - getErrorRateValues('transaction'), - getErrorRateValues('metric'), - ]); - }); + describe('compare latency value between service inventory and service maps', () => { + before(async () => { + [errorTransactionValues, errorRateMetricValues] = await Promise.all([ + getErrorRateValues('transaction'), + getErrorRateValues('metric'), + ]); + }); - it('returns same avg error rate value for Transaction-based and Metric-based data', () => { - [ - errorTransactionValues.serviceInventoryErrorRate, - errorTransactionValues.serviceMapsNodeDetailsErrorRate, - errorRateMetricValues.serviceInventoryErrorRate, - errorRateMetricValues.serviceMapsNodeDetailsErrorRate, - ].forEach((value) => expect(value).to.be.equal(GO_PROD_ID_ERROR_RATE / 100)); - }); + it('returns same avg error rate value for Transaction-based and Metric-based data', () => { + [ + errorTransactionValues.serviceInventoryErrorRate, + errorTransactionValues.serviceMapsNodeDetailsErrorRate, + errorRateMetricValues.serviceInventoryErrorRate, + errorRateMetricValues.serviceMapsNodeDetailsErrorRate, + ].forEach((value) => expect(value).to.be.equal(GO_PROD_ID_ERROR_RATE / 100)); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/errors/distribution.spec.ts b/x-pack/test/apm_api_integration/tests/errors/distribution.spec.ts index 4cd338441eefa..6d57addcc7bb7 100644 --- a/x-pack/test/apm_api_integration/tests/errors/distribution.spec.ts +++ b/x-pack/test/apm_api_integration/tests/errors/distribution.spec.ts @@ -60,128 +60,124 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('errors distribution', () => { - const { appleTransaction, bananaTransaction } = config; + registry.when('when data is loaded', { config: 'basic', archives: [] }, () => { + describe('errors distribution', () => { + const { appleTransaction, bananaTransaction } = config; + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('without comparison', () => { + let errorsDistribution: ErrorsDistribution; before(async () => { - await generateData({ serviceName, start, end, synthtraceEsClient }); + const response = await callApi(); + errorsDistribution = response.body; }); - after(() => synthtraceEsClient.clean()); - - describe('without comparison', () => { - let errorsDistribution: ErrorsDistribution; - before(async () => { - const response = await callApi(); - errorsDistribution = response.body; - }); + it('displays combined number of occurrences', () => { + const countSum = sumBy(errorsDistribution.currentPeriod, 'y'); + const numberOfBuckets = 15; + expect(countSum).to.equal( + (appleTransaction.failureRate + bananaTransaction.failureRate) * numberOfBuckets + ); + }); + }); - it('displays combined number of occurrences', () => { - const countSum = sumBy(errorsDistribution.currentPeriod, 'y'); - const numberOfBuckets = 15; - expect(countSum).to.equal( - (appleTransaction.failureRate + bananaTransaction.failureRate) * numberOfBuckets - ); + describe('displays occurrences for type "apple transaction" only', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const response = await callApi({ + query: { kuery: `error.exception.type:"${appleTransaction.name}"` }, }); + errorsDistribution = response.body; }); + it('displays combined number of occurrences', () => { + const countSum = sumBy(errorsDistribution.currentPeriod, 'y'); + const numberOfBuckets = 15; + expect(countSum).to.equal(appleTransaction.failureRate * numberOfBuckets); + }); + }); - describe('displays occurrences for type "apple transaction" only', () => { + describe('with comparison', () => { + describe('when data is returned', () => { let errorsDistribution: ErrorsDistribution; before(async () => { + const fiveMinutes = 5 * 60 * 1000; const response = await callApi({ - query: { kuery: `error.exception.type:"${appleTransaction.name}"` }, + query: { + start: new Date(end - fiveMinutes).toISOString(), + end: new Date(end).toISOString(), + offset: '5m', + }, }); errorsDistribution = response.body; }); - it('displays combined number of occurrences', () => { - const countSum = sumBy(errorsDistribution.currentPeriod, 'y'); - const numberOfBuckets = 15; - expect(countSum).to.equal(appleTransaction.failureRate * numberOfBuckets); - }); - }); - - describe('with comparison', () => { - describe('when data is returned', () => { - let errorsDistribution: ErrorsDistribution; - before(async () => { - const fiveMinutes = 5 * 60 * 1000; - const response = await callApi({ - query: { - start: new Date(end - fiveMinutes).toISOString(), - end: new Date(end).toISOString(), - offset: '5m', - }, - }); - errorsDistribution = response.body; - }); - it('returns some data', () => { - const hasCurrentPeriodData = errorsDistribution.currentPeriod.some(({ y }) => - isFiniteNumber(y) - ); + it('returns some data', () => { + const hasCurrentPeriodData = errorsDistribution.currentPeriod.some(({ y }) => + isFiniteNumber(y) + ); - const hasPreviousPeriodData = errorsDistribution.previousPeriod.some(({ y }) => - isFiniteNumber(y) - ); + const hasPreviousPeriodData = errorsDistribution.previousPeriod.some(({ y }) => + isFiniteNumber(y) + ); - expect(hasCurrentPeriodData).to.equal(true); - expect(hasPreviousPeriodData).to.equal(true); - }); + expect(hasCurrentPeriodData).to.equal(true); + expect(hasPreviousPeriodData).to.equal(true); + }); - it('has same start time for both periods', () => { - expect(first(errorsDistribution.currentPeriod)?.x).to.equal( - first(errorsDistribution.previousPeriod)?.x - ); - }); + it('has same start time for both periods', () => { + expect(first(errorsDistribution.currentPeriod)?.x).to.equal( + first(errorsDistribution.previousPeriod)?.x + ); + }); - it('has same end time for both periods', () => { - expect(last(errorsDistribution.currentPeriod)?.x).to.equal( - last(errorsDistribution.previousPeriod)?.x - ); - }); + it('has same end time for both periods', () => { + expect(last(errorsDistribution.currentPeriod)?.x).to.equal( + last(errorsDistribution.previousPeriod)?.x + ); + }); - it('returns same number of buckets for both periods', () => { - expect(errorsDistribution.currentPeriod.length).to.equal( - errorsDistribution.previousPeriod.length - ); - }); + it('returns same number of buckets for both periods', () => { + expect(errorsDistribution.currentPeriod.length).to.equal( + errorsDistribution.previousPeriod.length + ); }); + }); - describe('when no data is returned', () => { - let errorsDistribution: ErrorsDistribution; - before(async () => { - const response = await callApi({ - query: { - start: '2021-01-03T00:00:00.000Z', - end: '2021-01-03T00:15:00.000Z', - offset: '1d', - }, - }); - errorsDistribution = response.body; + describe('when no data is returned', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const response = await callApi({ + query: { + start: '2021-01-03T00:00:00.000Z', + end: '2021-01-03T00:15:00.000Z', + offset: '1d', + }, }); + errorsDistribution = response.body; + }); - it('has same start time for both periods', () => { - expect(first(errorsDistribution.currentPeriod)?.x).to.equal( - first(errorsDistribution.previousPeriod)?.x - ); - }); + it('has same start time for both periods', () => { + expect(first(errorsDistribution.currentPeriod)?.x).to.equal( + first(errorsDistribution.previousPeriod)?.x + ); + }); - it('has same end time for both periods', () => { - expect(last(errorsDistribution.currentPeriod)?.x).to.equal( - last(errorsDistribution.previousPeriod)?.x - ); - }); + it('has same end time for both periods', () => { + expect(last(errorsDistribution.currentPeriod)?.x).to.equal( + last(errorsDistribution.previousPeriod)?.x + ); + }); - it('returns same number of buckets for both periods', () => { - expect(errorsDistribution.currentPeriod.length).to.equal( - errorsDistribution.previousPeriod.length - ); - }); + it('returns same number of buckets for both periods', () => { + expect(errorsDistribution.currentPeriod.length).to.equal( + errorsDistribution.previousPeriod.length + ); }); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/errors/error_group_list.spec.ts b/x-pack/test/apm_api_integration/tests/errors/error_group_list.spec.ts index db630ba71cd18..5156ed7f05478 100644 --- a/x-pack/test/apm_api_integration/tests/errors/error_group_list.spec.ts +++ b/x-pack/test/apm_api_integration/tests/errors/error_group_list.spec.ts @@ -53,97 +53,91 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('errors group', () => { - const appleTransaction = { - name: 'GET /apple 🍎 ', - successRate: 75, - failureRate: 25, - }; + registry.when('when data is loaded', { config: 'basic', archives: [] }, () => { + describe('errors group', () => { + const appleTransaction = { + name: 'GET /apple 🍎 ', + successRate: 75, + failureRate: 25, + }; - const bananaTransaction = { - name: 'GET /banana 🍌', - successRate: 50, - failureRate: 50, - }; + const bananaTransaction = { + name: 'GET /banana 🍌', + successRate: 50, + failureRate: 50, + }; - before(async () => { - const serviceInstance = apm - .service(serviceName, 'production', 'go') - .instance('instance-a'); + before(async () => { + const serviceInstance = apm.service(serviceName, 'production', 'go').instance('instance-a'); - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(appleTransaction.successRate) - .generator((timestamp) => - serviceInstance - .transaction(appleTransaction.name) - .timestamp(timestamp) - .duration(1000) - .success() - ), - timerange(start, end) - .interval('1m') - .rate(appleTransaction.failureRate) - .generator((timestamp) => - serviceInstance - .transaction(appleTransaction.name) - .errors(serviceInstance.error('error 1', 'foo').timestamp(timestamp)) - .duration(1000) - .timestamp(timestamp) - .failure() - ), - timerange(start, end) - .interval('1m') - .rate(bananaTransaction.successRate) - .generator((timestamp) => - serviceInstance - .transaction(bananaTransaction.name) - .timestamp(timestamp) - .duration(1000) - .success() - ), - timerange(start, end) - .interval('1m') - .rate(bananaTransaction.failureRate) - .generator((timestamp) => - serviceInstance - .transaction(bananaTransaction.name) - .errors(serviceInstance.error('error 2', 'bar').timestamp(timestamp)) - .duration(1000) - .timestamp(timestamp) - .failure() - ), - ]); - }); + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(appleTransaction.successRate) + .generator((timestamp) => + serviceInstance + .transaction(appleTransaction.name) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval('1m') + .rate(appleTransaction.failureRate) + .generator((timestamp) => + serviceInstance + .transaction(appleTransaction.name) + .errors(serviceInstance.error('error 1', 'foo').timestamp(timestamp)) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + timerange(start, end) + .interval('1m') + .rate(bananaTransaction.successRate) + .generator((timestamp) => + serviceInstance + .transaction(bananaTransaction.name) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval('1m') + .rate(bananaTransaction.failureRate) + .generator((timestamp) => + serviceInstance + .transaction(bananaTransaction.name) + .errors(serviceInstance.error('error 2', 'bar').timestamp(timestamp)) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + ]); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - describe('returns the correct data', () => { - let errorGroups: ErrorGroups; - before(async () => { - const response = await callApi(); - errorGroups = response.body.errorGroups; - }); + describe('returns the correct data', () => { + let errorGroups: ErrorGroups; + before(async () => { + const response = await callApi(); + errorGroups = response.body.errorGroups; + }); - it('returns correct number of errors', () => { - expect(errorGroups.length).to.equal(2); - expect(errorGroups.map((error) => error.name).sort()).to.eql(['error 1', 'error 2']); - }); + it('returns correct number of errors', () => { + expect(errorGroups.length).to.equal(2); + expect(errorGroups.map((error) => error.name).sort()).to.eql(['error 1', 'error 2']); + }); - it('returns correct occurences', () => { - const numberOfBuckets = 15; - expect(errorGroups.map((error) => error.occurrences).sort()).to.eql([ - appleTransaction.failureRate * numberOfBuckets, - bananaTransaction.failureRate * numberOfBuckets, - ]); - }); + it('returns correct occurences', () => { + const numberOfBuckets = 15; + expect(errorGroups.map((error) => error.occurrences).sort()).to.eql([ + appleTransaction.failureRate * numberOfBuckets, + bananaTransaction.failureRate * numberOfBuckets, + ]); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/errors/group_id.spec.ts b/x-pack/test/apm_api_integration/tests/errors/group_id.spec.ts index af9a3d01f08a7..93965744c4ff3 100644 --- a/x-pack/test/apm_api_integration/tests/errors/group_id.spec.ts +++ b/x-pack/test/apm_api_integration/tests/errors/group_id.spec.ts @@ -58,35 +58,31 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - const { bananaTransaction } = config; - describe('error group id', () => { - before(async () => { - await generateData({ serviceName, start, end, synthtraceEsClient }); - }); + registry.when('when data is loaded', { config: 'basic', archives: [] }, () => { + const { bananaTransaction } = config; + describe('error group id', () => { + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - describe('return correct data', () => { - let errorsDistribution: ErrorsDistribution; - before(async () => { - const response = await callApi({ - path: { groupId: '0000000000000000000000000Error 1' }, - }); - errorsDistribution = response.body; + describe('return correct data', () => { + let errorsDistribution: ErrorsDistribution; + before(async () => { + const response = await callApi({ + path: { groupId: '0000000000000000000000000Error 1' }, }); + errorsDistribution = response.body; + }); - it('displays correct number of occurrences', () => { - const numberOfBuckets = 15; - expect(errorsDistribution.occurrencesCount).to.equal( - bananaTransaction.failureRate * numberOfBuckets - ); - }); + it('displays correct number of occurrences', () => { + const numberOfBuckets = 15; + expect(errorsDistribution.occurrencesCount).to.equal( + bananaTransaction.failureRate * numberOfBuckets + ); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/errors/top_erroneous_transactions/top_erroneous_transactions.spec.ts b/x-pack/test/apm_api_integration/tests/errors/top_erroneous_transactions/top_erroneous_transactions.spec.ts index 8e8078e00ab7a..cd01ca49afcc5 100644 --- a/x-pack/test/apm_api_integration/tests/errors/top_erroneous_transactions/top_erroneous_transactions.spec.ts +++ b/x-pack/test/apm_api_integration/tests/errors/top_erroneous_transactions/top_erroneous_transactions.spec.ts @@ -63,149 +63,141 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - const { - firstTransaction: { name: firstTransactionName, failureRate: firstTransactionFailureRate }, - secondTransaction: { - name: secondTransactionName, - failureRate: secondTransactionFailureRate, - }, - } = config; + registry.when('when data is loaded', { config: 'basic', archives: [] }, () => { + const { + firstTransaction: { name: firstTransactionName, failureRate: firstTransactionFailureRate }, + secondTransaction: { name: secondTransactionName, failureRate: secondTransactionFailureRate }, + } = config; + + describe('returns the correct data', () => { + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('without comparison', () => { + const numberOfBuckets = 15; + let erroneousTransactions: ErroneousTransactions; - describe('returns the correct data', () => { before(async () => { - await generateData({ serviceName, start, end, synthtraceEsClient }); + const response = await callApi({ + path: { groupId: '0000000000000000000000Error test' }, + }); + erroneousTransactions = response.body; }); - after(() => synthtraceEsClient.clean()); + it('displays the correct number of occurrences', () => { + const { topErroneousTransactions } = erroneousTransactions; + expect(topErroneousTransactions.length).to.be(2); + + const firstTransaction = topErroneousTransactions.find( + (x) => x.transactionName === firstTransactionName + ); + expect(firstTransaction).to.not.be(undefined); + expect(firstTransaction?.occurrences).to.be( + firstTransactionFailureRate * numberOfBuckets + ); + + const secondTransaction = topErroneousTransactions.find( + (x) => x.transactionName === secondTransactionName + ); + expect(secondTransaction).to.not.be(undefined); + expect(secondTransaction?.occurrences).to.be( + secondTransactionFailureRate * numberOfBuckets + ); + }); + + it('displays the correct number of occurrences in time series', () => { + const { topErroneousTransactions } = erroneousTransactions; + + const firstTransaction = topErroneousTransactions.find( + (x) => x.transactionName === firstTransactionName + ); + const firstErrorCount = sumBy(firstTransaction?.currentPeriodTimeseries, 'y'); + expect(firstErrorCount).to.be(firstTransactionFailureRate * numberOfBuckets); + + const secondTransaction = topErroneousTransactions.find( + (x) => x.transactionName === secondTransactionName + ); + const secondErrorCount = sumBy(secondTransaction?.currentPeriodTimeseries, 'y'); + expect(secondErrorCount).to.be(secondTransactionFailureRate * numberOfBuckets); + }); + }); - describe('without comparison', () => { - const numberOfBuckets = 15; + describe('with comparison', () => { + describe('when there are data for the time periods', () => { let erroneousTransactions: ErroneousTransactions; before(async () => { + const fiveMinutes = 5 * 60 * 1000; const response = await callApi({ path: { groupId: '0000000000000000000000Error test' }, + query: { + start: new Date(end - fiveMinutes).toISOString(), + end: new Date(end).toISOString(), + offset: '5m', + }, }); erroneousTransactions = response.body; }); - it('displays the correct number of occurrences', () => { + it('returns some data', () => { const { topErroneousTransactions } = erroneousTransactions; - expect(topErroneousTransactions.length).to.be(2); - const firstTransaction = topErroneousTransactions.find( - (x) => x.transactionName === firstTransactionName - ); - expect(firstTransaction).to.not.be(undefined); - expect(firstTransaction?.occurrences).to.be( - firstTransactionFailureRate * numberOfBuckets + const hasCurrentPeriodData = topErroneousTransactions[0].currentPeriodTimeseries.some( + ({ y }) => isFiniteNumber(y) ); - const secondTransaction = topErroneousTransactions.find( - (x) => x.transactionName === secondTransactionName - ); - expect(secondTransaction).to.not.be(undefined); - expect(secondTransaction?.occurrences).to.be( - secondTransactionFailureRate * numberOfBuckets + const hasPreviousPeriodData = topErroneousTransactions[0].previousPeriodTimeseries.some( + ({ y }) => isFiniteNumber(y) ); + + expect(hasCurrentPeriodData).to.be(true); + expect(hasPreviousPeriodData).to.be(true); }); - it('displays the correct number of occurrences in time series', () => { + it('has the same start time for both periods', () => { const { topErroneousTransactions } = erroneousTransactions; + expect(first(topErroneousTransactions[0].currentPeriodTimeseries)?.x).to.be( + first(topErroneousTransactions[0].previousPeriodTimeseries)?.x + ); + }); - const firstTransaction = topErroneousTransactions.find( - (x) => x.transactionName === firstTransactionName + it('has same end time for both periods', () => { + const { topErroneousTransactions } = erroneousTransactions; + expect(last(topErroneousTransactions[0].currentPeriodTimeseries)?.x).to.be( + last(topErroneousTransactions[0].previousPeriodTimeseries)?.x ); - const firstErrorCount = sumBy(firstTransaction?.currentPeriodTimeseries, 'y'); - expect(firstErrorCount).to.be(firstTransactionFailureRate * numberOfBuckets); + }); - const secondTransaction = topErroneousTransactions.find( - (x) => x.transactionName === secondTransactionName + it('returns same number of buckets for both periods', () => { + const { topErroneousTransactions } = erroneousTransactions; + expect(topErroneousTransactions[0].currentPeriodTimeseries.length).to.be( + topErroneousTransactions[0].previousPeriodTimeseries.length ); - const secondErrorCount = sumBy(secondTransaction?.currentPeriodTimeseries, 'y'); - expect(secondErrorCount).to.be(secondTransactionFailureRate * numberOfBuckets); }); }); - describe('with comparison', () => { - describe('when there are data for the time periods', () => { - let erroneousTransactions: ErroneousTransactions; - - before(async () => { - const fiveMinutes = 5 * 60 * 1000; - const response = await callApi({ - path: { groupId: '0000000000000000000000Error test' }, - query: { - start: new Date(end - fiveMinutes).toISOString(), - end: new Date(end).toISOString(), - offset: '5m', - }, - }); - erroneousTransactions = response.body; - }); - - it('returns some data', () => { - const { topErroneousTransactions } = erroneousTransactions; - - const hasCurrentPeriodData = topErroneousTransactions[0].currentPeriodTimeseries.some( - ({ y }) => isFiniteNumber(y) - ); - - const hasPreviousPeriodData = - topErroneousTransactions[0].previousPeriodTimeseries.some(({ y }) => - isFiniteNumber(y) - ); - - expect(hasCurrentPeriodData).to.be(true); - expect(hasPreviousPeriodData).to.be(true); - }); - - it('has the same start time for both periods', () => { - const { topErroneousTransactions } = erroneousTransactions; - expect(first(topErroneousTransactions[0].currentPeriodTimeseries)?.x).to.be( - first(topErroneousTransactions[0].previousPeriodTimeseries)?.x - ); - }); - - it('has same end time for both periods', () => { - const { topErroneousTransactions } = erroneousTransactions; - expect(last(topErroneousTransactions[0].currentPeriodTimeseries)?.x).to.be( - last(topErroneousTransactions[0].previousPeriodTimeseries)?.x - ); + describe('when there are no data for the time period', () => { + it('returns an empty array', async () => { + const response = await callApi({ + path: { groupId: '0000000000000000000000Error test' }, + query: { + start: '2021-01-03T00:00:00.000Z', + end: '2021-01-03T00:15:00.000Z', + offset: '1d', + }, }); - it('returns same number of buckets for both periods', () => { - const { topErroneousTransactions } = erroneousTransactions; - expect(topErroneousTransactions[0].currentPeriodTimeseries.length).to.be( - topErroneousTransactions[0].previousPeriodTimeseries.length - ); - }); - }); + const { + body: { topErroneousTransactions }, + } = response; - describe('when there are no data for the time period', () => { - it('returns an empty array', async () => { - const response = await callApi({ - path: { groupId: '0000000000000000000000Error test' }, - query: { - start: '2021-01-03T00:00:00.000Z', - end: '2021-01-03T00:15:00.000Z', - offset: '1d', - }, - }); - - const { - body: { topErroneousTransactions }, - } = response; - - expect(topErroneousTransactions).to.be.empty(); - }); + expect(topErroneousTransactions).to.be.empty(); }); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/errors/top_errors_for_transaction/top_errors_main_stats.spec.ts b/x-pack/test/apm_api_integration/tests/errors/top_errors_for_transaction/top_errors_main_stats.spec.ts index 75d3ba0624375..830e5032a8de7 100644 --- a/x-pack/test/apm_api_integration/tests/errors/top_errors_for_transaction/top_errors_main_stats.spec.ts +++ b/x-pack/test/apm_api_integration/tests/errors/top_errors_for_transaction/top_errors_main_stats.spec.ts @@ -58,54 +58,47 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('top errors for transaction', () => { - const { - firstTransaction: { - name: firstTransactionName, - failureRate: firstTransactionFailureRate, - }, - } = config; + registry.when('when data is loaded', { config: 'basic', archives: [] }, () => { + describe('top errors for transaction', () => { + const { + firstTransaction: { name: firstTransactionName, failureRate: firstTransactionFailureRate }, + } = config; - before(async () => { - await generateData({ serviceName, start, end, synthtraceEsClient }); - }); + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - describe('returns the correct data', () => { - let errorGroups: ErrorGroups; - before(async () => { - const response = await callApi({ query: { transactionName: firstTransactionName } }); - errorGroups = response.body.errorGroups; - }); + describe('returns the correct data', () => { + let errorGroups: ErrorGroups; + before(async () => { + const response = await callApi({ query: { transactionName: firstTransactionName } }); + errorGroups = response.body.errorGroups; + }); - it('returns correct number of errors and error data', () => { - const numberOfBuckets = 15; + it('returns correct number of errors and error data', () => { + const numberOfBuckets = 15; - expect(errorGroups.length).to.equal(2); + expect(errorGroups.length).to.equal(2); - const firstErrorId = `Error 1 transaction ${firstTransactionName}`; - const firstError = errorGroups.find((x) => x.groupId === firstErrorId); - expect(firstError).to.not.be(undefined); - expect(firstError?.groupId).to.be(firstErrorId); - expect(firstError?.name).to.be(firstErrorId); - expect(firstError?.occurrences).to.be(firstTransactionFailureRate * numberOfBuckets); - expect(firstError?.lastSeen).to.be(moment(end).startOf('minute').valueOf()); + const firstErrorId = `Error 1 transaction ${firstTransactionName}`; + const firstError = errorGroups.find((x) => x.groupId === firstErrorId); + expect(firstError).to.not.be(undefined); + expect(firstError?.groupId).to.be(firstErrorId); + expect(firstError?.name).to.be(firstErrorId); + expect(firstError?.occurrences).to.be(firstTransactionFailureRate * numberOfBuckets); + expect(firstError?.lastSeen).to.be(moment(end).startOf('minute').valueOf()); - const secondErrorId = `Error 2 transaction ${firstTransactionName}`; - const secondError = errorGroups.find((x) => x.groupId === secondErrorId); - expect(secondError).to.not.be(undefined); - expect(secondError?.groupId).to.be(secondErrorId); - expect(secondError?.name).to.be(secondErrorId); - expect(secondError?.occurrences).to.be(firstTransactionFailureRate * numberOfBuckets); - expect(secondError?.lastSeen).to.be(moment(end).startOf('minute').valueOf()); - }); + const secondErrorId = `Error 2 transaction ${firstTransactionName}`; + const secondError = errorGroups.find((x) => x.groupId === secondErrorId); + expect(secondError).to.not.be(undefined); + expect(secondError?.groupId).to.be(secondErrorId); + expect(secondError?.name).to.be(secondErrorId); + expect(secondError?.occurrences).to.be(firstTransactionFailureRate * numberOfBuckets); + expect(secondError?.lastSeen).to.be(moment(end).startOf('minute').valueOf()); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/infrastructure/infrastructure_attributes.spec.ts b/x-pack/test/apm_api_integration/tests/infrastructure/infrastructure_attributes.spec.ts index 39a45a9b396c7..19df367035911 100644 --- a/x-pack/test/apm_api_integration/tests/infrastructure/infrastructure_attributes.spec.ts +++ b/x-pack/test/apm_api_integration/tests/infrastructure/infrastructure_attributes.spec.ts @@ -48,39 +48,33 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Infrastructure attributes', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded', () => { - beforeEach(async () => { - await generateData({ start, end, synthtraceEsClient }); - }); + registry.when('Infrastructure attributes', { config: 'basic', archives: [] }, () => { + describe('when data is loaded', () => { + beforeEach(async () => { + await generateData({ start, end, synthtraceEsClient }); + }); - afterEach(() => synthtraceEsClient.clean()); + afterEach(() => synthtraceEsClient.clean()); - describe('when service runs in container', () => { - it('returns arrays of container ids and pod names', async () => { - const response = await callApi('synth-go'); - expect(response.status).to.be(200); - expect(response.body.containerIds.length).to.be(1); - // hostNames is always returning empty - // we can not test the infra indices api call with synthtrace - expect(response.body.hostNames.length).to.be(0); - expect(response.body.podNames.length).to.be(1); - }); + describe('when service runs in container', () => { + it('returns arrays of container ids and pod names', async () => { + const response = await callApi('synth-go'); + expect(response.status).to.be(200); + expect(response.body.containerIds.length).to.be(1); + expect(response.body.hostNames.length).to.be(1); + expect(response.body.podNames.length).to.be(1); }); + }); - describe('when service does NOT run in container', () => { - it('returns array of host names', async () => { - const response = await callApi('synth-java'); - expect(response.status).to.be(200); - expect(response.body.containerIds.length).to.be(0); - expect(response.body.hostNames.length).to.be(1); - expect(response.body.podNames.length).to.be(0); - }); + describe('when service does NOT run in container', () => { + it('returns array of host names', async () => { + const response = await callApi('synth-java'); + expect(response.status).to.be(200); + expect(response.body.containerIds.length).to.be(0); + expect(response.body.hostNames.length).to.be(1); + expect(response.body.podNames.length).to.be(0); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/latency/service_apis.spec.ts b/x-pack/test/apm_api_integration/tests/latency/service_apis.spec.ts index 1ad8322443e1a..b38a7ef3052c2 100644 --- a/x-pack/test/apm_api_integration/tests/latency/service_apis.spec.ts +++ b/x-pack/test/apm_api_integration/tests/latency/service_apis.spec.ts @@ -116,7 +116,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let latencyMetricValues: Awaited>; let latencyTransactionValues: Awaited>; - registry.when('Services APIs', { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, () => { + registry.when('Services APIs', { config: 'basic', archives: [] }, () => { describe('when data is loaded ', () => { const GO_PROD_RATE = 80; const GO_DEV_RATE = 20; diff --git a/x-pack/test/apm_api_integration/tests/latency/service_maps.spec.ts b/x-pack/test/apm_api_integration/tests/latency/service_maps.spec.ts index e898dbb67f2e5..e9b9749b659e2 100644 --- a/x-pack/test/apm_api_integration/tests/latency/service_maps.spec.ts +++ b/x-pack/test/apm_api_integration/tests/latency/service_maps.spec.ts @@ -59,68 +59,63 @@ export default function ApiTest({ getService }: FtrProviderContext) { let latencyMetricValues: Awaited>; let latencyTransactionValues: Awaited>; - registry.when( - 'Service maps APIs', - { config: 'trial', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded ', () => { - const GO_PROD_RATE = 80; - const GO_DEV_RATE = 20; - const GO_PROD_DURATION = 1000; - const GO_DEV_DURATION = 500; - before(async () => { - const serviceGoProdInstance = apm - .service(serviceName, 'production', 'go') - .instance('instance-a'); - const serviceGoDevInstance = apm - .service(serviceName, 'development', 'go') - .instance('instance-b'); + registry.when('Service maps APIs', { config: 'trial', archives: [] }, () => { + describe('when data is loaded ', () => { + const GO_PROD_RATE = 80; + const GO_DEV_RATE = 20; + const GO_PROD_DURATION = 1000; + const GO_DEV_DURATION = 500; + before(async () => { + const serviceGoProdInstance = apm + .service(serviceName, 'production', 'go') + .instance('instance-a'); + const serviceGoDevInstance = apm + .service(serviceName, 'development', 'go') + .instance('instance-b'); - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(GO_PROD_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction('GET /api/product/list', 'Worker') - .duration(GO_PROD_DURATION) - .timestamp(timestamp) - ), - timerange(start, end) - .interval('1m') - .rate(GO_DEV_RATE) - .generator((timestamp) => - serviceGoDevInstance - .transaction('GET /api/product/:id') - .duration(GO_DEV_DURATION) - .timestamp(timestamp) - ), - ]); - }); + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(GO_PROD_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction('GET /api/product/list', 'Worker') + .duration(GO_PROD_DURATION) + .timestamp(timestamp) + ), + timerange(start, end) + .interval('1m') + .rate(GO_DEV_RATE) + .generator((timestamp) => + serviceGoDevInstance + .transaction('GET /api/product/:id') + .duration(GO_DEV_DURATION) + .timestamp(timestamp) + ), + ]); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - describe('compare latency value between service inventory and service maps', () => { - before(async () => { - [latencyTransactionValues, latencyMetricValues] = await Promise.all([ - getLatencyValues('transaction'), - getLatencyValues('metric'), - ]); - }); + describe('compare latency value between service inventory and service maps', () => { + before(async () => { + [latencyTransactionValues, latencyMetricValues] = await Promise.all([ + getLatencyValues('transaction'), + getLatencyValues('metric'), + ]); + }); - it('returns same avg latency value for Transaction-based and Metric-based data', () => { - const expectedLatencyAvgValueMs = - ((GO_DEV_RATE * GO_DEV_DURATION) / GO_DEV_RATE) * 1000; + it('returns same avg latency value for Transaction-based and Metric-based data', () => { + const expectedLatencyAvgValueMs = ((GO_DEV_RATE * GO_DEV_DURATION) / GO_DEV_RATE) * 1000; - [ - latencyTransactionValues.serviceMapsNodeDetailsLatency, - latencyTransactionValues.serviceInventoryLatency, - latencyMetricValues.serviceMapsNodeDetailsLatency, - latencyMetricValues.serviceInventoryLatency, - ].forEach((value) => expect(value).to.be.equal(expectedLatencyAvgValueMs)); - }); + [ + latencyTransactionValues.serviceMapsNodeDetailsLatency, + latencyTransactionValues.serviceInventoryLatency, + latencyMetricValues.serviceMapsNodeDetailsLatency, + latencyMetricValues.serviceInventoryLatency, + ].forEach((value) => expect(value).to.be.equal(expectedLatencyAvgValueMs)); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.spec.ts b/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.spec.ts index e924fc865c42f..d25b17cc0dc6b 100644 --- a/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.spec.ts +++ b/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.spec.ts @@ -83,93 +83,87 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('Observability overview api ', () => { - const GO_PROD_RATE = 50; - const GO_DEV_RATE = 5; - const JAVA_PROD_RATE = 45; - before(async () => { - const serviceGoProdInstance = apm - .service('synth-go', 'production', 'go') - .instance('instance-a'); - const serviceGoDevInstance = apm - .service('synth-go', 'development', 'go') - .instance('instance-b'); + registry.when('data is loaded', { config: 'basic', archives: [] }, () => { + describe('Observability overview api ', () => { + const GO_PROD_RATE = 50; + const GO_DEV_RATE = 5; + const JAVA_PROD_RATE = 45; + before(async () => { + const serviceGoProdInstance = apm + .service('synth-go', 'production', 'go') + .instance('instance-a'); + const serviceGoDevInstance = apm + .service('synth-go', 'development', 'go') + .instance('instance-b'); - const serviceJavaInstance = apm - .service('synth-java', 'production', 'java') - .instance('instance-c'); + const serviceJavaInstance = apm + .service('synth-java', 'production', 'java') + .instance('instance-c'); - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(GO_PROD_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction('GET /api/product/list') - .duration(1000) - .timestamp(timestamp) - ), - timerange(start, end) - .interval('1m') - .rate(GO_DEV_RATE) - .generator((timestamp) => - serviceGoDevInstance - .transaction('GET /api/product/:id') - .duration(1000) - .timestamp(timestamp) - ), - timerange(start, end) - .interval('1m') - .rate(JAVA_PROD_RATE) - .generator((timestamp) => - serviceJavaInstance - .transaction('POST /api/product/buy') - .duration(1000) - .timestamp(timestamp) - ), - ]); - }); + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(GO_PROD_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction('GET /api/product/list') + .duration(1000) + .timestamp(timestamp) + ), + timerange(start, end) + .interval('1m') + .rate(GO_DEV_RATE) + .generator((timestamp) => + serviceGoDevInstance + .transaction('GET /api/product/:id') + .duration(1000) + .timestamp(timestamp) + ), + timerange(start, end) + .interval('1m') + .rate(JAVA_PROD_RATE) + .generator((timestamp) => + serviceJavaInstance + .transaction('POST /api/product/buy') + .duration(1000) + .timestamp(timestamp) + ), + ]); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - describe('compare throughput values', () => { - let throughputValues: Awaited>; - before(async () => { - throughputValues = await getThroughputValues(); - }); + describe('compare throughput values', () => { + let throughputValues: Awaited>; + before(async () => { + throughputValues = await getThroughputValues(); + }); - it('returns same number of service as shown on service inventory API', () => { - const { serviceInventoryCount, observabilityOverview } = throughputValues; - [serviceInventoryCount, observabilityOverview.serviceCount].forEach((value) => - expect(value).to.be.equal(2) - ); - }); + it('returns same number of service as shown on service inventory API', () => { + const { serviceInventoryCount, observabilityOverview } = throughputValues; + [serviceInventoryCount, observabilityOverview.serviceCount].forEach((value) => + expect(value).to.be.equal(2) + ); + }); - it('returns same throughput value on service inventory and obs throughput count', () => { - const { serviceInventoryThroughputSum, observabilityOverview } = throughputValues; - const obsThroughputCount = roundNumber( - observabilityOverview.transactionPerMinute.value - ); - [serviceInventoryThroughputSum, obsThroughputCount].forEach((value) => - expect(value).to.be.equal(roundNumber(GO_PROD_RATE + GO_DEV_RATE + JAVA_PROD_RATE)) - ); - }); + it('returns same throughput value on service inventory and obs throughput count', () => { + const { serviceInventoryThroughputSum, observabilityOverview } = throughputValues; + const obsThroughputCount = roundNumber(observabilityOverview.transactionPerMinute.value); + [serviceInventoryThroughputSum, obsThroughputCount].forEach((value) => + expect(value).to.be.equal(roundNumber(GO_PROD_RATE + GO_DEV_RATE + JAVA_PROD_RATE)) + ); + }); - it('returns same throughput value on service inventory and obs mean throughput timeseries', () => { - const { serviceInventoryThroughputSum, observabilityOverview } = throughputValues; - const obsThroughputMean = roundNumber( - meanBy(observabilityOverview.transactionPerMinute.timeseries, 'y') - ); - [serviceInventoryThroughputSum, obsThroughputMean].forEach((value) => - expect(value).to.be.equal(roundNumber(GO_PROD_RATE + GO_DEV_RATE + JAVA_PROD_RATE)) - ); - }); + it('returns same throughput value on service inventory and obs mean throughput timeseries', () => { + const { serviceInventoryThroughputSum, observabilityOverview } = throughputValues; + const obsThroughputMean = roundNumber( + meanBy(observabilityOverview.transactionPerMinute.timeseries, 'y') + ); + [serviceInventoryThroughputSum, obsThroughputMean].forEach((value) => + expect(value).to.be.equal(roundNumber(GO_PROD_RATE + GO_DEV_RATE + JAVA_PROD_RATE)) + ); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/service_nodes/get_service_nodes.spec.ts b/x-pack/test/apm_api_integration/tests/service_nodes/get_service_nodes.spec.ts index a6c53e0bade05..c582c929c67cb 100644 --- a/x-pack/test/apm_api_integration/tests/service_nodes/get_service_nodes.spec.ts +++ b/x-pack/test/apm_api_integration/tests/service_nodes/get_service_nodes.spec.ts @@ -48,36 +48,33 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'Service nodes when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - before(async () => { - const instance = apm.service(serviceName, 'production', 'go').instance(instanceName); - await synthtraceEsClient.index( - timerange(start, end) - .interval('1m') - .rate(1) - .generator((timestamp) => - instance - .appMetrics({ - 'system.process.cpu.total.norm.pct': 1, - 'jvm.memory.heap.used': 1000, - 'jvm.memory.non_heap.used': 100, - 'jvm.thread.count': 25, - }) - .timestamp(timestamp) - ) - ); - }); - after(() => synthtraceEsClient.clean()); + registry.when('Service nodes when data is loaded', { config: 'basic', archives: [] }, () => { + before(async () => { + const instance = apm.service(serviceName, 'production', 'go').instance(instanceName); + await synthtraceEsClient.index( + timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => + instance + .appMetrics({ + 'system.process.cpu.total.norm.pct': 1, + 'jvm.memory.heap.used': 1000, + 'jvm.memory.non_heap.used': 100, + 'jvm.thread.count': 25, + }) + .timestamp(timestamp) + ) + ); + }); + after(() => synthtraceEsClient.clean()); - it('returns service nodes', async () => { - const response = await callApi(); + it('returns service nodes', async () => { + const response = await callApi(); - expect(response.status).to.be(200); + expect(response.status).to.be(200); - expectSnapshot(response.body).toMatchInline(` + expectSnapshot(response.body).toMatchInline(` Object { "serviceNodes": Array [ Object { @@ -91,7 +88,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { ], } `); - }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.spec.ts b/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.spec.ts index 8d92ec6a38573..8313ec635c69a 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.spec.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.spec.ts @@ -283,7 +283,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'Service overview instances main statistics when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { describe('for two go instances and one java instance', () => { const GO_A_INSTANCE_RATE_SUCCESS = 10; diff --git a/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_detailed_statistics.spec.ts b/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_detailed_statistics.spec.ts index d6dc2bfb4b9ed..b9db3ae5e8fdd 100644 --- a/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_detailed_statistics.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_detailed_statistics.spec.ts @@ -64,136 +64,130 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Error groups detailed statistics', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded', () => { - const { PROD_LIST_ERROR_RATE, PROD_ID_ERROR_RATE } = config; + registry.when('Error groups detailed statistics', { config: 'basic', archives: [] }, () => { + describe('when data is loaded', () => { + const { PROD_LIST_ERROR_RATE, PROD_ID_ERROR_RATE } = config; + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + describe('without data comparison', () => { + let errorGroupsDetailedStatistics: ErrorGroupsDetailedStatistics; + let errorIds: string[] = []; before(async () => { - await generateData({ serviceName, start, end, synthtraceEsClient }); + errorIds = await getErrorGroupIds({ serviceName, start, end, apmApiClient }); + const response = await callApi({ + body: { + groupIds: JSON.stringify(errorIds), + }, + }); + errorGroupsDetailedStatistics = response.body; + }); + + it('return detailed statistics for all errors found', () => { + expect(Object.keys(errorGroupsDetailedStatistics.currentPeriod).sort()).to.eql(errorIds); }); - after(() => synthtraceEsClient.clean()); - - describe('without data comparison', () => { - let errorGroupsDetailedStatistics: ErrorGroupsDetailedStatistics; - let errorIds: string[] = []; - before(async () => { - errorIds = await getErrorGroupIds({ serviceName, start, end, apmApiClient }); - const response = await callApi({ - body: { - groupIds: JSON.stringify(errorIds), - }, + it('returns correct number of occurrencies', () => { + const numberOfBuckets = 15; + const detailedStatisticsOccurrenciesSum = Object.values( + errorGroupsDetailedStatistics.currentPeriod + ) + .sort() + .map(({ timeseries }) => { + return sumBy(timeseries, 'y'); }); - errorGroupsDetailedStatistics = response.body; - }); - it('return detailed statistics for all errors found', () => { - expect(Object.keys(errorGroupsDetailedStatistics.currentPeriod).sort()).to.eql( - errorIds - ); - }); + expect(detailedStatisticsOccurrenciesSum).to.eql([ + PROD_ID_ERROR_RATE * numberOfBuckets, + PROD_LIST_ERROR_RATE * numberOfBuckets, + ]); + }); + }); - it('returns correct number of occurrencies', () => { - const numberOfBuckets = 15; - const detailedStatisticsOccurrenciesSum = Object.values( - errorGroupsDetailedStatistics.currentPeriod - ) - .sort() - .map(({ timeseries }) => { - return sumBy(timeseries, 'y'); - }); - - expect(detailedStatisticsOccurrenciesSum).to.eql([ - PROD_ID_ERROR_RATE * numberOfBuckets, - PROD_LIST_ERROR_RATE * numberOfBuckets, - ]); + describe('return empty state when invalid group id', () => { + let errorGroupsDetailedStatistics: ErrorGroupsDetailedStatistics; + before(async () => { + const response = await callApi({ + body: { + groupIds: JSON.stringify(['foo']), + }, }); + errorGroupsDetailedStatistics = response.body; }); - describe('return empty state when invalid group id', () => { - let errorGroupsDetailedStatistics: ErrorGroupsDetailedStatistics; - before(async () => { - const response = await callApi({ - body: { - groupIds: JSON.stringify(['foo']), - }, - }); - errorGroupsDetailedStatistics = response.body; - }); - - it('returns empty state', () => { - expect(errorGroupsDetailedStatistics).to.be.eql({ - currentPeriod: {}, - previousPeriod: {}, - }); + it('returns empty state', () => { + expect(errorGroupsDetailedStatistics).to.be.eql({ + currentPeriod: {}, + previousPeriod: {}, }); }); + }); - describe('with comparison', () => { - let errorGroupsDetailedStatistics: ErrorGroupsDetailedStatistics; - let errorIds: string[] = []; - before(async () => { - errorIds = await getErrorGroupIds({ serviceName, start, end, apmApiClient }); - const response = await callApi({ - query: { - start: moment(end).subtract(7, 'minutes').toISOString(), - end: new Date(end).toISOString(), - offset: '7m', - }, - body: { - groupIds: JSON.stringify(errorIds), - }, - }); - errorGroupsDetailedStatistics = response.body; + describe('with comparison', () => { + let errorGroupsDetailedStatistics: ErrorGroupsDetailedStatistics; + let errorIds: string[] = []; + before(async () => { + errorIds = await getErrorGroupIds({ serviceName, start, end, apmApiClient }); + const response = await callApi({ + query: { + start: moment(end).subtract(7, 'minutes').toISOString(), + end: new Date(end).toISOString(), + offset: '7m', + }, + body: { + groupIds: JSON.stringify(errorIds), + }, }); + errorGroupsDetailedStatistics = response.body; + }); - it('returns some data', () => { - expect( - Object.keys(errorGroupsDetailedStatistics.currentPeriod).length - ).to.be.greaterThan(0); - expect( - Object.keys(errorGroupsDetailedStatistics.previousPeriod).length - ).to.be.greaterThan(0); + it('returns some data', () => { + expect(Object.keys(errorGroupsDetailedStatistics.currentPeriod).length).to.be.greaterThan( + 0 + ); + expect( + Object.keys(errorGroupsDetailedStatistics.previousPeriod).length + ).to.be.greaterThan(0); - const hasCurrentPeriodData = Object.values( - errorGroupsDetailedStatistics.currentPeriod - )[0].timeseries.some(({ y }) => isFiniteNumber(y)); + const hasCurrentPeriodData = Object.values( + errorGroupsDetailedStatistics.currentPeriod + )[0].timeseries.some(({ y }) => isFiniteNumber(y)); - const hasPreviousPeriodData = Object.values( - errorGroupsDetailedStatistics.previousPeriod - )[0].timeseries.some(({ y }) => isFiniteNumber(y)); + const hasPreviousPeriodData = Object.values( + errorGroupsDetailedStatistics.previousPeriod + )[0].timeseries.some(({ y }) => isFiniteNumber(y)); - expect(hasCurrentPeriodData).to.equal(true); - expect(hasPreviousPeriodData).to.equal(true); - }); + expect(hasCurrentPeriodData).to.equal(true); + expect(hasPreviousPeriodData).to.equal(true); + }); - it('has same start time for both periods', () => { - expect( - first(Object.values(errorGroupsDetailedStatistics.currentPeriod)[0].timeseries)?.x - ).to.equal( - first(Object.values(errorGroupsDetailedStatistics.previousPeriod)[0].timeseries)?.x - ); - }); + it('has same start time for both periods', () => { + expect( + first(Object.values(errorGroupsDetailedStatistics.currentPeriod)[0].timeseries)?.x + ).to.equal( + first(Object.values(errorGroupsDetailedStatistics.previousPeriod)[0].timeseries)?.x + ); + }); - it('has same end time for both periods', () => { - expect( - last(Object.values(errorGroupsDetailedStatistics.currentPeriod)[0].timeseries)?.x - ).to.equal( - last(Object.values(errorGroupsDetailedStatistics.previousPeriod)[0].timeseries)?.x - ); - }); + it('has same end time for both periods', () => { + expect( + last(Object.values(errorGroupsDetailedStatistics.currentPeriod)[0].timeseries)?.x + ).to.equal( + last(Object.values(errorGroupsDetailedStatistics.previousPeriod)[0].timeseries)?.x + ); + }); - it('returns same number of buckets for both periods', () => { - expect( - Object.values(errorGroupsDetailedStatistics.currentPeriod)[0].timeseries.length - ).to.equal( - Object.values(errorGroupsDetailedStatistics.previousPeriod)[0].timeseries.length - ); - }); + it('returns same number of buckets for both periods', () => { + expect( + Object.values(errorGroupsDetailedStatistics.currentPeriod)[0].timeseries.length + ).to.equal( + Object.values(errorGroupsDetailedStatistics.previousPeriod)[0].timeseries.length + ); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_main_statistics.spec.ts b/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_main_statistics.spec.ts index df86dc2bda16f..32ae3b9bfd5ac 100644 --- a/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_main_statistics.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/error_groups/error_groups_main_statistics.spec.ts @@ -58,51 +58,44 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Error groups main statistics', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded', () => { - const { PROD_LIST_ERROR_RATE, PROD_ID_ERROR_RATE, ERROR_NAME_1, ERROR_NAME_2 } = config; + registry.when('Error groups main statistics', { config: 'basic', archives: [] }, () => { + describe('when data is loaded', () => { + const { PROD_LIST_ERROR_RATE, PROD_ID_ERROR_RATE, ERROR_NAME_1, ERROR_NAME_2 } = config; - before(async () => { - await generateData({ serviceName, start, end, synthtraceEsClient }); - }); + before(async () => { + await generateData({ serviceName, start, end, synthtraceEsClient }); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - describe('returns the correct data', () => { - let errorGroupMainStatistics: ErrorGroupsMainStatistics; - before(async () => { - const response = await callApi(); - errorGroupMainStatistics = response.body; - }); + describe('returns the correct data', () => { + let errorGroupMainStatistics: ErrorGroupsMainStatistics; + before(async () => { + const response = await callApi(); + errorGroupMainStatistics = response.body; + }); - it('returns correct number of occurrences', () => { - expect(errorGroupMainStatistics.errorGroups.length).to.equal(2); - expect(errorGroupMainStatistics.errorGroups.map((error) => error.name).sort()).to.eql([ - ERROR_NAME_1, - ERROR_NAME_2, - ]); - }); + it('returns correct number of occurrences', () => { + expect(errorGroupMainStatistics.errorGroups.length).to.equal(2); + expect(errorGroupMainStatistics.errorGroups.map((error) => error.name).sort()).to.eql([ + ERROR_NAME_1, + ERROR_NAME_2, + ]); + }); - it('returns correct occurences', () => { - const numberOfBuckets = 15; - expect( - errorGroupMainStatistics.errorGroups.map((error) => error.occurrences).sort() - ).to.eql([ - PROD_LIST_ERROR_RATE * numberOfBuckets, - PROD_ID_ERROR_RATE * numberOfBuckets, - ]); - }); + it('returns correct occurences', () => { + const numberOfBuckets = 15; + expect( + errorGroupMainStatistics.errorGroups.map((error) => error.occurrences).sort() + ).to.eql([PROD_LIST_ERROR_RATE * numberOfBuckets, PROD_ID_ERROR_RATE * numberOfBuckets]); + }); - it('has same last seen value as end date', () => { - errorGroupMainStatistics.errorGroups.map((error) => { - expect(error.lastSeen).to.equal(moment(end).startOf('minute').valueOf()); - }); + it('has same last seen value as end date', () => { + errorGroupMainStatistics.errorGroups.map((error) => { + expect(error.lastSeen).to.equal(moment(end).startOf('minute').valueOf()); }); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts b/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts index 0033c5b8f026b..49160f9b5caf2 100644 --- a/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/get_service_node_metadata.spec.ts @@ -54,7 +54,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'Service node metadata when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { before(async () => { const instance = apm.service(serviceName, 'production', 'go').instance(instanceName); diff --git a/x-pack/test/apm_api_integration/tests/services/service_details/service_details.spec.ts b/x-pack/test/apm_api_integration/tests/services/service_details/service_details.spec.ts index c53c9f9f16e86..f54fbf26c7b99 100644 --- a/x-pack/test/apm_api_integration/tests/services/service_details/service_details.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/service_details/service_details.spec.ts @@ -50,79 +50,75 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'Service details when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - let body: ServiceDetails; - let status: number; - - before(async () => { - await generateData({ synthtraceEsClient, start, end }); - const response = await callApi(); - body = response.body; - status = response.status; - }); + registry.when('Service details when data is generated', { config: 'basic', archives: [] }, () => { + let body: ServiceDetails; + let status: number; + + before(async () => { + await generateData({ synthtraceEsClient, start, end }); + const response = await callApi(); + body = response.body; + status = response.status; + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - it('returns correct HTTP status', () => { - expect(status).to.be(200); - }); + it('returns correct HTTP status', () => { + expect(status).to.be(200); + }); - it('returns correct cloud details', () => { - const { cloud } = dataConfig; - const { - provider, - availabilityZone, - region, - machineType, - projectName, - serviceName: cloudServiceName, - } = cloud; - - expect(first(body?.cloud?.availabilityZones)).to.be(availabilityZone); - expect(first(body?.cloud?.machineTypes)).to.be(machineType); - expect(body?.cloud?.provider).to.be(provider); - expect(body?.cloud?.projectName).to.be(projectName); - expect(body?.cloud?.serviceName).to.be(cloudServiceName); - expect(first(body?.cloud?.regions)).to.be(region); - }); + it('returns correct cloud details', () => { + const { cloud } = dataConfig; + const { + provider, + availabilityZone, + region, + machineType, + projectName, + serviceName: cloudServiceName, + } = cloud; + + expect(first(body?.cloud?.availabilityZones)).to.be(availabilityZone); + expect(first(body?.cloud?.machineTypes)).to.be(machineType); + expect(body?.cloud?.provider).to.be(provider); + expect(body?.cloud?.projectName).to.be(projectName); + expect(body?.cloud?.serviceName).to.be(cloudServiceName); + expect(first(body?.cloud?.regions)).to.be(region); + }); - it('returns correct container details', () => { - const { containerOs } = dataConfig; + it('returns correct container details', () => { + const { containerOs } = dataConfig; - expect(body?.container?.isContainerized).to.be(true); - expect(body?.container?.os).to.be(containerOs); - expect(body?.container?.totalNumberInstances).to.be(1); - expect(body?.container?.type).to.be('Kubernetes'); - }); + expect(body?.container?.isContainerized).to.be(true); + expect(body?.container?.os).to.be(containerOs); + expect(body?.container?.totalNumberInstances).to.be(1); + expect(body?.container?.type).to.be('Kubernetes'); + }); - it('returns correct serverless details', () => { - const { cloud, serverless } = dataConfig; - const { serviceName: cloudServiceName } = cloud; - const { faasTriggerType, firstFunctionName, secondFunctionName } = serverless; + it('returns correct serverless details', () => { + const { cloud, serverless } = dataConfig; + const { serviceName: cloudServiceName } = cloud; + const { faasTriggerType, firstFunctionName, secondFunctionName } = serverless; - expect(body?.serverless?.type).to.be(cloudServiceName); - expect(body?.serverless?.functionNames).to.have.length(2); - expect(body?.serverless?.functionNames).to.contain(firstFunctionName); - expect(body?.serverless?.functionNames).to.contain(secondFunctionName); - expect(first(body?.serverless?.faasTriggerTypes)).to.be(faasTriggerType); - }); + expect(body?.serverless?.type).to.be(cloudServiceName); + expect(body?.serverless?.functionNames).to.have.length(2); + expect(body?.serverless?.functionNames).to.contain(firstFunctionName); + expect(body?.serverless?.functionNames).to.contain(secondFunctionName); + expect(first(body?.serverless?.faasTriggerTypes)).to.be(faasTriggerType); + }); - it('returns correct service details', () => { - const { service } = dataConfig; - const { version, runtime, framework, agent } = service; - const { name: runTimeName, version: runTimeVersion } = runtime; - const { name: agentName, version: agentVersion } = agent; - - expect(body?.service?.framework).to.be(framework); - expect(body?.service?.agent.name).to.be(agentName); - expect(body?.service?.agent.version).to.be(agentVersion); - expect(body?.service?.runtime?.name).to.be(runTimeName); - expect(body?.service?.runtime?.version).to.be(runTimeVersion); - expect(first(body?.service?.versions)).to.be(version); - }); - } - ); + it('returns correct service details', () => { + const { service } = dataConfig; + const { version, runtime, framework, agent } = service; + const { name: runTimeName, version: runTimeVersion } = runtime; + const { name: agentName, version: agentVersion } = agent; + + expect(body?.service?.framework).to.be(framework); + expect(body?.service?.agent.name).to.be(agentName); + expect(body?.service?.agent.version).to.be(agentVersion); + expect(body?.service?.runtime?.name).to.be(runTimeName); + expect(body?.service?.runtime?.version).to.be(runTimeVersion); + expect(first(body?.service?.versions)).to.be(version); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/services/service_icons/service_icons.spec.ts b/x-pack/test/apm_api_integration/tests/services/service_icons/service_icons.spec.ts index 11cb59fff0756..756babbadd9f0 100644 --- a/x-pack/test/apm_api_integration/tests/services/service_icons/service_icons.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/service_icons/service_icons.spec.ts @@ -43,35 +43,31 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'Service icons when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - let body: ServiceIconMetadata; - let status: number; + registry.when('Service icons when data is generated', { config: 'basic', archives: [] }, () => { + let body: ServiceIconMetadata; + let status: number; - before(async () => { - await generateData({ synthtraceEsClient, start, end }); - const response = await callApi(); - body = response.body; - status = response.status; - }); + before(async () => { + await generateData({ synthtraceEsClient, start, end }); + const response = await callApi(); + body = response.body; + status = response.status; + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - it('returns correct HTTP status', () => { - expect(status).to.be(200); - }); + it('returns correct HTTP status', () => { + expect(status).to.be(200); + }); - it('returns correct metadata', () => { - const { agentName, cloud } = dataConfig; - const { provider, serviceName: cloudServiceName } = cloud; + it('returns correct metadata', () => { + const { agentName, cloud } = dataConfig; + const { provider, serviceName: cloudServiceName } = cloud; - expect(body.agentName).to.be(agentName); - expect(body.cloudProvider).to.be(provider); - expect(body.containerType).to.be('Kubernetes'); - expect(body.serverlessType).to.be(cloudServiceName); - }); - } - ); + expect(body.agentName).to.be(agentName); + expect(body.cloudProvider).to.be(provider); + expect(body.containerType).to.be('Kubernetes'); + expect(body.serverlessType).to.be(cloudServiceName); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/services/sorted_and_filtered_services.spec.ts b/x-pack/test/apm_api_integration/tests/services/sorted_and_filtered_services.spec.ts index 92a6997244b20..ca2cb0c3d20a7 100644 --- a/x-pack/test/apm_api_integration/tests/services/sorted_and_filtered_services.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/sorted_and_filtered_services.spec.ts @@ -51,102 +51,98 @@ export default function ApiTest({ getService }: FtrProviderContext) { type ServiceListItem = ValuesType>>; // FLAKY: https://github.com/elastic/kibana/issues/127939 - registry.when.skip( - 'Sorted and filtered services', - { config: 'trial', archives: ['apm_mappings_only_8.0.0'] }, - () => { - before(async () => { - const serviceA = apm.service(SERVICE_NAME_PREFIX + 'a', 'production', 'java').instance('a'); - - const serviceB = apm.service(SERVICE_NAME_PREFIX + 'b', 'development', 'go').instance('b'); - - const serviceC = apm.service(SERVICE_NAME_PREFIX + 'c', 'development', 'go').instance('c'); - - const spikeStart = new Date('2021-01-07T12:00:00.000Z').getTime(); - const spikeEnd = new Date('2021-01-07T14:00:00.000Z').getTime(); - - const eventsWithinTimerange = timerange(new Date(start).getTime(), new Date(end).getTime()) - .interval('15m') - .rate(1) - .generator((timestamp) => { - const isInSpike = spikeStart <= timestamp && spikeEnd >= timestamp; - return [ - serviceA - .transaction('GET /api') - .duration(isInSpike ? 1000 : 1100) - .timestamp(timestamp), - serviceB - .transaction('GET /api') - .duration(isInSpike ? 1000 : 4000) - .timestamp(timestamp), - ]; - }); - - const eventsOutsideOfTimerange = timerange( - new Date('2021-01-01T00:00:00.000Z').getTime(), - new Date(start).getTime() - 1 - ) - .interval('15m') - .rate(1) - .generator((timestamp) => { - return serviceC.transaction('GET /api', 'custom').duration(1000).timestamp(timestamp); - }); - - await synthtraceClient.index(eventsWithinTimerange.merge(eventsOutsideOfTimerange)); - - await Promise.all([ - createAndRunApmMlJob({ environment: 'production', ml }), - createAndRunApmMlJob({ environment: 'development', ml }), - ]); - }); + registry.when.skip('Sorted and filtered services', { config: 'trial', archives: [] }, () => { + before(async () => { + const serviceA = apm.service(SERVICE_NAME_PREFIX + 'a', 'production', 'java').instance('a'); + + const serviceB = apm.service(SERVICE_NAME_PREFIX + 'b', 'development', 'go').instance('b'); + + const serviceC = apm.service(SERVICE_NAME_PREFIX + 'c', 'development', 'go').instance('c'); + + const spikeStart = new Date('2021-01-07T12:00:00.000Z').getTime(); + const spikeEnd = new Date('2021-01-07T14:00:00.000Z').getTime(); + + const eventsWithinTimerange = timerange(new Date(start).getTime(), new Date(end).getTime()) + .interval('15m') + .rate(1) + .generator((timestamp) => { + const isInSpike = spikeStart <= timestamp && spikeEnd >= timestamp; + return [ + serviceA + .transaction('GET /api') + .duration(isInSpike ? 1000 : 1100) + .timestamp(timestamp), + serviceB + .transaction('GET /api') + .duration(isInSpike ? 1000 : 4000) + .timestamp(timestamp), + ]; + }); - after(() => { - return Promise.all([synthtraceClient.clean(), ml.cleanMlIndices()]); - }); + const eventsOutsideOfTimerange = timerange( + new Date('2021-01-01T00:00:00.000Z').getTime(), + new Date(start).getTime() - 1 + ) + .interval('15m') + .rate(1) + .generator((timestamp) => { + return serviceC.transaction('GET /api', 'custom').duration(1000).timestamp(timestamp); + }); - describe('with no kuery or environment are set', () => { - let items: ServiceListItem[]; + await synthtraceClient.index(eventsWithinTimerange.merge(eventsOutsideOfTimerange)); - before(async () => { - items = await getSortedAndFilteredServices(); - }); + await Promise.all([ + createAndRunApmMlJob({ environment: 'production', ml }), + createAndRunApmMlJob({ environment: 'development', ml }), + ]); + }); - it('returns services based on the terms enum API and ML data', () => { - const serviceNames = items.map((item) => item.serviceName); + after(() => { + return Promise.all([synthtraceClient.clean(), ml.cleanMlIndices()]); + }); - expect(serviceNames.sort()).to.eql(['a', 'b', 'c']); - }); + describe('with no kuery or environment are set', () => { + let items: ServiceListItem[]; + + before(async () => { + items = await getSortedAndFilteredServices(); }); - describe('with kuery set', () => { - let items: ServiceListItem[]; + it('returns services based on the terms enum API and ML data', () => { + const serviceNames = items.map((item) => item.serviceName); - before(async () => { - items = await getSortedAndFilteredServices({ - kuery: 'service.name:*', - }); - }); + expect(serviceNames.sort()).to.eql(['a', 'b', 'c']); + }); + }); + + describe('with kuery set', () => { + let items: ServiceListItem[]; - it('does not return any services', () => { - expect(items.length).to.be(0); + before(async () => { + items = await getSortedAndFilteredServices({ + kuery: 'service.name:*', }); }); - describe('with environment set to production', () => { - let items: ServiceListItem[]; + it('does not return any services', () => { + expect(items.length).to.be(0); + }); + }); - before(async () => { - items = await getSortedAndFilteredServices({ - environment: 'production', - }); + describe('with environment set to production', () => { + let items: ServiceListItem[]; + + before(async () => { + items = await getSortedAndFilteredServices({ + environment: 'production', }); + }); - it('returns services for production only', () => { - const serviceNames = items.map((item) => item.serviceName); + it('returns services for production only', () => { + const serviceNames = items.map((item) => item.serviceName); - expect(serviceNames.sort()).to.eql(['a']); - }); + expect(serviceNames.sort()).to.eql(['a']); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts b/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts index 12c4c809193e2..c9c95b2e99bbc 100644 --- a/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts @@ -63,219 +63,213 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when( - 'Throughput when data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('Throughput chart api', () => { - const GO_PROD_RATE = 50; - const GO_DEV_RATE = 5; - const JAVA_PROD_RATE = 45; + registry.when('Throughput when data is loaded', { config: 'basic', archives: [] }, () => { + describe('Throughput chart api', () => { + const GO_PROD_RATE = 50; + const GO_DEV_RATE = 5; + const JAVA_PROD_RATE = 45; + + before(async () => { + const serviceGoProdInstance = apm + .service(serviceName, 'production', 'go') + .instance('instance-a'); + const serviceGoDevInstance = apm + .service(serviceName, 'development', 'go') + .instance('instance-b'); + + const serviceJavaInstance = apm + .service('synth-java', 'development', 'java') + .instance('instance-c'); + + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(GO_PROD_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction('GET /api/product/list') + .duration(1000) + .timestamp(timestamp) + ), + timerange(start, end) + .interval('1m') + .rate(GO_DEV_RATE) + .generator((timestamp) => + serviceGoDevInstance + .transaction('GET /api/product/:id') + .duration(1000) + .timestamp(timestamp) + ), + timerange(start, end) + .interval('1m') + .rate(JAVA_PROD_RATE) + .generator((timestamp) => + serviceJavaInstance + .transaction('POST /api/product/buy') + .duration(1000) + .timestamp(timestamp) + ), + ]); + }); + + after(() => synthtraceEsClient.clean()); + + describe('compare transactions and metrics based throughput', () => { + let throughputMetrics: ThroughputReturn; + let throughputTransactions: ThroughputReturn; before(async () => { - const serviceGoProdInstance = apm - .service(serviceName, 'production', 'go') - .instance('instance-a'); - const serviceGoDevInstance = apm - .service(serviceName, 'development', 'go') - .instance('instance-b'); - - const serviceJavaInstance = apm - .service('synth-java', 'development', 'java') - .instance('instance-c'); - - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(GO_PROD_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction('GET /api/product/list') - .duration(1000) - .timestamp(timestamp) - ), - timerange(start, end) - .interval('1m') - .rate(GO_DEV_RATE) - .generator((timestamp) => - serviceGoDevInstance - .transaction('GET /api/product/:id') - .duration(1000) - .timestamp(timestamp) - ), - timerange(start, end) - .interval('1m') - .rate(JAVA_PROD_RATE) - .generator((timestamp) => - serviceJavaInstance - .transaction('POST /api/product/buy') - .duration(1000) - .timestamp(timestamp) - ), + const [throughputMetricsResponse, throughputTransactionsResponse] = await Promise.all([ + callApi({ query: { kuery: 'processor.event : "metric"' } }), + callApi({ query: { kuery: 'processor.event : "transaction"' } }), ]); + throughputMetrics = throughputMetricsResponse.body; + throughputTransactions = throughputTransactionsResponse.body; }); - after(() => synthtraceEsClient.clean()); - - describe('compare transactions and metrics based throughput', () => { - let throughputMetrics: ThroughputReturn; - let throughputTransactions: ThroughputReturn; + it('returns some transactions data', () => { + expect(throughputTransactions.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputTransactions.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); - before(async () => { - const [throughputMetricsResponse, throughputTransactionsResponse] = await Promise.all([ - callApi({ query: { kuery: 'processor.event : "metric"' } }), - callApi({ query: { kuery: 'processor.event : "transaction"' } }), - ]); - throughputMetrics = throughputMetricsResponse.body; - throughputTransactions = throughputTransactionsResponse.body; - }); + it('returns some metrics data', () => { + expect(throughputMetrics.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputMetrics.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); - it('returns some transactions data', () => { - expect(throughputTransactions.currentPeriod.length).to.be.greaterThan(0); - const hasData = throughputTransactions.currentPeriod.some(({ y }) => isFiniteNumber(y)); - expect(hasData).to.equal(true); - }); + it('has same mean value for metrics and transactions data', () => { + const transactionsMean = meanBy(throughputTransactions.currentPeriod, 'y'); + const metricsMean = meanBy(throughputMetrics.currentPeriod, 'y'); + [transactionsMean, metricsMean].forEach((value) => + expect(roundNumber(value)).to.be.equal(roundNumber(GO_PROD_RATE + GO_DEV_RATE)) + ); + }); - it('returns some metrics data', () => { - expect(throughputMetrics.currentPeriod.length).to.be.greaterThan(0); - const hasData = throughputMetrics.currentPeriod.some(({ y }) => isFiniteNumber(y)); - expect(hasData).to.equal(true); - }); + it('has a bucket size of 30 seconds for transactions data', () => { + const firstTimerange = throughputTransactions.currentPeriod[0].x; + const secondTimerange = throughputTransactions.currentPeriod[1].x; + const timeIntervalAsSeconds = (secondTimerange - firstTimerange) / 1000; + expect(timeIntervalAsSeconds).to.equal(30); + }); - it('has same mean value for metrics and transactions data', () => { - const transactionsMean = meanBy(throughputTransactions.currentPeriod, 'y'); - const metricsMean = meanBy(throughputMetrics.currentPeriod, 'y'); - [transactionsMean, metricsMean].forEach((value) => - expect(roundNumber(value)).to.be.equal(roundNumber(GO_PROD_RATE + GO_DEV_RATE)) - ); - }); + it('has a bucket size of 1 minute for metrics data', () => { + const firstTimerange = throughputMetrics.currentPeriod[0].x; + const secondTimerange = throughputMetrics.currentPeriod[1].x; + const timeIntervalAsMinutes = (secondTimerange - firstTimerange) / 1000 / 60; + expect(timeIntervalAsMinutes).to.equal(1); + }); + }); - it('has a bucket size of 30 seconds for transactions data', () => { - const firstTimerange = throughputTransactions.currentPeriod[0].x; - const secondTimerange = throughputTransactions.currentPeriod[1].x; - const timeIntervalAsSeconds = (secondTimerange - firstTimerange) / 1000; - expect(timeIntervalAsSeconds).to.equal(30); - }); + describe('production environment', () => { + let throughput: ThroughputReturn; - it('has a bucket size of 1 minute for metrics data', () => { - const firstTimerange = throughputMetrics.currentPeriod[0].x; - const secondTimerange = throughputMetrics.currentPeriod[1].x; - const timeIntervalAsMinutes = (secondTimerange - firstTimerange) / 1000 / 60; - expect(timeIntervalAsMinutes).to.equal(1); - }); + before(async () => { + const throughputResponse = await callApi({ query: { environment: 'production' } }); + throughput = throughputResponse.body; }); - describe('production environment', () => { - let throughput: ThroughputReturn; + it('returns some data', () => { + expect(throughput.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughput.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); - before(async () => { - const throughputResponse = await callApi({ query: { environment: 'production' } }); - throughput = throughputResponse.body; - }); + it('returns correct average throughput', () => { + const throughputMean = meanBy(throughput.currentPeriod, 'y'); + expect(roundNumber(throughputMean)).to.be.equal(roundNumber(GO_PROD_RATE)); + }); + }); - it('returns some data', () => { - expect(throughput.currentPeriod.length).to.be.greaterThan(0); - const hasData = throughput.currentPeriod.some(({ y }) => isFiniteNumber(y)); - expect(hasData).to.equal(true); - }); + describe('when synth-java is selected', () => { + let throughput: ThroughputReturn; - it('returns correct average throughput', () => { - const throughputMean = meanBy(throughput.currentPeriod, 'y'); - expect(roundNumber(throughputMean)).to.be.equal(roundNumber(GO_PROD_RATE)); - }); + before(async () => { + const throughputResponse = await callApi({ path: { serviceName: 'synth-java' } }); + throughput = throughputResponse.body; }); - describe('when synth-java is selected', () => { - let throughput: ThroughputReturn; + it('returns some data', () => { + expect(throughput.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughput.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); - before(async () => { - const throughputResponse = await callApi({ path: { serviceName: 'synth-java' } }); - throughput = throughputResponse.body; - }); + it('returns throughput related to java agent', () => { + const throughputMean = meanBy(throughput.currentPeriod, 'y'); + expect(roundNumber(throughputMean)).to.be.equal(roundNumber(JAVA_PROD_RATE)); + }); + }); - it('returns some data', () => { - expect(throughput.currentPeriod.length).to.be.greaterThan(0); - const hasData = throughput.currentPeriod.some(({ y }) => isFiniteNumber(y)); - expect(hasData).to.equal(true); - }); + describe('time comparisons', () => { + let throughputResponse: ThroughputReturn; - it('returns throughput related to java agent', () => { - const throughputMean = meanBy(throughput.currentPeriod, 'y'); - expect(roundNumber(throughputMean)).to.be.equal(roundNumber(JAVA_PROD_RATE)); + before(async () => { + const response = await callApi({ + query: { + start: moment(end).subtract(7, 'minutes').toISOString(), + end: new Date(end).toISOString(), + offset: '7m', + }, }); + throughputResponse = response.body; }); - describe('time comparisons', () => { - let throughputResponse: ThroughputReturn; - - before(async () => { - const response = await callApi({ - query: { - start: moment(end).subtract(7, 'minutes').toISOString(), - end: new Date(end).toISOString(), - offset: '7m', - }, - }); - throughputResponse = response.body; - }); + it('returns some data', () => { + expect(throughputResponse.currentPeriod.length).to.be.greaterThan(0); + expect(throughputResponse.previousPeriod.length).to.be.greaterThan(0); - it('returns some data', () => { - expect(throughputResponse.currentPeriod.length).to.be.greaterThan(0); - expect(throughputResponse.previousPeriod.length).to.be.greaterThan(0); + const hasCurrentPeriodData = throughputResponse.currentPeriod.some(({ y }) => + isFiniteNumber(y) + ); + const hasPreviousPeriodData = throughputResponse.previousPeriod.some(({ y }) => + isFiniteNumber(y) + ); - const hasCurrentPeriodData = throughputResponse.currentPeriod.some(({ y }) => - isFiniteNumber(y) - ); - const hasPreviousPeriodData = throughputResponse.previousPeriod.some(({ y }) => - isFiniteNumber(y) - ); - - expect(hasCurrentPeriodData).to.equal(true); - expect(hasPreviousPeriodData).to.equal(true); - }); + expect(hasCurrentPeriodData).to.equal(true); + expect(hasPreviousPeriodData).to.equal(true); + }); - it('has same start time for both periods', () => { - expect(first(throughputResponse.currentPeriod)?.x).to.equal( - first(throughputResponse.previousPeriod)?.x - ); - }); + it('has same start time for both periods', () => { + expect(first(throughputResponse.currentPeriod)?.x).to.equal( + first(throughputResponse.previousPeriod)?.x + ); + }); - it('has same end time for both periods', () => { - expect(last(throughputResponse.currentPeriod)?.x).to.equal( - last(throughputResponse.previousPeriod)?.x - ); - }); + it('has same end time for both periods', () => { + expect(last(throughputResponse.currentPeriod)?.x).to.equal( + last(throughputResponse.previousPeriod)?.x + ); + }); - it('returns same number of buckets for both periods', () => { - expect(throughputResponse.currentPeriod.length).to.be( - throughputResponse.previousPeriod.length - ); - }); + it('returns same number of buckets for both periods', () => { + expect(throughputResponse.currentPeriod.length).to.be( + throughputResponse.previousPeriod.length + ); + }); - it('has same mean value for both periods', () => { - const currentPeriodMean = meanBy( - throughputResponse.currentPeriod.filter( - (item) => isFiniteNumber(item.y) && item.y > 0 - ), - 'y' - ); - const previousPeriodMean = meanBy( - throughputResponse.previousPeriod.filter( - (item) => isFiniteNumber(item.y) && item.y > 0 - ), - 'y' - ); - const currentPeriod = throughputResponse.currentPeriod; - const bucketSize = currentPeriod[1].x - currentPeriod[0].x; - const durationAsMinutes = bucketSize / 1000 / 60; - [currentPeriodMean, previousPeriodMean].every((value) => - expect(roundNumber(value)).to.be.equal( - roundNumber((GO_PROD_RATE + GO_DEV_RATE) / durationAsMinutes) - ) - ); - }); + it('has same mean value for both periods', () => { + const currentPeriodMean = meanBy( + throughputResponse.currentPeriod.filter((item) => isFiniteNumber(item.y) && item.y > 0), + 'y' + ); + const previousPeriodMean = meanBy( + throughputResponse.previousPeriod.filter( + (item) => isFiniteNumber(item.y) && item.y > 0 + ), + 'y' + ); + const currentPeriod = throughputResponse.currentPeriod; + const bucketSize = currentPeriod[1].x - currentPeriod[0].x; + const durationAsMinutes = bucketSize / 1000 / 60; + [currentPeriodMean, previousPeriodMean].every((value) => + expect(roundNumber(value)).to.be.equal( + roundNumber((GO_PROD_RATE + GO_DEV_RATE) / durationAsMinutes) + ) + ); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/services/top_services.spec.ts b/x-pack/test/apm_api_integration/tests/services/top_services.spec.ts index 960c7e55f4153..898f12ceaeffb 100644 --- a/x-pack/test/apm_api_integration/tests/services/top_services.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/top_services.spec.ts @@ -33,7 +33,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'APM Services Overview with a basic license when data is not generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { it('handles the empty state', async () => { const response = await apmApiClient.readUser({ @@ -57,7 +57,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { registry.when( 'APM Services Overview with a basic license when data is generated', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, + { config: 'basic', archives: [] }, () => { let response: { status: number; diff --git a/x-pack/test/apm_api_integration/tests/settings/agent_configuration/agent_configuration.spec.ts b/x-pack/test/apm_api_integration/tests/settings/agent_configuration/agent_configuration.spec.ts index e4960791eee5a..696c57779fb30 100644 --- a/x-pack/test/apm_api_integration/tests/settings/agent_configuration/agent_configuration.spec.ts +++ b/x-pack/test/apm_api_integration/tests/settings/agent_configuration/agent_configuration.spec.ts @@ -386,73 +386,69 @@ export default function agentConfigurationTests({ getService }: FtrProviderConte } ); - registry.when( - 'Agent configurations through fleet', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - const name = 'myservice'; - const environment = 'development'; - const testConfig = { - service: { name, environment }, - settings: { transaction_sample_rate: '0.9' }, - }; - - let agentConfiguration: - | APIReturnType<'GET /api/apm/settings/agent-configuration/view'> - | undefined; - - before(async () => { - log.debug('creating agent configuration'); - await createConfiguration(testConfig); - const { body } = await findExactConfiguration(name, environment); - agentConfiguration = body; - }); + registry.when('Agent configurations through fleet', { config: 'basic', archives: [] }, () => { + const name = 'myservice'; + const environment = 'development'; + const testConfig = { + service: { name, environment }, + settings: { transaction_sample_rate: '0.9' }, + }; + + let agentConfiguration: + | APIReturnType<'GET /api/apm/settings/agent-configuration/view'> + | undefined; + + before(async () => { + log.debug('creating agent configuration'); + await createConfiguration(testConfig); + const { body } = await findExactConfiguration(name, environment); + agentConfiguration = body; + }); - after(async () => { - await deleteConfiguration(testConfig); - }); + after(async () => { + await deleteConfiguration(testConfig); + }); - it(`should have 'applied_by_agent=false' when there are no agent config metrics for this etag`, async () => { - expect(agentConfiguration?.applied_by_agent).to.be(false); - }); + it(`should have 'applied_by_agent=false' when there are no agent config metrics for this etag`, async () => { + expect(agentConfiguration?.applied_by_agent).to.be(false); + }); - describe('when there are agent config metrics for this etag', () => { - before(async () => { - const start = new Date().getTime(); - const end = moment(start).add(15, 'minutes').valueOf(); - - await addAgentConfigMetrics({ - synthtraceEsClient, - start, - end, - etag: agentConfiguration?.etag, - }); + describe('when there are agent config metrics for this etag', () => { + before(async () => { + const start = new Date().getTime(); + const end = moment(start).add(15, 'minutes').valueOf(); + + await addAgentConfigMetrics({ + synthtraceEsClient, + start, + end, + etag: agentConfiguration?.etag, }); + }); - after(() => synthtraceEsClient.clean()); + after(() => synthtraceEsClient.clean()); - it(`should have 'applied_by_agent=true' when getting a config from all configurations`, async () => { - const { - body: { configurations }, - } = await getAllConfigurations(); + it(`should have 'applied_by_agent=true' when getting a config from all configurations`, async () => { + const { + body: { configurations }, + } = await getAllConfigurations(); - const updatedConfig = configurations.find( - (x) => x.service.name === name && x.service.environment === environment - ); + const updatedConfig = configurations.find( + (x) => x.service.name === name && x.service.environment === environment + ); - expect(updatedConfig?.applied_by_agent).to.be(true); - }); + expect(updatedConfig?.applied_by_agent).to.be(true); + }); - it(`should have 'applied_by_agent=true' when getting a single config`, async () => { - const { - body: { applied_by_agent: appliedByAgent }, - } = await findExactConfiguration(name, environment); + it(`should have 'applied_by_agent=true' when getting a single config`, async () => { + const { + body: { applied_by_agent: appliedByAgent }, + } = await findExactConfiguration(name, environment); - expect(appliedByAgent).to.be(true); - }); + expect(appliedByAgent).to.be(true); }); - } - ); + }); + }); registry.when( 'agent configuration when data is loaded', diff --git a/x-pack/test/apm_api_integration/tests/span_links/span_links.spec.ts b/x-pack/test/apm_api_integration/tests/span_links/span_links.spec.ts index 3c9e669db62d4..09ca2f454f1e6 100644 --- a/x-pack/test/apm_api_integration/tests/span_links/span_links.spec.ts +++ b/x-pack/test/apm_api_integration/tests/span_links/span_links.spec.ts @@ -18,479 +18,467 @@ export default function ApiTest({ getService }: FtrProviderContext) { const start = new Date('2022-01-01T00:00:00.000Z').getTime(); const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; - registry.when( - 'contains linked children', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - let ids: ReturnType['ids']; - - before(async () => { - const spanLinksData = generateSpanLinksData(); - - ids = spanLinksData.ids; - - await synthtraceEsClient.index( - new EntityArrayIterable(spanLinksData.apmFields.producerInternalOnly).merge( - new EntityArrayIterable(spanLinksData.apmFields.producerExternalOnly), - new EntityArrayIterable(spanLinksData.apmFields.producerConsumer), - new EntityArrayIterable(spanLinksData.apmFields.producerMultiple) - ) - ); - }); - - after(() => synthtraceEsClient.clean()); - - describe('Span links count on traces', () => { - async function fetchTraces({ traceId }: { traceId: string }) { - return await apmApiClient.readUser({ - endpoint: `GET /internal/apm/traces/{traceId}`, - params: { - path: { traceId }, - query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - }, + registry.when('contains linked children', { config: 'basic', archives: [] }, () => { + let ids: ReturnType['ids']; + + before(async () => { + const spanLinksData = generateSpanLinksData(); + + ids = spanLinksData.ids; + + await synthtraceEsClient.index( + new EntityArrayIterable(spanLinksData.apmFields.producerInternalOnly).merge( + new EntityArrayIterable(spanLinksData.apmFields.producerExternalOnly), + new EntityArrayIterable(spanLinksData.apmFields.producerConsumer), + new EntityArrayIterable(spanLinksData.apmFields.producerMultiple) + ) + ); + }); + + after(() => synthtraceEsClient.clean()); + + describe('Span links count on traces', () => { + async function fetchTraces({ traceId }: { traceId: string }) { + return await apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces/{traceId}`, + params: { + path: { traceId }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), }, - }); - } + }, + }); + } - describe('producer-internal-only trace', () => { - let traces: Awaited>['body']; - before(async () => { - const tracesResponse = await fetchTraces({ traceId: ids.producerInternalOnly.traceId }); - traces = tracesResponse.body; - }); + describe('producer-internal-only trace', () => { + let traces: Awaited>['body']; + before(async () => { + const tracesResponse = await fetchTraces({ traceId: ids.producerInternalOnly.traceId }); + traces = tracesResponse.body; + }); - it('contains two children link on Span A', () => { - expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(1); - expect( - traces.linkedChildrenOfSpanCountBySpanId[ids.producerInternalOnly.spanAId] - ).to.equal(2); - }); + it('contains two children link on Span A', () => { + expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(1); + expect( + traces.linkedChildrenOfSpanCountBySpanId[ids.producerInternalOnly.spanAId] + ).to.equal(2); }); + }); - describe('producer-external-only trace', () => { - let traces: Awaited>['body']; - before(async () => { - const tracesResponse = await fetchTraces({ traceId: ids.producerExternalOnly.traceId }); - traces = tracesResponse.body; - }); + describe('producer-external-only trace', () => { + let traces: Awaited>['body']; + before(async () => { + const tracesResponse = await fetchTraces({ traceId: ids.producerExternalOnly.traceId }); + traces = tracesResponse.body; + }); - it('contains two children link on Span B', () => { - expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(2); - expect( - traces.linkedChildrenOfSpanCountBySpanId[ids.producerExternalOnly.spanBId] - ).to.equal(1); - expect( - traces.linkedChildrenOfSpanCountBySpanId[ids.producerExternalOnly.transactionBId] - ).to.equal(1); - }); + it('contains two children link on Span B', () => { + expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(2); + expect( + traces.linkedChildrenOfSpanCountBySpanId[ids.producerExternalOnly.spanBId] + ).to.equal(1); + expect( + traces.linkedChildrenOfSpanCountBySpanId[ids.producerExternalOnly.transactionBId] + ).to.equal(1); }); + }); - describe('producer-consumer trace', () => { - let traces: Awaited>['body']; - before(async () => { - const tracesResponse = await fetchTraces({ traceId: ids.producerConsumer.traceId }); - traces = tracesResponse.body; - }); + describe('producer-consumer trace', () => { + let traces: Awaited>['body']; + before(async () => { + const tracesResponse = await fetchTraces({ traceId: ids.producerConsumer.traceId }); + traces = tracesResponse.body; + }); - it('contains one children link on transaction C and two on span C', () => { - expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(2); - expect( - traces.linkedChildrenOfSpanCountBySpanId[ids.producerConsumer.transactionCId] - ).to.equal(1); - expect(traces.linkedChildrenOfSpanCountBySpanId[ids.producerConsumer.spanCId]).to.equal( - 1 - ); - }); + it('contains one children link on transaction C and two on span C', () => { + expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(2); + expect( + traces.linkedChildrenOfSpanCountBySpanId[ids.producerConsumer.transactionCId] + ).to.equal(1); + expect(traces.linkedChildrenOfSpanCountBySpanId[ids.producerConsumer.spanCId]).to.equal( + 1 + ); }); + }); - describe('consumer-multiple trace', () => { - let traces: Awaited>['body']; - before(async () => { - const tracesResponse = await fetchTraces({ traceId: ids.producerMultiple.traceId }); - traces = tracesResponse.body; - }); + describe('consumer-multiple trace', () => { + let traces: Awaited>['body']; + before(async () => { + const tracesResponse = await fetchTraces({ traceId: ids.producerMultiple.traceId }); + traces = tracesResponse.body; + }); - it('contains no children', () => { - expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(0); - expect( - traces.linkedChildrenOfSpanCountBySpanId[ids.producerMultiple.transactionDId] - ).to.equal(undefined); - expect(traces.linkedChildrenOfSpanCountBySpanId[ids.producerMultiple.spanEId]).to.equal( - undefined - ); - }); + it('contains no children', () => { + expect(Object.values(traces.linkedChildrenOfSpanCountBySpanId).length).to.equal(0); + expect( + traces.linkedChildrenOfSpanCountBySpanId[ids.producerMultiple.transactionDId] + ).to.equal(undefined); + expect(traces.linkedChildrenOfSpanCountBySpanId[ids.producerMultiple.spanEId]).to.equal( + undefined + ); }); }); - - describe('Span links details', () => { - async function fetchChildrenAndParentsDetails({ - kuery, - traceId, - spanId, - processorEvent, - }: { - kuery: string; - traceId: string; - spanId: string; - processorEvent: ProcessorEvent; - }) { - const [childrenLinksResponse, parentsLinksResponse] = await Promise.all([ - await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/traces/{traceId}/span_links/{spanId}/children', - params: { - path: { traceId, spanId }, - query: { - kuery, - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - }, + }); + + describe('Span links details', () => { + async function fetchChildrenAndParentsDetails({ + kuery, + traceId, + spanId, + processorEvent, + }: { + kuery: string; + traceId: string; + spanId: string; + processorEvent: ProcessorEvent; + }) { + const [childrenLinksResponse, parentsLinksResponse] = await Promise.all([ + await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/traces/{traceId}/span_links/{spanId}/children', + params: { + path: { traceId, spanId }, + query: { + kuery, + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), }, - }), - apmApiClient.readUser({ - endpoint: 'GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents', - params: { - path: { traceId, spanId }, - query: { - kuery, - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - processorEvent, - }, + }, + }), + apmApiClient.readUser({ + endpoint: 'GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents', + params: { + path: { traceId, spanId }, + query: { + kuery, + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + processorEvent, }, + }, + }), + ]); + + return { + childrenLinks: childrenLinksResponse.body, + parentsLinks: parentsLinksResponse.body, + }; + } + + describe('producer-internal-only span links details', () => { + let transactionALinksDetails: Awaited>; + let spanALinksDetails: Awaited>; + before(async () => { + const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all([ + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerInternalOnly.traceId, + spanId: ids.producerInternalOnly.transactionAId, + processorEvent: ProcessorEvent.transaction, + }), + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerInternalOnly.traceId, + spanId: ids.producerInternalOnly.spanAId, + processorEvent: ProcessorEvent.span, }), ]); + transactionALinksDetails = transactionALinksDetailsResponse; + spanALinksDetails = spanALinksDetailsResponse; + }); - return { - childrenLinks: childrenLinksResponse.body, - parentsLinks: parentsLinksResponse.body, - }; - } - - describe('producer-internal-only span links details', () => { - let transactionALinksDetails: Awaited>; - let spanALinksDetails: Awaited>; - before(async () => { - const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all( - [ - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerInternalOnly.traceId, - spanId: ids.producerInternalOnly.transactionAId, - processorEvent: ProcessorEvent.transaction, - }), - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerInternalOnly.traceId, - spanId: ids.producerInternalOnly.spanAId, - processorEvent: ProcessorEvent.span, - }), - ] - ); - transactionALinksDetails = transactionALinksDetailsResponse; - spanALinksDetails = spanALinksDetailsResponse; - }); + it('returns no links for transaction A', () => { + expect(transactionALinksDetails.childrenLinks.spanLinksDetails).to.eql([]); + expect(transactionALinksDetails.parentsLinks.spanLinksDetails).to.eql([]); + }); - it('returns no links for transaction A', () => { - expect(transactionALinksDetails.childrenLinks.spanLinksDetails).to.eql([]); - expect(transactionALinksDetails.parentsLinks.spanLinksDetails).to.eql([]); - }); + it('returns no parents on Span A', () => { + expect(spanALinksDetails.parentsLinks.spanLinksDetails).to.eql([]); + }); - it('returns no parents on Span A', () => { - expect(spanALinksDetails.parentsLinks.spanLinksDetails).to.eql([]); + it('returns two children on Span A', () => { + expect(spanALinksDetails.childrenLinks.spanLinksDetails.length).to.eql(2); + const serviceCDetails = spanALinksDetails.childrenLinks.spanLinksDetails.find( + (childDetails) => { + return ( + childDetails.traceId === ids.producerConsumer.traceId && + childDetails.spanId === ids.producerConsumer.transactionCId + ); + } + ); + expect(serviceCDetails?.details).to.eql({ + serviceName: 'producer-consumer', + agentName: 'ruby', + transactionId: ids.producerConsumer.transactionCId, + spanName: 'Transaction C', + duration: 1000000, }); - it('returns two children on Span A', () => { - expect(spanALinksDetails.childrenLinks.spanLinksDetails.length).to.eql(2); - const serviceCDetails = spanALinksDetails.childrenLinks.spanLinksDetails.find( - (childDetails) => { - return ( - childDetails.traceId === ids.producerConsumer.traceId && - childDetails.spanId === ids.producerConsumer.transactionCId - ); - } - ); - expect(serviceCDetails?.details).to.eql({ - serviceName: 'producer-consumer', - agentName: 'ruby', - transactionId: ids.producerConsumer.transactionCId, - spanName: 'Transaction C', - duration: 1000000, - }); - - const serviceDDetails = spanALinksDetails.childrenLinks.spanLinksDetails.find( - (childDetails) => { - return ( - childDetails.traceId === ids.producerMultiple.traceId && - childDetails.spanId === ids.producerMultiple.transactionDId - ); - } - ); - expect(serviceDDetails?.details).to.eql({ - serviceName: 'consumer-multiple', - agentName: 'nodejs', - transactionId: ids.producerMultiple.transactionDId, - spanName: 'Transaction D', - duration: 1000000, - }); + const serviceDDetails = spanALinksDetails.childrenLinks.spanLinksDetails.find( + (childDetails) => { + return ( + childDetails.traceId === ids.producerMultiple.traceId && + childDetails.spanId === ids.producerMultiple.transactionDId + ); + } + ); + expect(serviceDDetails?.details).to.eql({ + serviceName: 'consumer-multiple', + agentName: 'nodejs', + transactionId: ids.producerMultiple.transactionDId, + spanName: 'Transaction D', + duration: 1000000, }); }); + }); - describe('producer-external-only span links details', () => { - let transactionBLinksDetails: Awaited>; - let spanBLinksDetails: Awaited>; - before(async () => { - const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all( - [ - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerExternalOnly.traceId, - spanId: ids.producerExternalOnly.transactionBId, - processorEvent: ProcessorEvent.transaction, - }), - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerExternalOnly.traceId, - spanId: ids.producerExternalOnly.spanBId, - processorEvent: ProcessorEvent.span, - }), - ] - ); - transactionBLinksDetails = transactionALinksDetailsResponse; - spanBLinksDetails = spanALinksDetailsResponse; - }); + describe('producer-external-only span links details', () => { + let transactionBLinksDetails: Awaited>; + let spanBLinksDetails: Awaited>; + before(async () => { + const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all([ + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerExternalOnly.traceId, + spanId: ids.producerExternalOnly.transactionBId, + processorEvent: ProcessorEvent.transaction, + }), + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerExternalOnly.traceId, + spanId: ids.producerExternalOnly.spanBId, + processorEvent: ProcessorEvent.span, + }), + ]); + transactionBLinksDetails = transactionALinksDetailsResponse; + spanBLinksDetails = spanALinksDetailsResponse; + }); - it('returns producer-consumer as children of transaction B', () => { - expect(transactionBLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); - }); + it('returns producer-consumer as children of transaction B', () => { + expect(transactionBLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); + }); - it('returns no parent for transaction B', () => { - expect(transactionBLinksDetails.parentsLinks.spanLinksDetails).to.eql([]); - }); + it('returns no parent for transaction B', () => { + expect(transactionBLinksDetails.parentsLinks.spanLinksDetails).to.eql([]); + }); - it('returns external parent on Span B', () => { - expect(spanBLinksDetails.parentsLinks.spanLinksDetails.length).to.be(1); - expect(spanBLinksDetails.parentsLinks.spanLinksDetails).to.eql([ - { traceId: 'trace#1', spanId: 'span#1' }, - ]); - }); + it('returns external parent on Span B', () => { + expect(spanBLinksDetails.parentsLinks.spanLinksDetails.length).to.be(1); + expect(spanBLinksDetails.parentsLinks.spanLinksDetails).to.eql([ + { traceId: 'trace#1', spanId: 'span#1' }, + ]); + }); - it('returns consumer-multiple as child on Span B', () => { - expect(spanBLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); - expect(spanBLinksDetails.childrenLinks.spanLinksDetails).to.eql([ - { - traceId: ids.producerMultiple.traceId, - spanId: ids.producerMultiple.spanEId, - details: { - serviceName: 'consumer-multiple', - agentName: 'nodejs', - transactionId: ids.producerMultiple.transactionDId, - spanName: 'Span E', - duration: 100000, - spanSubtype: 'http', - spanType: 'external', - }, + it('returns consumer-multiple as child on Span B', () => { + expect(spanBLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); + expect(spanBLinksDetails.childrenLinks.spanLinksDetails).to.eql([ + { + traceId: ids.producerMultiple.traceId, + spanId: ids.producerMultiple.spanEId, + details: { + serviceName: 'consumer-multiple', + agentName: 'nodejs', + transactionId: ids.producerMultiple.transactionDId, + spanName: 'Span E', + duration: 100000, + spanSubtype: 'http', + spanType: 'external', }, - ]); - }); + }, + ]); }); + }); - describe('producer-consumer span links details', () => { - let transactionCLinksDetails: Awaited>; - let spanCLinksDetails: Awaited>; - before(async () => { - const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all( - [ - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerConsumer.traceId, - spanId: ids.producerConsumer.transactionCId, - processorEvent: ProcessorEvent.transaction, - }), - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerConsumer.traceId, - spanId: ids.producerConsumer.spanCId, - processorEvent: ProcessorEvent.span, - }), - ] - ); - transactionCLinksDetails = transactionALinksDetailsResponse; - spanCLinksDetails = spanALinksDetailsResponse; - }); + describe('producer-consumer span links details', () => { + let transactionCLinksDetails: Awaited>; + let spanCLinksDetails: Awaited>; + before(async () => { + const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all([ + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerConsumer.traceId, + spanId: ids.producerConsumer.transactionCId, + processorEvent: ProcessorEvent.transaction, + }), + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerConsumer.traceId, + spanId: ids.producerConsumer.spanCId, + processorEvent: ProcessorEvent.span, + }), + ]); + transactionCLinksDetails = transactionALinksDetailsResponse; + spanCLinksDetails = spanALinksDetailsResponse; + }); - it('returns producer-internal-only Span A, producer-external-only Transaction B, and External link as parents of Transaction C', () => { - expect(transactionCLinksDetails.parentsLinks.spanLinksDetails.length).to.be(3); - expect(transactionCLinksDetails.parentsLinks.spanLinksDetails).to.eql([ - { - traceId: ids.producerInternalOnly.traceId, - spanId: ids.producerInternalOnly.spanAId, - details: { - serviceName: 'producer-internal-only', - agentName: 'go', - transactionId: ids.producerInternalOnly.transactionAId, - spanName: 'Span A', - duration: 100000, - spanSubtype: 'http', - spanType: 'external', - }, - }, - { - traceId: ids.producerExternalOnly.traceId, - spanId: ids.producerExternalOnly.transactionBId, - details: { - serviceName: 'producer-external-only', - agentName: 'java', - transactionId: ids.producerExternalOnly.transactionBId, - duration: 1000000, - spanName: 'Transaction B', - }, + it('returns producer-internal-only Span A, producer-external-only Transaction B, and External link as parents of Transaction C', () => { + expect(transactionCLinksDetails.parentsLinks.spanLinksDetails.length).to.be(3); + expect(transactionCLinksDetails.parentsLinks.spanLinksDetails).to.eql([ + { + traceId: ids.producerInternalOnly.traceId, + spanId: ids.producerInternalOnly.spanAId, + details: { + serviceName: 'producer-internal-only', + agentName: 'go', + transactionId: ids.producerInternalOnly.transactionAId, + spanName: 'Span A', + duration: 100000, + spanSubtype: 'http', + spanType: 'external', }, - { - traceId: ids.producerConsumer.externalTraceId, - spanId: ids.producerExternalOnly.spanBId, + }, + { + traceId: ids.producerExternalOnly.traceId, + spanId: ids.producerExternalOnly.transactionBId, + details: { + serviceName: 'producer-external-only', + agentName: 'java', + transactionId: ids.producerExternalOnly.transactionBId, + duration: 1000000, + spanName: 'Transaction B', }, - ]); - }); + }, + { + traceId: ids.producerConsumer.externalTraceId, + spanId: ids.producerExternalOnly.spanBId, + }, + ]); + }); - it('returns consumer-multiple Span E as child of Transaction C', () => { - expect(transactionCLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); - expect(transactionCLinksDetails.childrenLinks.spanLinksDetails).to.eql([ - { - traceId: ids.producerMultiple.traceId, - spanId: ids.producerMultiple.spanEId, - details: { - serviceName: 'consumer-multiple', - agentName: 'nodejs', - transactionId: ids.producerMultiple.transactionDId, - spanName: 'Span E', - duration: 100000, - spanSubtype: 'http', - spanType: 'external', - }, + it('returns consumer-multiple Span E as child of Transaction C', () => { + expect(transactionCLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); + expect(transactionCLinksDetails.childrenLinks.spanLinksDetails).to.eql([ + { + traceId: ids.producerMultiple.traceId, + spanId: ids.producerMultiple.spanEId, + details: { + serviceName: 'consumer-multiple', + agentName: 'nodejs', + transactionId: ids.producerMultiple.transactionDId, + spanName: 'Span E', + duration: 100000, + spanSubtype: 'http', + spanType: 'external', }, - ]); - }); + }, + ]); + }); - it('returns no child on Span C', () => { - expect(spanCLinksDetails.parentsLinks.spanLinksDetails.length).to.be(0); - }); + it('returns no child on Span C', () => { + expect(spanCLinksDetails.parentsLinks.spanLinksDetails.length).to.be(0); + }); - it('returns consumer-multiple as Child on producer-consumer', () => { - expect(spanCLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); - expect(spanCLinksDetails.childrenLinks.spanLinksDetails).to.eql([ - { - traceId: ids.producerMultiple.traceId, - spanId: ids.producerMultiple.transactionDId, - details: { - serviceName: 'consumer-multiple', - agentName: 'nodejs', - transactionId: ids.producerMultiple.transactionDId, - spanName: 'Transaction D', - duration: 1000000, - }, + it('returns consumer-multiple as Child on producer-consumer', () => { + expect(spanCLinksDetails.childrenLinks.spanLinksDetails.length).to.be(1); + expect(spanCLinksDetails.childrenLinks.spanLinksDetails).to.eql([ + { + traceId: ids.producerMultiple.traceId, + spanId: ids.producerMultiple.transactionDId, + details: { + serviceName: 'consumer-multiple', + agentName: 'nodejs', + transactionId: ids.producerMultiple.transactionDId, + spanName: 'Transaction D', + duration: 1000000, }, - ]); - }); + }, + ]); }); + }); - describe('consumer-multiple span links details', () => { - let transactionDLinksDetails: Awaited>; - let spanELinksDetails: Awaited>; - before(async () => { - const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all( - [ - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerMultiple.traceId, - spanId: ids.producerMultiple.transactionDId, - processorEvent: ProcessorEvent.transaction, - }), - fetchChildrenAndParentsDetails({ - kuery: '', - traceId: ids.producerMultiple.traceId, - spanId: ids.producerMultiple.spanEId, - processorEvent: ProcessorEvent.span, - }), - ] - ); - transactionDLinksDetails = transactionALinksDetailsResponse; - spanELinksDetails = spanALinksDetailsResponse; - }); + describe('consumer-multiple span links details', () => { + let transactionDLinksDetails: Awaited>; + let spanELinksDetails: Awaited>; + before(async () => { + const [transactionALinksDetailsResponse, spanALinksDetailsResponse] = await Promise.all([ + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerMultiple.traceId, + spanId: ids.producerMultiple.transactionDId, + processorEvent: ProcessorEvent.transaction, + }), + fetchChildrenAndParentsDetails({ + kuery: '', + traceId: ids.producerMultiple.traceId, + spanId: ids.producerMultiple.spanEId, + processorEvent: ProcessorEvent.span, + }), + ]); + transactionDLinksDetails = transactionALinksDetailsResponse; + spanELinksDetails = spanALinksDetailsResponse; + }); - it('returns producer-internal-only Span A and producer-consumer Span C as parents of Transaction D', () => { - expect(transactionDLinksDetails.parentsLinks.spanLinksDetails.length).to.be(2); - expect(transactionDLinksDetails.parentsLinks.spanLinksDetails).to.eql([ - { - traceId: ids.producerInternalOnly.traceId, - spanId: ids.producerInternalOnly.spanAId, - details: { - serviceName: 'producer-internal-only', - agentName: 'go', - transactionId: ids.producerInternalOnly.transactionAId, - spanName: 'Span A', - duration: 100000, - spanSubtype: 'http', - spanType: 'external', - }, + it('returns producer-internal-only Span A and producer-consumer Span C as parents of Transaction D', () => { + expect(transactionDLinksDetails.parentsLinks.spanLinksDetails.length).to.be(2); + expect(transactionDLinksDetails.parentsLinks.spanLinksDetails).to.eql([ + { + traceId: ids.producerInternalOnly.traceId, + spanId: ids.producerInternalOnly.spanAId, + details: { + serviceName: 'producer-internal-only', + agentName: 'go', + transactionId: ids.producerInternalOnly.transactionAId, + spanName: 'Span A', + duration: 100000, + spanSubtype: 'http', + spanType: 'external', }, - { - traceId: ids.producerConsumer.traceId, - spanId: ids.producerConsumer.spanCId, - details: { - serviceName: 'producer-consumer', - agentName: 'ruby', - transactionId: ids.producerConsumer.transactionCId, - spanName: 'Span C', - duration: 100000, - spanSubtype: 'http', - spanType: 'external', - }, + }, + { + traceId: ids.producerConsumer.traceId, + spanId: ids.producerConsumer.spanCId, + details: { + serviceName: 'producer-consumer', + agentName: 'ruby', + transactionId: ids.producerConsumer.transactionCId, + spanName: 'Span C', + duration: 100000, + spanSubtype: 'http', + spanType: 'external', }, - ]); - }); + }, + ]); + }); - it('returns no children on Transaction D', () => { - expect(transactionDLinksDetails.childrenLinks.spanLinksDetails.length).to.be(0); - }); + it('returns no children on Transaction D', () => { + expect(transactionDLinksDetails.childrenLinks.spanLinksDetails.length).to.be(0); + }); - it('returns producer-external-only Span B and producer-consumer Transaction C as parents of Span E', () => { - expect(spanELinksDetails.parentsLinks.spanLinksDetails.length).to.be(2); - - expect(spanELinksDetails.parentsLinks.spanLinksDetails).to.eql([ - { - traceId: ids.producerExternalOnly.traceId, - spanId: ids.producerExternalOnly.spanBId, - details: { - serviceName: 'producer-external-only', - agentName: 'java', - transactionId: ids.producerExternalOnly.transactionBId, - spanName: 'Span B', - duration: 100000, - spanSubtype: 'http', - spanType: 'external', - }, + it('returns producer-external-only Span B and producer-consumer Transaction C as parents of Span E', () => { + expect(spanELinksDetails.parentsLinks.spanLinksDetails.length).to.be(2); + + expect(spanELinksDetails.parentsLinks.spanLinksDetails).to.eql([ + { + traceId: ids.producerExternalOnly.traceId, + spanId: ids.producerExternalOnly.spanBId, + details: { + serviceName: 'producer-external-only', + agentName: 'java', + transactionId: ids.producerExternalOnly.transactionBId, + spanName: 'Span B', + duration: 100000, + spanSubtype: 'http', + spanType: 'external', }, - { - traceId: ids.producerConsumer.traceId, - spanId: ids.producerConsumer.transactionCId, - details: { - serviceName: 'producer-consumer', - agentName: 'ruby', - transactionId: ids.producerConsumer.transactionCId, - spanName: 'Transaction C', - duration: 1000000, - }, + }, + { + traceId: ids.producerConsumer.traceId, + spanId: ids.producerConsumer.transactionCId, + details: { + serviceName: 'producer-consumer', + agentName: 'ruby', + transactionId: ids.producerConsumer.transactionCId, + spanName: 'Transaction C', + duration: 1000000, }, - ]); - }); + }, + ]); + }); - it('returns no children on Span E', () => { - expect(spanELinksDetails.childrenLinks.spanLinksDetails.length).to.be(0); - }); + it('returns no children on Span E', () => { + expect(spanELinksDetails.childrenLinks.spanLinksDetails.length).to.be(0); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/throughput/dependencies_apis.spec.ts b/x-pack/test/apm_api_integration/tests/throughput/dependencies_apis.spec.ts index 58be27fe311ae..c990a7c632caa 100644 --- a/x-pack/test/apm_api_integration/tests/throughput/dependencies_apis.spec.ts +++ b/x-pack/test/apm_api_integration/tests/throughput/dependencies_apis.spec.ts @@ -93,149 +93,145 @@ export default function ApiTest({ getService }: FtrProviderContext) { let throughputValues: Awaited>; - registry.when( - 'Dependencies throughput value', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded', () => { - const GO_PROD_RATE = 75; - const JAVA_PROD_RATE = 25; + registry.when('Dependencies throughput value', { config: 'basic', archives: [] }, () => { + describe('when data is loaded', () => { + const GO_PROD_RATE = 75; + const JAVA_PROD_RATE = 25; + before(async () => { + const serviceGoProdInstance = apm + .service('synth-go', 'production', 'go') + .instance('instance-a'); + const serviceJavaInstance = apm + .service('synth-java', 'development', 'java') + .instance('instance-c'); + + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(GO_PROD_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction('GET /api/product/list') + .duration(1000) + .timestamp(timestamp) + .children( + serviceGoProdInstance + .span('GET apm-*/_search', 'db', 'elasticsearch') + .duration(1000) + .success() + .destination('elasticsearch') + .timestamp(timestamp), + serviceGoProdInstance + .span('custom_operation', 'app') + .duration(550) + .children( + serviceGoProdInstance + .span('SELECT FROM products', 'db', 'postgresql') + .duration(500) + .success() + .destination('postgresql') + .timestamp(timestamp) + ) + .success() + .timestamp(timestamp) + ) + ), + timerange(start, end) + .interval('1m') + .rate(JAVA_PROD_RATE) + .generator((timestamp) => + serviceJavaInstance + .transaction('POST /api/product/buy') + .duration(1000) + .timestamp(timestamp) + .children( + serviceJavaInstance + .span('GET apm-*/_search', 'db', 'elasticsearch') + .duration(1000) + .success() + .destination('elasticsearch') + .timestamp(timestamp), + serviceJavaInstance + .span('custom_operation', 'app') + .duration(50) + .success() + .timestamp(timestamp) + ) + ), + ]); + }); + + after(() => synthtraceEsClient.clean()); + + describe('verify top dependencies', () => { before(async () => { - const serviceGoProdInstance = apm - .service('synth-go', 'production', 'go') - .instance('instance-a'); - const serviceJavaInstance = apm - .service('synth-java', 'development', 'java') - .instance('instance-c'); - - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(GO_PROD_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction('GET /api/product/list') - .duration(1000) - .timestamp(timestamp) - .children( - serviceGoProdInstance - .span('GET apm-*/_search', 'db', 'elasticsearch') - .duration(1000) - .success() - .destination('elasticsearch') - .timestamp(timestamp), - serviceGoProdInstance - .span('custom_operation', 'app') - .duration(550) - .children( - serviceGoProdInstance - .span('SELECT FROM products', 'db', 'postgresql') - .duration(500) - .success() - .destination('postgresql') - .timestamp(timestamp) - ) - .success() - .timestamp(timestamp) - ) - ), - timerange(start, end) - .interval('1m') - .rate(JAVA_PROD_RATE) - .generator((timestamp) => - serviceJavaInstance - .transaction('POST /api/product/buy') - .duration(1000) - .timestamp(timestamp) - .children( - serviceJavaInstance - .span('GET apm-*/_search', 'db', 'elasticsearch') - .duration(1000) - .success() - .destination('elasticsearch') - .timestamp(timestamp), - serviceJavaInstance - .span('custom_operation', 'app') - .duration(50) - .success() - .timestamp(timestamp) - ) - ), - ]); + throughputValues = await getThroughputValues(); }); - after(() => synthtraceEsClient.clean()); + it('returns elasticsearch and postgresql as dependencies', () => { + const { topDependencies } = throughputValues; + const topDependenciesAsObj = Object.fromEntries(topDependencies); + expect(topDependenciesAsObj.elasticsearch).to.equal( + roundNumber(JAVA_PROD_RATE + GO_PROD_RATE) + ); + expect(topDependenciesAsObj.postgresql).to.equal(roundNumber(GO_PROD_RATE)); + }); + }); - describe('verify top dependencies', () => { + describe('compare throughput value between top backends, backend throughput chart and upstream services apis', () => { + describe('elasticsearch dependency', () => { before(async () => { - throughputValues = await getThroughputValues(); + throughputValues = await getThroughputValues({ dependencyName: 'elasticsearch' }); + }); + + it('matches throughput values between throughput chart and top dependency', () => { + const { topDependencies, dependencyThroughputChartMean } = throughputValues; + const topDependenciesAsObj = Object.fromEntries(topDependencies); + const elasticsearchDependency = topDependenciesAsObj.elasticsearch; + [elasticsearchDependency, dependencyThroughputChartMean].forEach((value) => + expect(value).to.be.equal(roundNumber(JAVA_PROD_RATE + GO_PROD_RATE)) + ); }); - it('returns elasticsearch and postgresql as dependencies', () => { - const { topDependencies } = throughputValues; + it('matches throughput values between upstream services and top dependency', () => { + const { topDependencies, upstreamServicesThroughput } = throughputValues; const topDependenciesAsObj = Object.fromEntries(topDependencies); - expect(topDependenciesAsObj.elasticsearch).to.equal( - roundNumber(JAVA_PROD_RATE + GO_PROD_RATE) + const elasticsearchDependency = topDependenciesAsObj.elasticsearch; + const upstreamServiceThroughputSum = roundNumber( + sumBy(upstreamServicesThroughput, 'throughput') + ); + [elasticsearchDependency, upstreamServiceThroughputSum].forEach((value) => + expect(value).to.be.equal(roundNumber(JAVA_PROD_RATE + GO_PROD_RATE)) ); - expect(topDependenciesAsObj.postgresql).to.equal(roundNumber(GO_PROD_RATE)); }); }); + describe('postgresql dependency', () => { + before(async () => { + throughputValues = await getThroughputValues({ dependencyName: 'postgresql' }); + }); - describe('compare throughput value between top backends, backend throughput chart and upstream services apis', () => { - describe('elasticsearch dependency', () => { - before(async () => { - throughputValues = await getThroughputValues({ dependencyName: 'elasticsearch' }); - }); - - it('matches throughput values between throughput chart and top dependency', () => { - const { topDependencies, dependencyThroughputChartMean } = throughputValues; - const topDependenciesAsObj = Object.fromEntries(topDependencies); - const elasticsearchDependency = topDependenciesAsObj.elasticsearch; - [elasticsearchDependency, dependencyThroughputChartMean].forEach((value) => - expect(value).to.be.equal(roundNumber(JAVA_PROD_RATE + GO_PROD_RATE)) - ); - }); - - it('matches throughput values between upstream services and top dependency', () => { - const { topDependencies, upstreamServicesThroughput } = throughputValues; - const topDependenciesAsObj = Object.fromEntries(topDependencies); - const elasticsearchDependency = topDependenciesAsObj.elasticsearch; - const upstreamServiceThroughputSum = roundNumber( - sumBy(upstreamServicesThroughput, 'throughput') - ); - [elasticsearchDependency, upstreamServiceThroughputSum].forEach((value) => - expect(value).to.be.equal(roundNumber(JAVA_PROD_RATE + GO_PROD_RATE)) - ); - }); + it('matches throughput values between throughput chart and top dependency', () => { + const { topDependencies, dependencyThroughputChartMean } = throughputValues; + const topDependenciesAsObj = Object.fromEntries(topDependencies); + const postgresqlDependency = topDependenciesAsObj.postgresql; + [postgresqlDependency, dependencyThroughputChartMean].forEach((value) => + expect(value).to.be.equal(roundNumber(GO_PROD_RATE)) + ); }); - describe('postgresql dependency', () => { - before(async () => { - throughputValues = await getThroughputValues({ dependencyName: 'postgresql' }); - }); - - it('matches throughput values between throughput chart and top dependency', () => { - const { topDependencies, dependencyThroughputChartMean } = throughputValues; - const topDependenciesAsObj = Object.fromEntries(topDependencies); - const postgresqlDependency = topDependenciesAsObj.postgresql; - [postgresqlDependency, dependencyThroughputChartMean].forEach((value) => - expect(value).to.be.equal(roundNumber(GO_PROD_RATE)) - ); - }); - - it('matches throughput values between upstream services and top dependency', () => { - const { topDependencies, upstreamServicesThroughput } = throughputValues; - const topDependenciesAsObj = Object.fromEntries(topDependencies); - const postgresqlDependency = topDependenciesAsObj.postgresql; - const upstreamServiceThroughputSum = roundNumber( - sumBy(upstreamServicesThroughput, 'throughput') - ); - [postgresqlDependency, upstreamServiceThroughputSum].forEach((value) => - expect(value).to.be.equal(roundNumber(GO_PROD_RATE)) - ); - }); + + it('matches throughput values between upstream services and top dependency', () => { + const { topDependencies, upstreamServicesThroughput } = throughputValues; + const topDependenciesAsObj = Object.fromEntries(topDependencies); + const postgresqlDependency = topDependenciesAsObj.postgresql; + const upstreamServiceThroughputSum = roundNumber( + sumBy(upstreamServicesThroughput, 'throughput') + ); + [postgresqlDependency, upstreamServiceThroughputSum].forEach((value) => + expect(value).to.be.equal(roundNumber(GO_PROD_RATE)) + ); }); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/throughput/service_apis.spec.ts b/x-pack/test/apm_api_integration/tests/throughput/service_apis.spec.ts index 41124abf10c5f..ef091dc83a429 100644 --- a/x-pack/test/apm_api_integration/tests/throughput/service_apis.spec.ts +++ b/x-pack/test/apm_api_integration/tests/throughput/service_apis.spec.ts @@ -104,7 +104,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { let throughputMetricValues: Awaited>; let throughputTransactionValues: Awaited>; - registry.when('Services APIs', { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, () => { + registry.when('Services APIs', { config: 'basic', archives: [] }, () => { describe('when data is loaded ', () => { const GO_PROD_RATE = 80; const GO_DEV_RATE = 20; diff --git a/x-pack/test/apm_api_integration/tests/throughput/service_maps.spec.ts b/x-pack/test/apm_api_integration/tests/throughput/service_maps.spec.ts index c3dc9adcaef19..fd775ec9af2a9 100644 --- a/x-pack/test/apm_api_integration/tests/throughput/service_maps.spec.ts +++ b/x-pack/test/apm_api_integration/tests/throughput/service_maps.spec.ts @@ -69,74 +69,67 @@ export default function ApiTest({ getService }: FtrProviderContext) { let throughputMetricValues: Awaited>; let throughputTransactionValues: Awaited>; - registry.when( - 'Service maps APIs', - { config: 'trial', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('when data is loaded ', () => { - const GO_PROD_RATE = 80; - const GO_DEV_RATE = 20; + registry.when('Service maps APIs', { config: 'trial', archives: [] }, () => { + describe('when data is loaded ', () => { + const GO_PROD_RATE = 80; + const GO_DEV_RATE = 20; + before(async () => { + const serviceGoProdInstance = apm + .service(serviceName, 'production', 'go') + .instance('instance-a'); + const serviceGoDevInstance = apm + .service(serviceName, 'development', 'go') + .instance('instance-b'); + + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(GO_PROD_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction('GET /apple 🍎 ', 'Worker') + .duration(1000) + .timestamp(timestamp) + ), + timerange(start, end) + .interval('1m') + .rate(GO_DEV_RATE) + .generator((timestamp) => + serviceGoDevInstance.transaction('GET /apple 🍎 ').duration(1000).timestamp(timestamp) + ), + ]); + }); + + after(() => synthtraceEsClient.clean()); + + describe('compare throughput value between service inventory and service maps', () => { before(async () => { - const serviceGoProdInstance = apm - .service(serviceName, 'production', 'go') - .instance('instance-a'); - const serviceGoDevInstance = apm - .service(serviceName, 'development', 'go') - .instance('instance-b'); - - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(GO_PROD_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction('GET /apple 🍎 ', 'Worker') - .duration(1000) - .timestamp(timestamp) - ), - timerange(start, end) - .interval('1m') - .rate(GO_DEV_RATE) - .generator((timestamp) => - serviceGoDevInstance - .transaction('GET /apple 🍎 ') - .duration(1000) - .timestamp(timestamp) - ), + [throughputTransactionValues, throughputMetricValues] = await Promise.all([ + getThroughputValues('transaction'), + getThroughputValues('metric'), ]); }); - after(() => synthtraceEsClient.clean()); - - describe('compare throughput value between service inventory and service maps', () => { - before(async () => { - [throughputTransactionValues, throughputMetricValues] = await Promise.all([ - getThroughputValues('transaction'), - getThroughputValues('metric'), - ]); - }); - - it('returns same throughput value for Transaction-based and Metric-based data', () => { - [ - ...Object.values(throughputTransactionValues), - ...Object.values(throughputMetricValues), - ].forEach((value) => expect(roundNumber(value)).to.be.equal(GO_DEV_RATE)); - }); + it('returns same throughput value for Transaction-based and Metric-based data', () => { + [ + ...Object.values(throughputTransactionValues), + ...Object.values(throughputMetricValues), + ].forEach((value) => expect(roundNumber(value)).to.be.equal(GO_DEV_RATE)); + }); + }); + + describe('when calling service maps transactions stats api', () => { + let serviceMapsNodeThroughput: number | null | undefined; + before(async () => { + const response = await callApi(); + serviceMapsNodeThroughput = + response.body.currentPeriod.transactionStats?.throughput?.value; }); - describe('when calling service maps transactions stats api', () => { - let serviceMapsNodeThroughput: number | null | undefined; - before(async () => { - const response = await callApi(); - serviceMapsNodeThroughput = - response.body.currentPeriod.transactionStats?.throughput?.value; - }); - - it('returns expected throughput value', () => { - expect(roundNumber(serviceMapsNodeThroughput)).to.be.equal(GO_DEV_RATE); - }); + it('returns expected throughput value', () => { + expect(roundNumber(serviceMapsNodeThroughput)).to.be.equal(GO_DEV_RATE); }); }); - } - ); + }); + }); } diff --git a/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts b/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts index b71beb0513af2..0c0696f801a95 100644 --- a/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts +++ b/x-pack/test/apm_api_integration/tests/traces/find_traces.spec.ts @@ -80,185 +80,146 @@ export default function ApiTest({ getService }: FtrProviderContext) { ); } - registry.when( - 'Find traces when traces do not exist', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - it('handles empty state', async () => { - const response = await fetchTraceSamples({ - query: '', - type: TraceSearchType.kql, - environment: ENVIRONMENT_ALL.value, - }); - - expect(response.status).to.be(200); - expect(response.body).to.eql({ - samples: [], - }); + registry.when('Find traces when traces do not exist', { config: 'basic', archives: [] }, () => { + it('handles empty state', async () => { + const response = await fetchTraceSamples({ + query: '', + type: TraceSearchType.kql, + environment: ENVIRONMENT_ALL.value, }); - } - ); - - registry.when( - 'Find traces when traces exist', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - before(() => { - const java = apm.service('java', 'production', 'java').instance('java'); - - const node = apm.service('node', 'development', 'nodejs').instance('node'); - - const python = apm.service('python', 'production', 'python').instance('python'); - - function generateTrace( - timestamp: number, - order: Instance[], - db?: 'elasticsearch' | 'redis' - ) { - return order - .concat() - .reverse() - .reduce((prev, instance, index) => { - const invertedIndex = order.length - index - 1; - - const duration = 50; - const time = timestamp + invertedIndex * 10; - - const transaction: Transaction = instance - .transaction(`GET /${instance.fields['service.name']!}/api`) - .timestamp(time) - .duration(duration); - - if (prev) { - const next = order[invertedIndex + 1].fields['service.name']!; - transaction.children( - instance - .span(`GET ${next}/api`, 'external', 'http') - .destination(next) - .duration(duration) - .timestamp(time + 1) - .children(prev) - ); - } else if (db) { - transaction.children( - instance - .span(db, 'db', db) - .destination(db) - .duration(duration) - .timestamp(time + 1) - ); - } - return transaction; - }, undefined)!; - } - - return synthtraceEsClient.index( - timerange(start, end) - .interval('15m') - .rate(1) - .generator((timestamp) => { - return [ - generateTrace(timestamp, [java, node]), - generateTrace(timestamp, [node, java], 'redis'), - generateTrace(timestamp, [python], 'redis'), - generateTrace(timestamp, [python, node, java], 'elasticsearch'), - generateTrace(timestamp, [java, python, node]), - ]; - }) - ); + expect(response.status).to.be(200); + expect(response.body).to.eql({ + samples: [], }); + }); + }); + + registry.when('Find traces when traces exist', { config: 'basic', archives: [] }, () => { + before(() => { + const java = apm.service('java', 'production', 'java').instance('java'); + + const node = apm.service('node', 'development', 'nodejs').instance('node'); + + const python = apm.service('python', 'production', 'python').instance('python'); + + function generateTrace(timestamp: number, order: Instance[], db?: 'elasticsearch' | 'redis') { + return order + .concat() + .reverse() + .reduce((prev, instance, index) => { + const invertedIndex = order.length - index - 1; + + const duration = 50; + const time = timestamp + invertedIndex * 10; + + const transaction: Transaction = instance + .transaction(`GET /${instance.fields['service.name']!}/api`) + .timestamp(time) + .duration(duration); + + if (prev) { + const next = order[invertedIndex + 1].fields['service.name']!; + transaction.children( + instance + .span(`GET ${next}/api`, 'external', 'http') + .destination(next) + .duration(duration) + .timestamp(time + 1) + .children(prev) + ); + } else if (db) { + transaction.children( + instance + .span(db, 'db', db) + .destination(db) + .duration(duration) + .timestamp(time + 1) + ); + } - describe('when using KQL', () => { - describe('and the query is empty', () => { - it('returns all trace samples', async () => { - const { - body: { samples }, - } = await fetchTraceSamples({ - query: '', - type: TraceSearchType.kql, - environment: 'ENVIRONMENT_ALL', - }); + return transaction; + }, undefined)!; + } + + return synthtraceEsClient.index( + timerange(start, end) + .interval('15m') + .rate(1) + .generator((timestamp) => { + return [ + generateTrace(timestamp, [java, node]), + generateTrace(timestamp, [node, java], 'redis'), + generateTrace(timestamp, [python], 'redis'), + generateTrace(timestamp, [python, node, java], 'elasticsearch'), + generateTrace(timestamp, [java, python, node]), + ]; + }) + ); + }); - expect(samples.length).to.eql(5); + describe('when using KQL', () => { + describe('and the query is empty', () => { + it('returns all trace samples', async () => { + const { + body: { samples }, + } = await fetchTraceSamples({ + query: '', + type: TraceSearchType.kql, + environment: 'ENVIRONMENT_ALL', }); - }); - - describe('and query is set', () => { - it('returns the relevant traces', async () => { - const { - body: { samples }, - } = await fetchTraceSamples({ - query: 'span.destination.service.resource:elasticsearch', - type: TraceSearchType.kql, - environment: 'ENVIRONMENT_ALL', - }); - expect(samples.length).to.eql(1); - }); + expect(samples.length).to.eql(5); }); }); - describe('when using EQL', () => { - describe('and the query is invalid', () => { - it.skip('returns a 400', async function () { - try { - await fetchTraceSamples({ - query: '', - type: TraceSearchType.eql, - environment: 'ENVIRONMENT_ALL', - }); - this.fail(); - } catch (error: unknown) { - const apiError = error as ApmApiError; - expect(apiError.res.status).to.eql(400); - } + describe('and query is set', () => { + it('returns the relevant traces', async () => { + const { + body: { samples }, + } = await fetchTraceSamples({ + query: 'span.destination.service.resource:elasticsearch', + type: TraceSearchType.kql, + environment: 'ENVIRONMENT_ALL', }); + + expect(samples.length).to.eql(1); }); + }); + }); - describe('and the query is set', () => { - it('returns the correct trace samples for transaction sequences', async () => { - const { - body: { samples }, - } = await fetchTraceSamples({ - query: `sequence by trace.id - [ transaction where service.name == "java" ] - [ transaction where service.name == "node" ]`, + describe('when using EQL', () => { + describe('and the query is invalid', () => { + it.skip('returns a 400', async function () { + try { + await fetchTraceSamples({ + query: '', type: TraceSearchType.eql, environment: 'ENVIRONMENT_ALL', }); - - const traces = await fetchTraces(samples); - - expect(traces.length).to.eql(2); - - const mapped = traces.map((traceDocs) => { - return sortBy(traceDocs, '@timestamp') - .filter((doc) => doc.processor.event === 'transaction') - .map((doc) => doc.service.name); - }); - - expect(mapped).to.eql([ - ['java', 'node'], - ['java', 'python', 'node'], - ]); - }); + this.fail(); + } catch (error: unknown) { + const apiError = error as ApmApiError; + expect(apiError.res.status).to.eql(400); + } }); + }); - it('returns the correct trace samples for join sequences', async () => { + describe('and the query is set', () => { + it('returns the correct trace samples for transaction sequences', async () => { const { body: { samples }, } = await fetchTraceSamples({ query: `sequence by trace.id - [ span where service.name == "java" ] by span.id - [ transaction where service.name == "python" ] by parent.id`, + [ transaction where service.name == "java" ] + [ transaction where service.name == "node" ]`, type: TraceSearchType.eql, environment: 'ENVIRONMENT_ALL', }); const traces = await fetchTraces(samples); - expect(traces.length).to.eql(1); + expect(traces.length).to.eql(2); const mapped = traces.map((traceDocs) => { return sortBy(traceDocs, '@timestamp') @@ -266,42 +227,69 @@ export default function ApiTest({ getService }: FtrProviderContext) { .map((doc) => doc.service.name); }); - expect(mapped).to.eql([['java', 'python', 'node']]); + expect(mapped).to.eql([ + ['java', 'node'], + ['java', 'python', 'node'], + ]); }); + }); - it('returns the correct trace samples for exit spans', async () => { - const { - body: { samples }, - } = await fetchTraceSamples({ - query: `sequence by trace.id + it('returns the correct trace samples for join sequences', async () => { + const { + body: { samples }, + } = await fetchTraceSamples({ + query: `sequence by trace.id + [ span where service.name == "java" ] by span.id + [ transaction where service.name == "python" ] by parent.id`, + type: TraceSearchType.eql, + environment: 'ENVIRONMENT_ALL', + }); + + const traces = await fetchTraces(samples); + + expect(traces.length).to.eql(1); + + const mapped = traces.map((traceDocs) => { + return sortBy(traceDocs, '@timestamp') + .filter((doc) => doc.processor.event === 'transaction') + .map((doc) => doc.service.name); + }); + + expect(mapped).to.eql([['java', 'python', 'node']]); + }); + + it('returns the correct trace samples for exit spans', async () => { + const { + body: { samples }, + } = await fetchTraceSamples({ + query: `sequence by trace.id [ transaction where service.name == "python" ] [ span where span.destination.service.resource == "redis" ]`, - type: TraceSearchType.eql, - environment: 'ENVIRONMENT_ALL', - }); + type: TraceSearchType.eql, + environment: 'ENVIRONMENT_ALL', + }); - const traces = await fetchTraces(samples); + const traces = await fetchTraces(samples); - expect(traces.length).to.eql(1); + expect(traces.length).to.eql(1); - const mapped = traces.map((traceDocs) => { - return sortBy(traceDocs, '@timestamp') - .filter( - (doc) => doc.processor.event === 'transaction' || doc.processor.event === 'span' - ) - .map((doc) => { - if (doc.span && 'destination' in doc.span) { - return doc.span.destination!.service.resource; - } - return doc.service.name; - }); - }); - - expect(mapped).to.eql([['python', 'redis']]); + const mapped = traces.map((traceDocs) => { + return sortBy(traceDocs, '@timestamp') + .filter( + (doc) => doc.processor.event === 'transaction' || doc.processor.event === 'span' + ) + .map((doc) => { + if (doc.span && 'destination' in doc.span) { + return doc.span.destination!.service.resource; + } + return doc.service.name; + }); }); + + expect(mapped).to.eql([['python', 'redis']]); }); + }); - after(() => synthtraceEsClient.clean()); - } - ); + after(() => synthtraceEsClient.clean()); + }); } diff --git a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts index 108772a57bc26..509d70caf5291 100644 --- a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts +++ b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts @@ -52,7 +52,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - registry.when('Trace exists', { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, () => { + registry.when('Trace exists', { config: 'basic', archives: [] }, () => { let serviceATraceId: string; before(async () => { const instanceJava = apm.service('synth-apple', 'production', 'java').instance('instance-b'); diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.spec.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.spec.ts index 4bbc2490dcd4b..350830abcbba3 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.spec.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.spec.ts @@ -75,178 +75,172 @@ export default function ApiTest({ getService }: FtrProviderContext) { } ); - registry.when( - 'data is loaded', - { config: 'basic', archives: ['apm_mappings_only_8.0.0'] }, - () => { - describe('transactions groups detailed stats', () => { - const GO_PROD_RATE = 75; - const GO_PROD_ERROR_RATE = 25; + registry.when('data is loaded', { config: 'basic', archives: [] }, () => { + describe('transactions groups detailed stats', () => { + const GO_PROD_RATE = 75; + const GO_PROD_ERROR_RATE = 25; + before(async () => { + const serviceGoProdInstance = apm + .service(serviceName, 'production', 'go') + .instance('instance-a'); + + const transactionName = 'GET /api/product/list'; + + await synthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(GO_PROD_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction(transactionName) + .timestamp(timestamp) + .duration(1000) + .success() + ), + timerange(start, end) + .interval('1m') + .rate(GO_PROD_ERROR_RATE) + .generator((timestamp) => + serviceGoProdInstance + .transaction(transactionName) + .duration(1000) + .timestamp(timestamp) + .failure() + ), + ]); + }); + + after(() => synthtraceEsClient.clean()); + + describe('without comparisons', () => { + let transactionsStatistics: TransactionsGroupsDetailedStatistics; + let metricsStatistics: TransactionsGroupsDetailedStatistics; before(async () => { - const serviceGoProdInstance = apm - .service(serviceName, 'production', 'go') - .instance('instance-a'); - - const transactionName = 'GET /api/product/list'; - - await synthtraceEsClient.index([ - timerange(start, end) - .interval('1m') - .rate(GO_PROD_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction(transactionName) - .timestamp(timestamp) - .duration(1000) - .success() - ), - timerange(start, end) - .interval('1m') - .rate(GO_PROD_ERROR_RATE) - .generator((timestamp) => - serviceGoProdInstance - .transaction(transactionName) - .duration(1000) - .timestamp(timestamp) - .failure() - ), + [metricsStatistics, transactionsStatistics] = await Promise.all([ + callApi({ query: { kuery: 'processor.event : "metric"' } }), + callApi({ query: { kuery: 'processor.event : "transaction"' } }), ]); }); - after(() => synthtraceEsClient.clean()); - - describe('without comparisons', () => { - let transactionsStatistics: TransactionsGroupsDetailedStatistics; - let metricsStatistics: TransactionsGroupsDetailedStatistics; - before(async () => { - [metricsStatistics, transactionsStatistics] = await Promise.all([ - callApi({ query: { kuery: 'processor.event : "metric"' } }), - callApi({ query: { kuery: 'processor.event : "transaction"' } }), - ]); - }); - - it('returns some transactions data', () => { - expect(isEmpty(transactionsStatistics.currentPeriod)).to.be.equal(false); - }); + it('returns some transactions data', () => { + expect(isEmpty(transactionsStatistics.currentPeriod)).to.be.equal(false); + }); - it('returns some metrics data', () => { - expect(isEmpty(metricsStatistics.currentPeriod)).to.be.equal(false); - }); + it('returns some metrics data', () => { + expect(isEmpty(metricsStatistics.currentPeriod)).to.be.equal(false); + }); - it('has same latency mean value for metrics and transactions data', () => { - const transactionsCurrentPeriod = - transactionsStatistics.currentPeriod[transactionNames[0]]; - const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; - const transactionsLatencyMean = meanBy(transactionsCurrentPeriod.latency, 'y'); - const metricsLatencyMean = meanBy(metricsCurrentPeriod.latency, 'y'); - [transactionsLatencyMean, metricsLatencyMean].forEach((value) => - expect(value).to.be.equal(1000000) - ); - }); + it('has same latency mean value for metrics and transactions data', () => { + const transactionsCurrentPeriod = + transactionsStatistics.currentPeriod[transactionNames[0]]; + const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; + const transactionsLatencyMean = meanBy(transactionsCurrentPeriod.latency, 'y'); + const metricsLatencyMean = meanBy(metricsCurrentPeriod.latency, 'y'); + [transactionsLatencyMean, metricsLatencyMean].forEach((value) => + expect(value).to.be.equal(1000000) + ); + }); - it('has same error rate mean value for metrics and transactions data', () => { - const transactionsCurrentPeriod = - transactionsStatistics.currentPeriod[transactionNames[0]]; - const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; + it('has same error rate mean value for metrics and transactions data', () => { + const transactionsCurrentPeriod = + transactionsStatistics.currentPeriod[transactionNames[0]]; + const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; - const transactionsErrorRateMean = meanBy(transactionsCurrentPeriod.errorRate, 'y'); - const metricsErrorRateMean = meanBy(metricsCurrentPeriod.errorRate, 'y'); - [transactionsErrorRateMean, metricsErrorRateMean].forEach((value) => - expect(asPercent(value, 1)).to.be.equal(`${GO_PROD_ERROR_RATE}%`) - ); - }); + const transactionsErrorRateMean = meanBy(transactionsCurrentPeriod.errorRate, 'y'); + const metricsErrorRateMean = meanBy(metricsCurrentPeriod.errorRate, 'y'); + [transactionsErrorRateMean, metricsErrorRateMean].forEach((value) => + expect(asPercent(value, 1)).to.be.equal(`${GO_PROD_ERROR_RATE}%`) + ); + }); - it('has same throughput mean value for metrics and transactions data', () => { - const transactionsCurrentPeriod = - transactionsStatistics.currentPeriod[transactionNames[0]]; - const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; - const transactionsThroughputMean = roundNumber( - meanBy(transactionsCurrentPeriod.throughput, 'y') - ); - const metricsThroughputMean = roundNumber(meanBy(metricsCurrentPeriod.throughput, 'y')); - [transactionsThroughputMean, metricsThroughputMean].forEach((value) => - expect(value).to.be.equal(roundNumber(GO_PROD_RATE + GO_PROD_ERROR_RATE)) - ); - }); + it('has same throughput mean value for metrics and transactions data', () => { + const transactionsCurrentPeriod = + transactionsStatistics.currentPeriod[transactionNames[0]]; + const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; + const transactionsThroughputMean = roundNumber( + meanBy(transactionsCurrentPeriod.throughput, 'y') + ); + const metricsThroughputMean = roundNumber(meanBy(metricsCurrentPeriod.throughput, 'y')); + [transactionsThroughputMean, metricsThroughputMean].forEach((value) => + expect(value).to.be.equal(roundNumber(GO_PROD_RATE + GO_PROD_ERROR_RATE)) + ); + }); - it('has same impact value for metrics and transactions data', () => { - const transactionsCurrentPeriod = - transactionsStatistics.currentPeriod[transactionNames[0]]; - const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; + it('has same impact value for metrics and transactions data', () => { + const transactionsCurrentPeriod = + transactionsStatistics.currentPeriod[transactionNames[0]]; + const metricsCurrentPeriod = metricsStatistics.currentPeriod[transactionNames[0]]; - const transactionsImpact = transactionsCurrentPeriod.impact; - const metricsImpact = metricsCurrentPeriod.impact; - [transactionsImpact, metricsImpact].forEach((value) => expect(value).to.be.equal(100)); - }); + const transactionsImpact = transactionsCurrentPeriod.impact; + const metricsImpact = metricsCurrentPeriod.impact; + [transactionsImpact, metricsImpact].forEach((value) => expect(value).to.be.equal(100)); }); + }); - describe('with comparisons', () => { - let transactionsStatistics: TransactionsGroupsDetailedStatistics; - before(async () => { - transactionsStatistics = await callApi({ - query: { - start: moment(end).subtract(7, 'minutes').toISOString(), - end: new Date(end).toISOString(), - offset: '8m', - }, - }); + describe('with comparisons', () => { + let transactionsStatistics: TransactionsGroupsDetailedStatistics; + before(async () => { + transactionsStatistics = await callApi({ + query: { + start: moment(end).subtract(7, 'minutes').toISOString(), + end: new Date(end).toISOString(), + offset: '8m', + }, }); + }); - it('returns some data for both periods', () => { - expect(isEmpty(transactionsStatistics.currentPeriod)).to.be.equal(false); - expect(isEmpty(transactionsStatistics.previousPeriod)).to.be.equal(false); - }); + it('returns some data for both periods', () => { + expect(isEmpty(transactionsStatistics.currentPeriod)).to.be.equal(false); + expect(isEmpty(transactionsStatistics.previousPeriod)).to.be.equal(false); + }); - it('has same start time for both periods', () => { - const currentPeriod = transactionsStatistics.currentPeriod[transactionNames[0]]; - const previousPeriod = transactionsStatistics.previousPeriod[transactionNames[0]]; - [ - [currentPeriod.latency, previousPeriod.latency], - [currentPeriod.errorRate, previousPeriod.errorRate], - [currentPeriod.throughput, previousPeriod.throughput], - ].forEach(([currentTimeseries, previousTimeseries]) => { - const firstCurrentPeriodDate = new Date( - first(currentTimeseries)?.x ?? NaN - ).toISOString(); - const firstPreviousPeriodDate = new Date( - first(previousPeriod.latency)?.x ?? NaN - ).toISOString(); - - expect(firstCurrentPeriodDate).to.equal(firstPreviousPeriodDate); - }); + it('has same start time for both periods', () => { + const currentPeriod = transactionsStatistics.currentPeriod[transactionNames[0]]; + const previousPeriod = transactionsStatistics.previousPeriod[transactionNames[0]]; + [ + [currentPeriod.latency, previousPeriod.latency], + [currentPeriod.errorRate, previousPeriod.errorRate], + [currentPeriod.throughput, previousPeriod.throughput], + ].forEach(([currentTimeseries, previousTimeseries]) => { + const firstCurrentPeriodDate = new Date( + first(currentTimeseries)?.x ?? NaN + ).toISOString(); + const firstPreviousPeriodDate = new Date( + first(previousPeriod.latency)?.x ?? NaN + ).toISOString(); + + expect(firstCurrentPeriodDate).to.equal(firstPreviousPeriodDate); }); - it('has same end time for both periods', () => { - const currentPeriod = transactionsStatistics.currentPeriod[transactionNames[0]]; - const previousPeriod = transactionsStatistics.previousPeriod[transactionNames[0]]; - [ - [currentPeriod.latency, previousPeriod.latency], - [currentPeriod.errorRate, previousPeriod.errorRate], - [currentPeriod.throughput, previousPeriod.throughput], - ].forEach(([currentTimeseries, previousTimeseries]) => { - const lastCurrentPeriodDate = new Date( - last(currentTimeseries)?.x ?? NaN - ).toISOString(); - const lastPreviousPeriodDate = new Date( - last(previousPeriod.latency)?.x ?? NaN - ).toISOString(); - - expect(lastCurrentPeriodDate).to.equal(lastPreviousPeriodDate); - }); + }); + it('has same end time for both periods', () => { + const currentPeriod = transactionsStatistics.currentPeriod[transactionNames[0]]; + const previousPeriod = transactionsStatistics.previousPeriod[transactionNames[0]]; + [ + [currentPeriod.latency, previousPeriod.latency], + [currentPeriod.errorRate, previousPeriod.errorRate], + [currentPeriod.throughput, previousPeriod.throughput], + ].forEach(([currentTimeseries, previousTimeseries]) => { + const lastCurrentPeriodDate = new Date(last(currentTimeseries)?.x ?? NaN).toISOString(); + const lastPreviousPeriodDate = new Date( + last(previousPeriod.latency)?.x ?? NaN + ).toISOString(); + + expect(lastCurrentPeriodDate).to.equal(lastPreviousPeriodDate); }); + }); - it('returns same number of buckets for both periods', () => { - const currentPeriod = transactionsStatistics.currentPeriod[transactionNames[0]]; - const previousPeriod = transactionsStatistics.previousPeriod[transactionNames[0]]; - [ - [currentPeriod.latency, previousPeriod.latency], - [currentPeriod.errorRate, previousPeriod.errorRate], - [currentPeriod.throughput, previousPeriod.throughput], - ].forEach(([currentTimeseries, previousTimeseries]) => { - expect(currentTimeseries.length).to.equal(previousTimeseries.length); - }); + it('returns same number of buckets for both periods', () => { + const currentPeriod = transactionsStatistics.currentPeriod[transactionNames[0]]; + const previousPeriod = transactionsStatistics.previousPeriod[transactionNames[0]]; + [ + [currentPeriod.latency, previousPeriod.latency], + [currentPeriod.errorRate, previousPeriod.errorRate], + [currentPeriod.throughput, previousPeriod.throughput], + ].forEach(([currentTimeseries, previousTimeseries]) => { + expect(currentTimeseries.length).to.equal(previousTimeseries.length); }); }); }); - } - ); + }); + }); } From 50821db39c07d5d35d510c8082d5c608c4e2fd4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 23 Aug 2022 20:56:55 +0200 Subject: [PATCH 36/41] [APM] Improve Cypress tests with sessions and better async handling (#139278) --- x-pack/plugins/apm/ftr_e2e/cypress.json | 5 +- .../feature_flag/comparison.spec.ts | 40 ++++++----- .../infrastructure_page.spec.ts | 18 ++--- .../integration_policy.spec.ts | 8 +-- .../integration/power_user/no_data_screen.ts | 69 +++++++++---------- .../power_user/rules/error_count.spec.ts | 35 +++++----- .../settings/agent_configurations.spec.ts | 10 +-- .../power_user/settings/custom_links.spec.ts | 6 +- .../read_only_user/deep_links.spec.ts | 4 +- .../read_only_user/dependencies.spec.ts | 20 +++--- .../errors/error_details.spec.ts | 22 +++--- .../read_only_user/errors/errors_page.spec.ts | 41 ++++++----- .../integration/read_only_user/home.spec.ts | 14 ++-- .../header_filters/header_filters.spec.ts | 10 +-- .../service_inventory.spec.ts | 34 +++++---- .../aws_lambda/aws_lamba.spec.ts | 17 ++--- .../service_overview/errors_table.spec.ts | 16 ++--- .../service_overview/header_filters.spec.ts | 14 ++-- .../service_overview/instances_table.spec.ts | 32 ++++----- .../service_overview/service_overview.spec.ts | 44 +++++++----- .../service_overview/time_comparison.spec.ts | 20 +++--- .../generate_span_links_data.ts | 4 +- .../transaction_details/span_links.spec.ts | 48 ++++++++----- .../transaction_details.spec.ts | 10 +-- .../transactions_overview.spec.ts | 12 ++-- .../read_only_user/tutorial/tutorial.spec.ts | 4 +- .../apm/ftr_e2e/cypress/support/commands.ts | 42 +++++++---- .../apm/ftr_e2e/cypress/support/types.d.ts | 1 + x-pack/plugins/apm/ftr_e2e/synthtrace.ts | 9 +-- 29 files changed, 322 insertions(+), 287 deletions(-) diff --git a/x-pack/plugins/apm/ftr_e2e/cypress.json b/x-pack/plugins/apm/ftr_e2e/cypress.json index 1791baaa5aae4..848a10efed668 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress.json +++ b/x-pack/plugins/apm/ftr_e2e/cypress.json @@ -6,11 +6,14 @@ "screenshotsFolder": "./cypress/screenshots", "supportFile": "./cypress/support/index.ts", "videosFolder": "./cypress/videos", + "requestTimeout": 10000, + "responseTimeout": 40000, "defaultCommandTimeout": 30000, "execTimeout": 120000, "pageLoadTimeout": 120000, "viewportHeight": 900, "viewportWidth": 1440, "video": false, - "screenshotOnRunFailure": false + "screenshotOnRunFailure": false, + "experimentalSessionAndOrigin": true } diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/feature_flag/comparison.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/feature_flag/comparison.spec.ts index 1a58eb1ca4fda..d1159efd0fc90 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/feature_flag/comparison.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/feature_flag/comparison.spec.ts @@ -10,9 +10,9 @@ import { opbeans } from '../../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; const end = '2021-10-10T00:15:00.000Z'; -describe.skip('Comparison feature flag', () => { - before(async () => { - await synthtrace.index( +describe('Comparison feature flag', () => { + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -20,29 +20,33 @@ describe.skip('Comparison feature flag', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); describe('when comparison feature is enabled', () => { beforeEach(() => { cy.loginAsEditorUser(); + + cy.updateAdvancedSettings({ + 'observability:enableComparisonByDefault': true, + }); }); it('shows the comparison feature enabled in services overview', () => { - cy.visit('/app/apm/services'); + cy.visitKibana('/app/apm/services'); cy.get('input[type="checkbox"]#comparison').should('be.checked'); cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled'); }); - it('shows the comparison feature enabled in services overview', () => { - cy.visit('/app/apm/dependencies'); + it('shows the comparison feature enabled in dependencies overview', () => { + cy.visitKibana('/app/apm/dependencies'); cy.get('input[type="checkbox"]#comparison').should('be.checked'); cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled'); }); it('shows the comparison feature disabled in service map overview page', () => { - cy.visit('/app/apm/service-map'); + cy.visitKibana('/app/apm/service-map'); cy.get('input[type="checkbox"]#comparison').should('be.checked'); cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled'); }); @@ -50,11 +54,11 @@ describe.skip('Comparison feature flag', () => { describe('when comparison feature is disabled', () => { beforeEach(() => { - cy.loginAsEditorUser().then(() => { - // Disables comparison feature on advanced settings - cy.updateAdvancedSettings({ - 'observability:enableComparisonByDefault': false, - }); + cy.loginAsEditorUser(); + + // Disables comparison feature on advanced settings + cy.updateAdvancedSettings({ + 'observability:enableComparisonByDefault': false, }); }); @@ -65,7 +69,7 @@ describe.skip('Comparison feature flag', () => { }); it('shows the comparison feature disabled in services overview', () => { - cy.visit('/app/apm/services'); + cy.visitKibana('/app/apm/services'); cy.get('input[type="checkbox"]#comparison').should('not.be.checked'); cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); }); @@ -74,14 +78,14 @@ describe.skip('Comparison feature flag', () => { cy.intercept('GET', '/internal/apm/dependencies/top_dependencies?*').as( 'topDependenciesRequest' ); - cy.visit('/app/apm/dependencies'); - cy.wait('@topDependenciesRequest', { requestTimeout: 10000 }); + cy.visitKibana('/app/apm/dependencies'); + cy.wait('@topDependenciesRequest'); cy.get('input[type="checkbox"]#comparison').should('not.be.checked'); cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); }); it('shows the comparison feature disabled in service map overview page', () => { - cy.visit('/app/apm/service-map'); + cy.visitKibana('/app/apm/service-map'); cy.get('input[type="checkbox"]#comparison').should('not.be.checked'); cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/infrastructure/infrastructure_page.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/infrastructure/infrastructure_page.spec.ts index 46d654ef2a4aa..439b95a796b71 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/infrastructure/infrastructure_page.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/infrastructure/infrastructure_page.spec.ts @@ -27,9 +27,9 @@ const nodeServiceInfraPageHref = url.format({ query: { rangeFrom: start, rangeTo: end }, }); -describe.skip('Infrastructure page', () => { - before(async () => { - await synthtrace.index( +describe('Infrastructure page', () => { + before(() => { + synthtrace.index( generateData({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -37,8 +37,8 @@ describe.skip('Infrastructure page', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { @@ -47,7 +47,7 @@ describe.skip('Infrastructure page', () => { describe('when data is loaded', () => { it('has no detectable a11y violations on load', () => { - cy.visit(goServiceInfraPageHref); + cy.visitKibana(goServiceInfraPageHref); cy.contains('Infrastructure'); // set skipFailures to true to not fail the test when there are accessibility failures checkA11y({ skipFailures: true }); @@ -55,7 +55,7 @@ describe.skip('Infrastructure page', () => { describe('when container ids, pod names and host names are returned by the api call', () => { it('shows all tabs', () => { - cy.visit(goServiceInfraPageHref); + cy.visitKibana(goServiceInfraPageHref); cy.contains('Containers'); cy.contains('Pods'); cy.contains('Hosts'); @@ -64,14 +64,14 @@ describe.skip('Infrastructure page', () => { describe('when only host names are returned by the api call', () => { it('shows only Hosts tab', () => { - cy.visit(javaServiceInfraPageHref); + cy.visitKibana(javaServiceInfraPageHref); cy.contains('Hosts'); }); }); describe('when none infrastructure attributes are returned by the api call', () => { it('shows no data message', () => { - cy.visit(nodeServiceInfraPageHref); + cy.visitKibana(nodeServiceInfraPageHref); cy.contains('No results match your search criteria.'); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/integration_settings/integration_policy.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/integration_settings/integration_policy.spec.ts index 655376eb3eb63..7b97813cb1219 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/integration_settings/integration_policy.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/integration_settings/integration_policy.spec.ts @@ -57,7 +57,7 @@ describe.skip('when navigating to integration page', () => { const integrationsPath = '/app/integrations/browse'; cy.loginAsEditorUser(); - cy.visit(integrationsPath); + cy.visitKibana(integrationsPath); // open integration policy form cy.get('[data-test-subj="integration-card:epr:apm:featured').click(); @@ -79,17 +79,17 @@ describe.skip('when navigating to integration page', () => { }); it('should display Tail-based section on latest version', () => { - cy.visit('/app/fleet/integrations/apm/add-integration'); + cy.visitKibana('/app/fleet/integrations/apm/add-integration'); cy.contains('Tail-based sampling').should('exist'); }); it('should hide Tail-based section for 8.0.0 apm package', () => { - cy.visit('/app/fleet/integrations/apm-8.0.0/add-integration'); + cy.visitKibana('/app/fleet/integrations/apm-8.0.0/add-integration'); cy.contains('Tail-based sampling').should('not.exist'); }); it('should Display Debug section', () => { - cy.visit('/app/fleet/integrations/apm-8.0.0/add-integration'); + cy.visitKibana('/app/fleet/integrations/apm-8.0.0/add-integration'); cy.contains('Debug settings').should('exist'); }); }); 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 c7f33301a5dfc..ae08bc1ea9b63 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 @@ -5,60 +5,55 @@ * 2.0. */ -const apmIndicesSaveURL = '/internal/apm/settings/apm-indices/save'; - describe('No data screen', () => { describe('bypass no data screen on settings pages', () => { - beforeEach(() => { - cy.loginAsEditorUser(); - }); - before(() => { - // Change default indices - cy.request({ - url: apmIndicesSaveURL, - method: 'POST', - body: { - sourcemap: 'foo-*', - error: 'foo-*', - onboarding: 'foo-*', - span: 'foo-*', - transaction: 'foo-*', - metric: 'foo-*', - }, - headers: { - 'kbn-xsrf': true, - }, - auth: { user: 'editor', pass: 'changeme' }, + // Change indices + setApmIndices({ + sourcemap: 'foo-*', + error: 'foo-*', + onboarding: 'foo-*', + span: 'foo-*', + transaction: 'foo-*', + metric: 'foo-*', }); }); + beforeEach(() => { + cy.loginAsEditorUser(); + }); + it('shows no data screen instead of service inventory', () => { - cy.visit('/app/apm/'); + cy.visitKibana('/app/apm/'); cy.contains('Welcome to Elastic Observability!'); }); + it('shows settings page', () => { - cy.visit('/app/apm/settings'); + cy.visitKibana('/app/apm/settings'); cy.contains('Welcome to Elastic Observability!').should('not.exist'); cy.get('h1').contains('Settings'); }); after(() => { // reset to default indices - cy.request({ - url: apmIndicesSaveURL, - method: 'POST', - body: { - sourcemap: '', - error: '', - onboarding: '', - span: '', - transaction: '', - metric: '', - }, - headers: { 'kbn-xsrf': true }, - auth: { user: 'editor', pass: 'changeme' }, + setApmIndices({ + sourcemap: '', + error: '', + onboarding: '', + span: '', + transaction: '', + metric: '', }); }); }); }); + +function setApmIndices(body: Record) { + cy.request({ + url: '/internal/apm/settings/apm-indices/save', + method: 'POST', + body, + headers: { 'kbn-xsrf': true }, + auth: { user: 'editor', pass: 'changeme' }, + }); +} diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts index b145369535225..ec01fc2df2da3 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/rules/error_count.spec.ts @@ -6,10 +6,12 @@ */ function deleteAllRules() { + cy.log('Delete all rules'); cy.request({ log: false, method: 'GET', url: '/api/alerting/rules/_find', + auth: { user: 'editor', pass: 'changeme' }, }).then(({ body }) => { if (body.data.length > 0) { cy.log(`Deleting rules`); @@ -21,12 +23,21 @@ function deleteAllRules() { log: false, method: 'DELETE', url: `/api/alerting/rule/${id}`, + auth: { user: 'editor', pass: 'changeme' }, }); }); }); } describe('Rules', () => { + beforeEach(() => { + deleteAllRules(); + }); + + after(() => { + deleteAllRules(); + }); + describe('Error count', () => { const ruleName = 'Error count threshold'; const comboBoxInputSelector = @@ -36,18 +47,11 @@ describe('Rules', () => { describe('when created from APM', () => { describe('when created from Service Inventory', () => { - before(() => { + it('creates a rule', () => { cy.loginAsEditorUser(); - deleteAllRules(); - }); - - after(() => { - deleteAllRules(); - }); - it('creates a rule', () => { // Create a rule in APM - cy.visit('/app/apm/services'); + cy.visitKibana('/app/apm/services'); cy.contains('Alerts and rules').click(); cy.contains('Create error count rule').click(); @@ -67,18 +71,13 @@ describe('Rules', () => { }); describe('when created from Stack management', () => { - before(() => { + it('creates a rule', () => { cy.loginAsEditorUser(); - deleteAllRules(); - }); - after(() => { - deleteAllRules(); - }); - - it('creates a rule', () => { // Go to stack management - cy.visit('/app/management/insightsAndAlerting/triggersActions/rules'); + cy.visitKibana( + '/app/management/insightsAndAlerting/triggersActions/rules' + ); // Create a rule cy.contains('button', 'Create rule').click(); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/agent_configurations.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/agent_configurations.spec.ts index a2f5e055e80a8..23154492c9f44 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/agent_configurations.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/agent_configurations.spec.ts @@ -55,10 +55,10 @@ function generateData({ } describe('Agent configuration', () => { - before(async () => { + before(() => { const { rangeFrom, rangeTo } = timeRange; - await synthtrace.index( + synthtrace.index( generateData({ from: new Date(rangeFrom).getTime(), to: new Date(rangeTo).getTime(), @@ -67,13 +67,13 @@ describe('Agent configuration', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { cy.loginAsEditorUser(); - cy.visit(agentConfigHref); + cy.visitKibana(agentConfigHref); }); it('persists service enviroment when clicking on edit button', () => { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/custom_links.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/custom_links.spec.ts index e5c409cb6da0d..53dbb82c1c6ae 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/custom_links.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/power_user/settings/custom_links.spec.ts @@ -13,13 +13,13 @@ describe('Custom links', () => { }); it('shows empty message and create button', () => { - cy.visit(basePath); + cy.visitKibana(basePath); cy.contains('No links found'); cy.contains('Create custom link'); }); it('creates custom link', () => { - cy.visit(basePath); + cy.visitKibana(basePath); const emptyPrompt = cy.get('[data-test-subj="customLinksEmptyPrompt"]'); cy.contains('Create custom link').click(); cy.contains('Create link'); @@ -36,7 +36,7 @@ describe('Custom links', () => { }); it('clears filter values when field is selected', () => { - cy.visit(basePath); + cy.visitKibana(basePath); cy.contains('Create custom link').click(); cy.get('[data-test-subj="filter-0"]').select('service.name'); cy.get( diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/deep_links.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/deep_links.spec.ts index 76c43ef03f332..cfcabe85b5b2a 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/deep_links.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/deep_links.spec.ts @@ -6,11 +6,11 @@ */ describe('APM deep links', () => { - before(() => { + beforeEach(() => { cy.loginAsViewerUser(); }); it('navigates to apm links on search elastic', () => { - cy.visit('/'); + cy.visitKibana('/'); cy.get('[data-test-subj="nav-search-input"]').type('APM'); cy.contains('APM'); cy.contains('APM / Services'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/dependencies.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/dependencies.spec.ts index 8042a1a07f8a2..e3746489936ab 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/dependencies.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/dependencies.spec.ts @@ -17,8 +17,8 @@ const timeRange = { }; describe.skip('Dependencies', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -26,8 +26,8 @@ describe.skip('Dependencies', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { @@ -36,7 +36,7 @@ describe.skip('Dependencies', () => { describe('top-level dependencies page', () => { it('has a list of dependencies and you can navigate to the page for one', () => { - cy.visit(`/app/apm/services?${new URLSearchParams(timeRange)}`); + cy.visitKibana(`/app/apm/services?${new URLSearchParams(timeRange)}`); cy.contains('nav a', 'Dependencies').click(); // `force: true` because Cypress says the element is 0x0 @@ -46,7 +46,7 @@ describe.skip('Dependencies', () => { }); it('has no detectable a11y violations on load', () => { - cy.visit( + cy.visitKibana( `/app/apm/services/opbeans-java/dependencies?${new URLSearchParams( timeRange )}` @@ -59,7 +59,7 @@ describe.skip('Dependencies', () => { describe.skip('dependency overview page', () => { it('shows dependency information and you can navigate to a page for an upstream service', () => { - cy.visit( + cy.visitKibana( `/app/apm/dependencies/overview?${new URLSearchParams({ ...timeRange, dependencyName: 'postgresql', @@ -76,7 +76,7 @@ describe.skip('Dependencies', () => { }); it('has no detectable a11y violations on load', () => { - cy.visit( + cy.visitKibana( `/app/apm/dependencies/overview?${new URLSearchParams({ ...timeRange, dependencyName: 'postgresql', @@ -90,7 +90,7 @@ describe.skip('Dependencies', () => { describe('service overview page', () => { it('shows dependency information and you can navigate to a page for a dependency', () => { - cy.visit( + cy.visitKibana( `/app/apm/services/opbeans-java/overview?${new URLSearchParams( timeRange )}` @@ -104,7 +104,7 @@ describe.skip('Dependencies', () => { describe('service dependencies tab', () => { it('shows dependency information and you can navigate to a page for a dependency', () => { - cy.visit( + cy.visitKibana( `/app/apm/services/opbeans-java/overview?${new URLSearchParams( timeRange )}` diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/error_details.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/error_details.spec.ts index 59c0d87029517..28b3068503644 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/error_details.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/error_details.spec.ts @@ -27,8 +27,8 @@ describe('Error details', () => { }); describe('when data is loaded', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( generateData({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -36,12 +36,12 @@ describe('Error details', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); it('has no detectable a11y violations on load', () => { - cy.visit(errorDetailsPageHref); + cy.visitKibana(errorDetailsPageHref); cy.contains('Error group 00000'); // set skipFailures to true to not fail the test when there are accessibility failures checkA11y({ skipFailures: true }); @@ -49,7 +49,7 @@ describe('Error details', () => { describe('when error has no occurrences', () => { it('shows an empty message', () => { - cy.visit( + cy.visitKibana( url.format({ pathname: '/app/apm/services/opbeans-java/errors/0000000000000000000000000Error%201', @@ -66,13 +66,13 @@ describe('Error details', () => { describe('when error has data', () => { it('shows errors distribution chart', () => { - cy.visit(errorDetailsPageHref); + cy.visitKibana(errorDetailsPageHref); cy.contains('Error group 00000'); cy.get('[data-test-subj="errorDistribution"]').contains('Occurrences'); }); it('shows top erroneous transactions table', () => { - cy.visit(errorDetailsPageHref); + cy.visitKibana(errorDetailsPageHref); cy.contains('Top 5 affected transactions'); cy.get('[data-test-subj="topErroneousTransactionsTable"]') .contains('a', 'GET /apple 🍎') @@ -81,14 +81,14 @@ describe('Error details', () => { }); it('shows a Stacktrace and Metadata tabs', () => { - cy.visit(errorDetailsPageHref); + cy.visitKibana(errorDetailsPageHref); cy.contains('button', 'Exception stack trace'); cy.contains('button', 'Metadata'); }); describe('when clicking on related transaction sample', () => { it('should redirects to the transaction details page', () => { - cy.visit(errorDetailsPageHref); + cy.visitKibana(errorDetailsPageHref); cy.contains('Error group 00000'); cy.contains('a', 'GET /apple 🍎').click(); cy.url().should('include', 'opbeans-java/transactions/view'); @@ -97,7 +97,7 @@ describe('Error details', () => { describe('when clicking on View x occurences in discover', () => { it.skip('should redirects the user to discover', () => { - cy.visit(errorDetailsPageHref); + cy.visitKibana(errorDetailsPageHref); cy.contains('View 1 occurrence in Discover').click(); cy.url().should('include', 'app/discover'); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/errors_page.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/errors_page.spec.ts index b000a3a8c2f3f..301b3384ee2eb 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/errors_page.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/errors/errors_page.spec.ts @@ -29,8 +29,8 @@ describe('Errors page', () => { }); describe('when data is loaded', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( generateData({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -38,12 +38,12 @@ describe('Errors page', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); it('has no detectable a11y violations on load', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.contains('Error occurrences'); // set skipFailures to true to not fail the test when there are accessibility failures checkA11y({ skipFailures: true }); @@ -51,7 +51,7 @@ describe('Errors page', () => { describe('when service has no errors', () => { it('shows empty message', () => { - cy.visit(nodeServiceErrorsPageHref); + cy.visitKibana(nodeServiceErrorsPageHref); cy.contains('opbeans-node'); cy.contains('No errors found'); }); @@ -59,28 +59,28 @@ describe('Errors page', () => { describe('when service has errors', () => { it('shows errors distribution chart', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.contains('Error occurrences'); }); it('shows failed transaction rate chart', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.contains('Failed transaction rate'); }); it('errors table is populated', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.contains('Error 0'); }); it('clicking on an error in the list navigates to error detail page', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.contains('a', 'Error 1').click(); cy.contains('div', 'Error 1'); }); it('clicking on type adds a filter in the kuerybar', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.get('[data-test-subj="headerFilterKuerybar"]') .invoke('val') .should('be.empty'); @@ -97,13 +97,13 @@ describe('Errors page', () => { }); it('sorts by ocurrences', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.contains('span', 'Occurrences').click(); cy.url().should('include', '&sortField=occurrences&sortDirection=asc'); }); it('sorts by latest occurrences', () => { - cy.visit(javaServiceErrorsPageHref); + cy.visitKibana(javaServiceErrorsPageHref); cy.contains('span', 'Last seen').click(); cy.url().should('include', '&sortField=lastSeen&sortDirection=asc'); }); @@ -112,9 +112,8 @@ describe('Errors page', () => { }); describe('Check detailed statistics API with multiple errors', () => { - before(async () => { - cy.loginAsViewerUser(); - await synthtrace.index( + before(() => { + synthtrace.index( generateErrors({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -123,8 +122,12 @@ describe('Check detailed statistics API with multiple errors', () => { ); }); - after(async () => { - await synthtrace.clean(); + beforeEach(() => { + cy.loginAsViewerUser(); + }); + + after(() => { + synthtrace.clean(); }); it('calls detailed API with visible items only', () => { @@ -136,7 +139,7 @@ describe('Check detailed statistics API with multiple errors', () => { 'POST', '/internal/apm/services/opbeans-java/errors/groups/detailed_statistics?*' ).as('errorsDetailedStatistics'); - cy.visit(`${javaServiceErrorsPageHref}&pageSize=10`); + cy.visitKibana(`${javaServiceErrorsPageHref}&pageSize=10`); cy.wait('@errorsMainStatistics'); cy.get('.euiPagination__list').children().should('have.length', 5); cy.wait('@errorsDetailedStatistics').then((payload) => { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts index 42ca9319b4ea3..be09ae3f06122 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/home.spec.ts @@ -24,8 +24,8 @@ const serviceInventoryHref = url.format({ }); describe.skip('Home page', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -33,8 +33,8 @@ describe.skip('Home page', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { @@ -42,7 +42,7 @@ describe.skip('Home page', () => { }); it('Redirects to service page with comparisonEnabled, environment, rangeFrom, rangeTo and offset added to the URL', () => { - cy.visit('/app/apm'); + cy.visitKibana('/app/apm'); cy.url().should( 'include', @@ -51,7 +51,7 @@ describe.skip('Home page', () => { }); it('includes services with only metric documents', () => { - cy.visit( + cy.visitKibana( `${serviceInventoryHref}&kuery=not%20(processor.event%3A%22transaction%22)` ); cy.contains('opbeans-java'); @@ -60,7 +60,7 @@ describe.skip('Home page', () => { describe('navigations', () => { it('navigates to service overview page with transaction type', () => { - cy.visit(serviceInventoryHref); + cy.visitKibana(serviceInventoryHref); cy.contains('Services'); cy.contains('opbeans-rum').click({ force: true }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/header_filters/header_filters.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/header_filters/header_filters.spec.ts index 03972eb0d0f20..c4e87ac15fbe1 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/header_filters/header_filters.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/header_filters/header_filters.spec.ts @@ -20,8 +20,8 @@ const specialServiceName = 'service 1 / ? # [ ] @ ! $ & ( ) * + , ; = < > % {} | ^ ` <>'; describe('Service inventory - header filters', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( generateData({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -30,8 +30,8 @@ describe('Service inventory - header filters', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { @@ -40,7 +40,7 @@ describe('Service inventory - header filters', () => { describe('Filtering by kuerybar', () => { it('filters by service.name with special characters', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('Services'); cy.contains('opbeans-node'); cy.contains('service 1'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts index 6575d015abde2..5b98284cdf52a 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_inventory/service_inventory.spec.ts @@ -44,12 +44,9 @@ const mainAliasNames = mainApiRequestsToIntercept.map( ); describe('When navigating to the service inventory', () => { - before(async () => { - cy.loginAsViewerUser(); - cy.visit(serviceInventoryHref); - + before(() => { const { rangeFrom, rangeTo } = timeRange; - await synthtrace.index( + synthtrace.index( opbeans({ from: new Date(rangeFrom).getTime(), to: new Date(rangeTo).getTime(), @@ -57,8 +54,13 @@ describe('When navigating to the service inventory', () => { ); }); - after(async () => { - await synthtrace.clean(); + beforeEach(() => { + cy.loginAsViewerUser(); + cy.visitKibana(serviceInventoryHref); + }); + + after(() => { + synthtrace.clean(); }); it('has no detectable a11y violations on load', () => { @@ -92,7 +94,7 @@ describe('When navigating to the service inventory', () => { ); cy.loginAsViewerUser(); - cy.visit(serviceInventoryHref); + cy.visitKibana(serviceInventoryHref); }); it('with the correct environment when changing the environment', () => { @@ -135,11 +137,9 @@ describe('When navigating to the service inventory', () => { }); describe('Check detailed statistics API with multiple services', () => { - before(async () => { - cy.loginAsViewerUser(); + before(() => { const { rangeFrom, rangeTo } = timeRange; - - await synthtrace.index( + synthtrace.index( generateMultipleServicesData({ from: new Date(rangeFrom).getTime(), to: new Date(rangeTo).getTime(), @@ -147,8 +147,12 @@ describe('Check detailed statistics API with multiple services', () => { ); }); - after(async () => { - await synthtrace.clean(); + beforeEach(() => { + cy.loginAsViewerUser(); + }); + + after(() => { + synthtrace.clean(); }); it('calls detailed API with visible items only', () => { @@ -157,7 +161,7 @@ describe('Check detailed statistics API with multiple services', () => { ); cy.intercept('GET', '/internal/apm/services?*').as('mainStatisticsRequest'); - cy.visit( + cy.visitKibana( `${serviceInventoryHref}&pageSize=10&sortField=serviceName&sortDirection=asc` ); cy.wait('@mainStatisticsRequest'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/aws_lambda/aws_lamba.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/aws_lambda/aws_lamba.spec.ts index a2674d056e317..a70620ee18f82 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/aws_lambda/aws_lamba.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/aws_lambda/aws_lamba.spec.ts @@ -23,8 +23,8 @@ const apiToIntercept = { }; describe('Service overview - aws lambda', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( generateData({ start: new Date(start).getTime(), end: new Date(end).getTime(), @@ -32,19 +32,16 @@ describe('Service overview - aws lambda', () => { ); }); - after(async () => { - await synthtrace.clean(); - }); - - beforeEach(() => { - cy.loginAsViewerUser(); + after(() => { + synthtrace.clean(); }); it('displays a cold start rate chart and not a transaction breakdown chart', () => { const { endpoint, name } = apiToIntercept; - cy.intercept('GET', endpoint).as(name); - cy.visit(serviceOverviewHref); + + cy.loginAsViewerUser(); + cy.visitKibana(serviceOverviewHref); cy.wait(`@${name}`); cy.contains('Cold start rate'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/errors_table.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/errors_table.spec.ts index 8d7cfd4e65288..b175eb0430ed4 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/errors_table.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/errors_table.spec.ts @@ -18,8 +18,8 @@ const serviceOverviewHref = url.format({ }); describe('Errors table', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -27,8 +27,8 @@ describe('Errors table', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { @@ -36,20 +36,20 @@ describe('Errors table', () => { }); it('errors table is populated', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); cy.contains('[MockError] Foo'); }); it('navigates to the errors page', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); cy.contains('a', 'View errors').click(); cy.url().should('include', '/opbeans-java/errors'); }); it('clicking on type adds a filter in the kuerybar and navigates to errors page', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.get('[data-test-subj="headerFilterKuerybar"]') .invoke('val') .should('be.empty'); @@ -64,7 +64,7 @@ describe('Errors table', () => { }); it('navigates to error detail page', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('a', '[MockError] Foo').click(); cy.contains('div', 'Exception message'); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts index 3b7b0c87a7f84..cf5102ee6e37e 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/header_filters.spec.ts @@ -59,14 +59,14 @@ const apisToIntercept = [ ]; describe('Service overview - header filters', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime() }) ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); describe('Filtering by transaction type', () => { @@ -74,7 +74,7 @@ describe('Service overview - header filters', () => { cy.loginAsViewerUser(); }); it('changes url when selecting different value', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-node'); cy.url().should('not.include', 'transactionType'); cy.get('[data-test-subj="headerFilterTransactionType"]').should( @@ -93,7 +93,7 @@ describe('Service overview - header filters', () => { apisToIntercept.map(({ endpoint, name }) => { cy.intercept('GET', endpoint).as(name); }); - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.get('[data-test-subj="headerFilterTransactionType"]').should( 'have.value', 'request' @@ -122,7 +122,7 @@ describe('Service overview - header filters', () => { cy.loginAsViewerUser(); }); it('filters by transaction.name', () => { - cy.visit( + cy.visitKibana( url.format({ pathname: '/app/apm/services/opbeans-java/overview', query: { rangeFrom: start, rangeTo: end }, diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts index 1fc83b3e2eb0a..c3b5f37c32acc 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/instances_table.spec.ts @@ -41,19 +41,19 @@ describe('Instances table', () => { cy.loginAsViewerUser(); }); - // describe('when data is not loaded', () => { - // it('shows empty message', () => { - // cy.visit(serviceOverviewHref); - // cy.contains('opbeans-java'); - // cy.get('[data-test-subj="serviceInstancesTableContainer"]').contains( - // 'No items found' - // ); - // }); - // }); + describe.skip('when data is not loaded', () => { + it('shows empty message', () => { + cy.visitKibana(serviceOverviewHref); + cy.contains('opbeans-java'); + cy.get('[data-test-subj="serviceInstancesTableContainer"]').contains( + 'No items found' + ); + }); + }); describe('when data is loaded', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -61,12 +61,12 @@ describe('Instances table', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); it('has data in the table', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); cy.contains(serviceNodeName); }); @@ -75,7 +75,7 @@ describe('Instances table', () => { cy.intercept('GET', endpoint).as(name); }); - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); cy.wait('@instancesMainRequest'); @@ -96,7 +96,7 @@ describe('Instances table', () => { cy.intercept('GET', endpoint).as(name); }); - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); cy.wait('@instancesMainRequest'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts index f61ad0c0761c6..d73713290b4ef 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/service_overview.spec.ts @@ -86,8 +86,8 @@ const aliasNamesWithComparison = apiRequestsToInterceptWithComparison.map( const aliasNames = [...aliasNamesNoComparison, ...aliasNamesWithComparison]; describe('Service Overview', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -95,14 +95,14 @@ describe('Service Overview', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); describe('renders', () => { - before(() => { + beforeEach(() => { cy.loginAsViewerUser(); - cy.visit(baseUrl); + cy.visitKibana(baseUrl); }); it('renders all components on the page', () => { @@ -122,7 +122,6 @@ describe('Service Overview', () => { describe('transactions', () => { beforeEach(() => { cy.loginAsViewerUser(); - cy.visit(baseUrl); }); it('persists transaction type selected when clicking on Transactions tab', () => { @@ -130,6 +129,9 @@ describe('Service Overview', () => { 'GET', '/internal/apm/services/opbeans-node/transaction_types?*' ).as('transactionTypesRequest'); + + cy.visitKibana(baseUrl); + cy.wait('@transactionTypesRequest'); cy.get('[data-test-subj="headerFilterTransactionType"]').should( @@ -148,11 +150,14 @@ describe('Service Overview', () => { ); }); - it.skip('persists transaction type selected when clicking on View Transactions link', () => { + it('persists transaction type selected when clicking on View Transactions link', () => { cy.intercept( 'GET', '/internal/apm/services/opbeans-node/transaction_types?*' ).as('transactionTypesRequest'); + + cy.visitKibana(baseUrl); + cy.wait('@transactionTypesRequest'); cy.get('[data-test-subj="headerFilterTransactionType"]').should( 'have.value', @@ -173,20 +178,20 @@ describe('Service Overview', () => { }); describe('when RUM service', () => { - before(() => { + it('hides dependency tab when RUM service', () => { cy.loginAsViewerUser(); - cy.visit( + + cy.intercept('GET', '/internal/apm/services/opbeans-rum/agent?*').as( + 'agentRequest' + ); + + cy.visitKibana( url.format({ pathname: '/app/apm/services/opbeans-rum/overview', query: { rangeFrom: start, rangeTo: end }, }) ); - }); - it('hides dependency tab when RUM service', () => { - cy.intercept('GET', '/internal/apm/services/opbeans-rum/agent?*').as( - 'agentRequest' - ); cy.contains('Overview'); cy.contains('Transactions'); cy.contains('Error'); @@ -204,17 +209,18 @@ describe('Service Overview', () => { describe('Calls APIs', () => { beforeEach(() => { cy.loginAsViewerUser(); - cy.visit(baseUrl); + apiRequestsToIntercept.map(({ endpoint, aliasName }) => { cy.intercept('GET', endpoint).as(aliasName); }); apiRequestsToInterceptWithComparison.map(({ endpoint, aliasName }) => { cy.intercept('GET', endpoint).as(aliasName); }); + cy.visitKibana(baseUrl); }); it.skip('with the correct environment when changing the environment', () => { - cy.wait(aliasNames, { requestTimeout: 10000 }); + cy.wait(aliasNames); cy.intercept('GET', 'internal/apm/suggestions?*').as( 'suggestionsRequest' @@ -241,11 +247,11 @@ describe('Service Overview', () => { it('when clicking the refresh button', () => { cy.contains('Refresh').click(); - cy.wait(aliasNames, { requestTimeout: 10000 }); + cy.wait(aliasNames); }); it.skip('when selecting a different time range and clicking the update button', () => { - cy.wait(aliasNames, { requestTimeout: 10000 }); + cy.wait(aliasNames); const timeStart = moment(start).subtract(5, 'm').toISOString(); const timeEnd = moment(end).subtract(5, 'm').toISOString(); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts index 25591cd358bd5..611455163eca3 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/service_overview/time_comparison.spec.ts @@ -51,8 +51,8 @@ const apisToIntercept = [ ]; describe.skip('Service overview: Time Comparison', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -60,8 +60,8 @@ describe.skip('Service overview: Time Comparison', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { @@ -69,14 +69,14 @@ describe.skip('Service overview: Time Comparison', () => { }); it('enables by default the time comparison feature with Last 24 hours selected', () => { - cy.visit(serviceOverviewPath); + cy.visitKibana(serviceOverviewPath); cy.url().should('include', 'comparisonEnabled=true'); cy.url().should('include', 'offset=1d'); }); describe('when comparison is toggled off', () => { it('disables select box', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); // Comparison is enabled by default @@ -91,7 +91,7 @@ describe.skip('Service overview: Time Comparison', () => { apisToIntercept.map(({ endpoint, name }) => { cy.intercept('GET', endpoint).as(name); }); - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.get('[data-test-subj="comparisonSelect"]').should('be.enabled'); const offset = `offset=1d`; @@ -125,7 +125,7 @@ describe.skip('Service overview: Time Comparison', () => { apisToIntercept.map(({ endpoint, name }) => { cy.intercept('GET', endpoint).as(name); }); - cy.visit(serviceOverviewPath); + cy.visitKibana(serviceOverviewPath); cy.contains('opbeans-java'); // opens the page with "Day before" selected cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d'); @@ -136,7 +136,7 @@ describe.skip('Service overview: Time Comparison', () => { }); it('changes comparison type when a new time range is selected', () => { - cy.visit(serviceOverviewHref); + cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); // Time comparison default value cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d'); @@ -189,7 +189,7 @@ describe.skip('Service overview: Time Comparison', () => { apisToIntercept.map(({ endpoint, name }) => { cy.intercept('GET', endpoint).as(name); }); - cy.visit( + cy.visitKibana( url.format({ pathname: serviceOverviewPath, query: { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/generate_span_links_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/generate_span_links_data.ts index 0ced34d8a1b7c..9fd2cfe6eab0b 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/generate_span_links_data.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/generate_span_links_data.ts @@ -296,7 +296,7 @@ function getConsumerMultiple({ * ----Span E * ------span.links= producer-external-only / Span B | producer-consumer / Transaction C */ -export async function generateSpanLinksData() { +export function generateSpanLinksData() { const producerInternalOnly = getProducerInternalOnly(); const producerExternalOnly = getProducerExternalOnly(); const producerConsumer = getProducerConsumer({ @@ -309,7 +309,7 @@ export async function generateSpanLinksData() { producerExternalOnlySpanBSpanLink: producerExternalOnly.spanBSpanLink, }); - await synthtrace.index( + synthtrace.index( new EntityArrayIterable(producerInternalOnly.apmFields).merge( new EntityArrayIterable(producerExternalOnly.apmFields), new EntityArrayIterable(producerConsumer.apmFields), diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/span_links.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/span_links.spec.ts index 3dff8f075f187..cddba048e8a18 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/span_links.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/span_links.spec.ts @@ -35,17 +35,17 @@ describe('Span links', () => { describe('when data is loaded', () => { let ids: Awaited>; - before(async () => { - ids = await generateSpanLinksData(); + before(() => { + ids = generateSpanLinksData(); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); describe('span links count on trace waterfall', () => { it('Shows two children and no parents on producer-internal-only Span A', () => { - cy.visit( + cy.visitKibana( getServiceInventoryUrl({ serviceName: 'producer-internal-only' }) ); cy.contains('Transaction A').click(); @@ -59,7 +59,7 @@ describe('Span links', () => { }); it('Shows one parent and one children on producer-external-only Span B', () => { - cy.visit( + cy.visitKibana( getServiceInventoryUrl({ serviceName: 'producer-external-only' }) ); cy.contains('Transaction B').click(); @@ -73,7 +73,9 @@ describe('Span links', () => { }); it('Shows one parent and one children on producer-consumer Transaction C', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'producer-consumer' }) + ); cy.contains('Transaction C').click(); cy.contains('2 Span links'); cy.get( @@ -85,7 +87,9 @@ describe('Span links', () => { }); it('Shows no parent and one children on producer-consumer Span C', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'producer-consumer' }) + ); cy.contains('Transaction C').click(); cy.contains('1 Span link'); cy.get( @@ -97,7 +101,9 @@ describe('Span links', () => { }); it('Shows two parents and one children on consumer-multiple Transaction D', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'consumer-multiple' }) + ); cy.contains('Transaction D').click(); cy.contains('2 Span links'); cy.get( @@ -109,7 +115,9 @@ describe('Span links', () => { }); it('Shows two parents and one children on consumer-multiple Span E', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'consumer-multiple' }) + ); cy.contains('Transaction D').click(); cy.contains('2 Span links'); cy.get( @@ -123,7 +131,7 @@ describe('Span links', () => { describe('span link flyout', () => { it('Shows children details on producer-internal-only Span A', () => { - cy.visit( + cy.visitKibana( getServiceInventoryUrl({ serviceName: 'producer-internal-only' }) ); cy.contains('Transaction A').click(); @@ -154,7 +162,7 @@ describe('Span links', () => { }); it('Shows children and parents details on producer-external-only Span B', () => { - cy.visit( + cy.visitKibana( getServiceInventoryUrl({ serviceName: 'producer-external-only' }) ); cy.contains('Transaction B').click(); @@ -178,7 +186,9 @@ describe('Span links', () => { }); it('Shows children and parents details on producer-consumer Transaction C', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'producer-consumer' }) + ); cy.contains('Transaction C').click(); cy.get( `[aria-controls="${ids.producerConsumerIds.transactionCId}"]` @@ -210,7 +220,9 @@ describe('Span links', () => { }); it('Shows children and parents details on producer-consumer Span C', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'producer-consumer' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'producer-consumer' }) + ); cy.contains('Transaction C').click(); cy.contains('Span C').click(); cy.get('[data-test-subj="spanLinksTab"]').click(); @@ -232,7 +244,9 @@ describe('Span links', () => { }); it('Shows children and parents details on consumer-multiple Transaction D', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'consumer-multiple' }) + ); cy.contains('Transaction D').click(); cy.get( `[aria-controls="${ids.producerMultipleIds.transactionDId}"]` @@ -266,7 +280,9 @@ describe('Span links', () => { }); it('Shows children and parents details on consumer-multiple Span E', () => { - cy.visit(getServiceInventoryUrl({ serviceName: 'consumer-multiple' })); + cy.visitKibana( + getServiceInventoryUrl({ serviceName: 'consumer-multiple' }) + ); cy.contains('Transaction D').click(); cy.contains('Span E').click(); cy.get('[data-test-subj="spanLinksTab"]').click(); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/transaction_details.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/transaction_details.spec.ts index c5eeda6645ce8..ee2aade9ec1df 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/transaction_details.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transaction_details/transaction_details.spec.ts @@ -17,8 +17,8 @@ const timeRange = { }; describe('Transaction details', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -26,13 +26,13 @@ describe('Transaction details', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { cy.loginAsViewerUser(); - cy.visit( + cy.visitKibana( `/app/apm/services/opbeans-java/transactions/view?${new URLSearchParams({ ...timeRange, transactionName: 'GET /api/product', diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transactions_overview/transactions_overview.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transactions_overview/transactions_overview.spec.ts index 671b35741f91b..83753b7fe2595 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transactions_overview/transactions_overview.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/transactions_overview/transactions_overview.spec.ts @@ -19,8 +19,8 @@ const serviceTransactionsHref = url.format({ }); describe('Transactions Overview', () => { - before(async () => { - await synthtrace.index( + before(() => { + synthtrace.index( opbeans({ from: new Date(start).getTime(), to: new Date(end).getTime(), @@ -28,8 +28,8 @@ describe('Transactions Overview', () => { ); }); - after(async () => { - await synthtrace.clean(); + after(() => { + synthtrace.clean(); }); beforeEach(() => { @@ -37,7 +37,7 @@ describe('Transactions Overview', () => { }); it('has no detectable a11y violations on load', () => { - cy.visit(serviceTransactionsHref); + cy.visitKibana(serviceTransactionsHref); cy.get('a:contains(Transactions)').should( 'have.attr', 'aria-selected', @@ -48,7 +48,7 @@ describe('Transactions Overview', () => { }); it('persists transaction type selected when navigating to Overview tab', () => { - cy.visit(serviceTransactionsHref); + cy.visitKibana(serviceTransactionsHref); cy.get('[data-test-subj="headerFilterTransactionType"]').should( 'have.value', 'request' diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/tutorial/tutorial.spec.ts b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/tutorial/tutorial.spec.ts index e2ebe9c2bdda8..cb8d9218b4ec1 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/tutorial/tutorial.spec.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/integration/read_only_user/tutorial/tutorial.spec.ts @@ -6,9 +6,9 @@ */ describe('APM tutorial', () => { - before(() => { + beforeEach(() => { cy.loginAsViewerUser(); - cy.visit('/app/home#/tutorial/apm'); + cy.visitKibana('/app/home#/tutorial/apm'); }); it('includes section for APM Server', () => { 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 0559b07b1cbf2..37182e328ebf3 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts @@ -21,21 +21,24 @@ Cypress.Commands.add('loginAsEditorUser', () => { Cypress.Commands.add( 'loginAs', ({ username, password }: { username: string; password: string }) => { - cy.log(`Logging in as ${username}`); - const kibanaUrl = Cypress.env('KIBANA_URL'); - return cy.request({ - log: false, - method: 'POST', - url: `${kibanaUrl}/internal/security/login`, - body: { - providerType: 'basic', - providerName: 'basic', - currentURL: `${kibanaUrl}/login`, - params: { username, password }, - }, - headers: { - 'kbn-xsrf': 'e2e_test', - }, + cy.log(`Calling 'loginAs'`); + cy.session([username, password], () => { + cy.log(`Logging in as ${username}`); + const kibanaUrl = Cypress.env('KIBANA_URL'); + cy.request({ + log: false, + method: 'POST', + url: `${kibanaUrl}/internal/security/login`, + body: { + providerType: 'basic', + providerName: 'basic', + currentURL: `${kibanaUrl}/login`, + params: { username, password }, + }, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + }); }); } ); @@ -45,6 +48,14 @@ Cypress.Commands.add('changeTimeRange', (value: string) => { cy.contains(value).click(); }); +Cypress.Commands.add('visitKibana', (url: string) => { + cy.visit(url); + cy.get('[data-test-subj="kbnLoadingMessage"]').should('exist'); + cy.get('[data-test-subj="kbnLoadingMessage"]').should('not.exist', { + timeout: 50000, + }); +}); + Cypress.Commands.add( 'selectAbsoluteTimeRange', (start: string, end: string) => { @@ -96,6 +107,7 @@ Cypress.Commands.add( headers: { 'kbn-xsrf': 'e2e_test', }, + auth: { user: 'editor', pass: 'changeme' }, }); } ); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts index f46a54142de0e..27720210b668a 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts @@ -14,6 +14,7 @@ declare namespace Cypress { password: string; }): Cypress.Chainable>; changeTimeRange(value: string): void; + visitKibana(url: string): void; selectAbsoluteTimeRange(start: string, end: string): void; expectAPIsToHaveBeenCalledWith(params: { apisIntercepted: string[]; diff --git a/x-pack/plugins/apm/ftr_e2e/synthtrace.ts b/x-pack/plugins/apm/ftr_e2e/synthtrace.ts index 6fb880c40b0cc..a421edea04a6e 100644 --- a/x-pack/plugins/apm/ftr_e2e/synthtrace.ts +++ b/x-pack/plugins/apm/ftr_e2e/synthtrace.ts @@ -8,11 +8,6 @@ import type { EntityIterable } from '@kbn/apm-synthtrace'; export const synthtrace = { index: (events: EntityIterable) => - new Promise((resolve) => { - cy.task('synthtrace:index', events.toArray()).then(resolve); - }), - clean: () => - new Promise((resolve) => { - cy.task('synthtrace:clean').then(resolve); - }), + cy.task('synthtrace:index', events.toArray()), + clean: () => cy.task('synthtrace:clean'), }; From f2c20b7c9f2f0dfdce6009e1662ed74cef6ebca4 Mon Sep 17 00:00:00 2001 From: Lee Drengenberg Date: Tue, 23 Aug 2022 14:31:39 -0500 Subject: [PATCH 37/41] [Archive Migration] batch 2 of removing es_archives/empty_kibana (#138208) * replace es_archives/empty_kibana with kibanaServer.savedObjects.cleanStandardList * [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' * add missing kibanaServer * add a tearDown * revert changes that don't pass * revert fleet_setup, delete spaces in tearDown * Don't fail on deleting spaces * revert file for failing test Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../security_and_spaces/setup.ts | 6 ++++-- .../apis/metrics_ui/log_entry_highlights.ts | 5 +++-- x-pack/test/api_integration/apis/metrics_ui/sources.ts | 5 +++-- x-pack/test/api_integration/apis/ml/modules/index.ts | 8 ++++---- x-pack/test/api_integration/apis/osquery/packs.ts | 4 ++-- .../apis/security_solution/saved_objects/notes.ts | 6 +++--- .../security_solution/saved_objects/pinned_events.ts | 6 +++--- .../apis/security_solution/saved_objects/timeline.ts | 6 +++--- x-pack/test/common/services/spaces.ts | 10 +++++----- .../apis/agent_policy/agent_policy.ts | 4 ++-- .../apis/download_sources/crud.ts | 5 +++-- .../apis/epm/install_error_rollback.ts | 6 +++--- .../test/fleet_api_integration/apis/fleet_telemetry.ts | 5 +++-- x-pack/test/fleet_api_integration/apis/outputs/crud.ts | 5 +++-- .../apis/package_policy/create.ts | 5 +++-- .../fleet_api_integration/apis/package_policy/get.ts | 5 +++-- .../apis/package_policy/upgrade.ts | 5 +++-- .../apis/preconfiguration/preconfiguration.ts | 5 +++-- .../test/fleet_api_integration/apis/service_tokens.ts | 6 +++--- .../with_host_configured/app_search/engines.ts | 8 +++----- .../without_host_configured/app_search/setup_guide.ts | 9 +++++---- .../workplace_search/setup_guide.ts | 9 +++++---- .../test_suites/event_log/public_api_integration.ts | 3 ++- .../reporting_without_security/management.ts | 5 ++--- .../apps/endpoint/endpoint_telemetry.ts | 5 +++-- x-pack/test/visual_regression/tests/login_page.ts | 6 +++--- 26 files changed, 82 insertions(+), 70 deletions(-) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/setup.ts b/x-pack/test/alerting_api_integration/security_and_spaces/setup.ts index 69ca58e1edc12..74dcdc3989e2a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/setup.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/setup.ts @@ -39,7 +39,7 @@ export async function setupSpacesAndUsers(getService: FtrProviderContext['getSer export async function tearDown(getService: FtrProviderContext['getService']) { const securityService = getService('security'); - const esArchiver = getService('esArchiver'); + const spacesService = getService('spaces'); for (const user of Users) { await securityService.user.delete(user.username); @@ -52,5 +52,7 @@ export async function tearDown(getService: FtrProviderContext['getService']) { } } - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + for (const space of Spaces) { + await spacesService.delete(space.id); + } } diff --git a/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts b/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts index bd9a9a0e7c480..aba182274c9a3 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/log_entry_highlights.ts @@ -37,6 +37,7 @@ const COMMON_HEADERS = { export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + const kibanaServer = getService('kibanaServer'); describe('log highlight apis', () => { before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/simple_logs')); @@ -44,8 +45,8 @@ export default function ({ getService }: FtrProviderContext) { describe('/log_entries/highlights', () => { describe('with the default source', () => { - before(() => esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana')); + before(() => kibanaServer.savedObjects.cleanStandardList()); + after(() => kibanaServer.savedObjects.cleanStandardList()); it('Handles empty responses', async () => { const { body } = await supertest diff --git a/x-pack/test/api_integration/apis/metrics_ui/sources.ts b/x-pack/test/api_integration/apis/metrics_ui/sources.ts index 0ba6f49634b54..c58b332c7102f 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/sources.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/sources.ts @@ -18,6 +18,7 @@ export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); const SOURCE_API_URL = '/api/metrics/source/default'; + const kibanaServer = getService('kibanaServer'); const patchRequest = async ( body: PartialMetricsSourceConfigurationProperties ): Promise => { @@ -32,8 +33,8 @@ export default function ({ getService }: FtrProviderContext) { describe('sources', () => { before(() => esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs')); after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')); - beforeEach(() => esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); - afterEach(() => esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana')); + before(() => kibanaServer.savedObjects.cleanStandardList()); + after(() => kibanaServer.savedObjects.cleanStandardList()); describe('patch request', () => { it('applies all top-level field updates to an existing source', async () => { diff --git a/x-pack/test/api_integration/apis/ml/modules/index.ts b/x-pack/test/api_integration/apis/ml/modules/index.ts index 182de3e2648cb..de8919976fd33 100644 --- a/x-pack/test/api_integration/apis/ml/modules/index.ts +++ b/x-pack/test/api_integration/apis/ml/modules/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const ml = getService('ml'); const fleetPackages = ['apache', 'nginx']; @@ -16,8 +16,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { describe('modules', function () { before(async () => { - // use empty_kibana to make sure the fleet setup is removed correctly after the tests - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + // use await kibanaServer.savedObjects.cleanStandardList(); to make sure the fleet setup is removed correctly after the tests + await kibanaServer.savedObjects.cleanStandardList(); // Fleet need to be setup to be able to setup packages await ml.testResources.setupFleet(); @@ -32,7 +32,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { for (const fleetPackage of installedPackages) { await ml.testResources.removeFleetPackage(fleetPackage.pkgName, fleetPackage.version); } - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); loadTestFile(require.resolve('./get_module')); diff --git a/x-pack/test/api_integration/apis/osquery/packs.ts b/x-pack/test/api_integration/apis/osquery/packs.ts index 840d5aecaeae0..dc019bffeec6f 100644 --- a/x-pack/test/api_integration/apis/osquery/packs.ts +++ b/x-pack/test/api_integration/apis/osquery/packs.ts @@ -50,13 +50,13 @@ export default function ({ getService }: FtrProviderContext) { let hostedPolicy: Record; let packagePolicyId: string; before(async () => { - await getService('esArchiver').load('x-pack/test/functional/es_archives/empty_kibana'); + await getService('kibanaServer').savedObjects.cleanStandardList(); await getService('esArchiver').load( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); }); after(async () => { - await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); + await getService('kibanaServer').savedObjects.cleanStandardList(); await getService('esArchiver').unload( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); diff --git a/x-pack/test/api_integration/apis/security_solution/saved_objects/notes.ts b/x-pack/test/api_integration/apis/security_solution/saved_objects/notes.ts index 03ea91775d1bf..a6dc1f88c596e 100644 --- a/x-pack/test/api_integration/apis/security_solution/saved_objects/notes.ts +++ b/x-pack/test/api_integration/apis/security_solution/saved_objects/notes.ts @@ -10,12 +10,12 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const supertest = getService('supertest'); describe('Note - Saved Objects', () => { - beforeEach(() => esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); - afterEach(() => esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana')); + before(() => kibanaServer.savedObjects.cleanStandardList()); + after(() => kibanaServer.savedObjects.cleanStandardList()); describe('create a note', () => { it('should return a timelineId, timelineVersion, noteId and version', async () => { diff --git a/x-pack/test/api_integration/apis/security_solution/saved_objects/pinned_events.ts b/x-pack/test/api_integration/apis/security_solution/saved_objects/pinned_events.ts index 8391f2f9ab18a..dcfe8a109b04e 100644 --- a/x-pack/test/api_integration/apis/security_solution/saved_objects/pinned_events.ts +++ b/x-pack/test/api_integration/apis/security_solution/saved_objects/pinned_events.ts @@ -10,12 +10,12 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const supertest = getService('supertest'); describe('Pinned Events - Saved Objects', () => { - beforeEach(() => esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); - afterEach(() => esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana')); + before(() => kibanaServer.savedObjects.cleanStandardList()); + after(() => kibanaServer.savedObjects.cleanStandardList()); describe('Pinned an event', () => { it('return a timelineId, timelineVersion, pinnedEventId and version', async () => { diff --git a/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts b/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts index 32d307ebc22d5..e3a79ba91b29c 100644 --- a/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts +++ b/x-pack/test/api_integration/apis/security_solution/saved_objects/timeline.ts @@ -12,12 +12,12 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; import { createBasicTimeline } from './helpers'; export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const supertest = getService('supertest'); describe('Timeline - Saved Objects', () => { - beforeEach(() => esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); - afterEach(() => esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana')); + beforeEach(() => kibanaServer.savedObjects.cleanStandardList()); + afterEach(() => kibanaServer.savedObjects.cleanStandardList()); describe('Persist a timeline', () => { it('Create a timeline just with a title', async () => { diff --git a/x-pack/test/common/services/spaces.ts b/x-pack/test/common/services/spaces.ts index 24554e151135c..c023d8da26ba5 100644 --- a/x-pack/test/common/services/spaces.ts +++ b/x-pack/test/common/services/spaces.ts @@ -24,7 +24,7 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { return new (class SpacesService { public async create(space: any) { - log.debug('creating space'); + log.debug(`creating space ${space.name}`); const { data, status, statusText } = await axios.post('/api/spaces/space', space); if (status !== 200) { @@ -32,19 +32,19 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { `Expected status code of 200, received ${status} ${statusText}: ${util.inspect(data)}` ); } - log.debug('created space'); + log.debug(`created space ${space}`); } public async delete(spaceId: string) { - log.debug(`deleting space: ${spaceId}`); + log.debug(`deleting space id: ${spaceId}`); const { data, status, statusText } = await axios.delete(`/api/spaces/space/${spaceId}`); if (status !== 204) { - throw new Error( + log.debug( `Expected status code of 204, received ${status} ${statusText}: ${util.inspect(data)}` ); } - log.debug(`deleted space: ${spaceId}`); + log.debug(`deleted space id: ${spaceId}`); } })(); } diff --git a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts index 6641867cadf22..e71c14a8054c8 100644 --- a/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts +++ b/x-pack/test/fleet_api_integration/apis/agent_policy/agent_policy.ts @@ -23,7 +23,7 @@ export default function (providerContext: FtrProviderContext) { let systemPkgVersion: string; before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); setupFleetAndAgents(providerContext); let packagePoliciesToDeleteIds: string[] = []; @@ -41,7 +41,7 @@ export default function (providerContext: FtrProviderContext) { } await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('should work with valid minimum required values', async () => { const { diff --git a/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts b/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts index 4e5d2c60ae932..c48f5602f5b52 100644 --- a/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/download_sources/crud.ts @@ -14,11 +14,12 @@ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); describe('fleet_download_sources_crud', async function () { skipIfNoDockerRegistry(providerContext); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); setupFleetAndAgents(providerContext); @@ -38,7 +39,7 @@ export default function (providerContext: FtrProviderContext) { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts b/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts index 9a49958d31d34..8906a7fa3ea37 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_error_rollback.ts @@ -13,10 +13,10 @@ import { setupFleetAndAgents } from '../agents/services'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); const pkgName = 'error_handling'; const goodPackageVersion = '0.1.0'; const badPackageVersion = '0.2.0'; + const kibanaServer = getService('kibanaServer'); const installPackage = async (pkg: string, version: string) => { await supertest @@ -33,10 +33,10 @@ export default function (providerContext: FtrProviderContext) { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); beforeEach(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); afterEach(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('on a fresh install, it should uninstall a broken package during rollback', async function () { diff --git a/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts b/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts index 88368e784dfa6..d1e7cd8d999c6 100644 --- a/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts +++ b/x-pack/test/fleet_api_integration/apis/fleet_telemetry.ts @@ -14,20 +14,21 @@ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); let agentCount = 0; let pkgVersion: string; describe('fleet_telemetry', () => { skipIfNoDockerRegistry(providerContext); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); setupFleetAndAgents(providerContext); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); if (pkgVersion) { await supertest.delete(`/api/fleet/epm/packages/fleet_server/${pkgVersion}`); diff --git a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts index 43a3707a21963..f48e17a704504 100644 --- a/x-pack/test/fleet_api_integration/apis/outputs/crud.ts +++ b/x-pack/test/fleet_api_integration/apis/outputs/crud.ts @@ -14,11 +14,12 @@ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); describe('fleet_output_crud', async function () { skipIfNoDockerRegistry(providerContext); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); setupFleetAndAgents(providerContext); @@ -37,7 +38,7 @@ export default function (providerContext: FtrProviderContext) { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/create.ts b/x-pack/test/fleet_api_integration/apis/package_policy/create.ts index c16815eee3168..46f716e132246 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/create.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/create.ts @@ -14,6 +14,7 @@ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const es: Client = getService('es'); const supertest = getService('supertest'); + const kibanaServer = getService('kibanaServer'); const getPackagePolicyById = async (id: string) => { const { body } = await supertest.get(`/api/fleet/package_policies/${id}`); @@ -27,13 +28,13 @@ export default function (providerContext: FtrProviderContext) { skipIfNoDockerRegistry(providerContext); let agentPolicyId: string; before(async () => { - await getService('esArchiver').load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await getService('esArchiver').load( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); }); after(async () => { - await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await getService('esArchiver').unload( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/get.ts b/x-pack/test/fleet_api_integration/apis/package_policy/get.ts index ef9eee7542838..dbfb8109a2c19 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/get.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/get.ts @@ -23,7 +23,8 @@ export default function (providerContext: FtrProviderContext) { skipIfNoDockerRegistry(providerContext); before(async () => { - await getService('esArchiver').load('x-pack/test/functional/es_archives/empty_kibana'); + await getService('kibanaServer').savedObjects.cleanStandardList(); + await getService('esArchiver').load( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); @@ -33,7 +34,7 @@ export default function (providerContext: FtrProviderContext) { await getService('esArchiver').unload( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); - await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); + await getService('kibanaServer').savedObjects.cleanStandardList(); }); describe('get by id', async function () { diff --git a/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts b/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts index 6486579f41c73..4a113714dc324 100644 --- a/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts +++ b/x-pack/test/fleet_api_integration/apis/package_policy/upgrade.ts @@ -17,6 +17,7 @@ export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); function withTestPackageVersion(version: string) { before(async function () { @@ -42,12 +43,12 @@ export default function (providerContext: FtrProviderContext) { let packagePolicyId: string; before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); after(async () => { - await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await getService('esArchiver').unload( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); diff --git a/x-pack/test/fleet_api_integration/apis/preconfiguration/preconfiguration.ts b/x-pack/test/fleet_api_integration/apis/preconfiguration/preconfiguration.ts index ee7679d2cef65..83d2913e7aa59 100644 --- a/x-pack/test/fleet_api_integration/apis/preconfiguration/preconfiguration.ts +++ b/x-pack/test/fleet_api_integration/apis/preconfiguration/preconfiguration.ts @@ -21,7 +21,8 @@ export default function (providerContext: FtrProviderContext) { describe('Preconfiguration', async () => { skipIfNoDockerRegistry(providerContext); before(async () => { - await getService('esArchiver').load('x-pack/test/functional/es_archives/empty_kibana'); + await getService('kibanaServer').savedObjects.cleanStandardList(); + await getService('esArchiver').load( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); @@ -31,7 +32,7 @@ export default function (providerContext: FtrProviderContext) { await getService('esArchiver').unload( 'x-pack/test/functional/es_archives/fleet/empty_fleet_server' ); - await getService('esArchiver').unload('x-pack/test/functional/es_archives/empty_kibana'); + await getService('kibanaServer').savedObjects.cleanStandardList(); }); // Basic health check for the API; functionality is covered by the unit tests diff --git a/x-pack/test/fleet_api_integration/apis/service_tokens.ts b/x-pack/test/fleet_api_integration/apis/service_tokens.ts index e668caab8e98f..bd13c3f5b8ca8 100644 --- a/x-pack/test/fleet_api_integration/apis/service_tokens.ts +++ b/x-pack/test/fleet_api_integration/apis/service_tokens.ts @@ -11,16 +11,16 @@ import { FtrProviderContext } from '../../api_integration/ftr_provider_context'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; const supertest = getService('supertest'); - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const esClient = getService('es'); describe('fleet_service_tokens', async () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('POST /api/fleet/service_tokens', () => { diff --git a/x-pack/test/functional_enterprise_search/apps/enterprise_search/with_host_configured/app_search/engines.ts b/x-pack/test/functional_enterprise_search/apps/enterprise_search/with_host_configured/app_search/engines.ts index 142f6af984994..5b10de7b3e036 100644 --- a/x-pack/test/functional_enterprise_search/apps/enterprise_search/with_host_configured/app_search/engines.ts +++ b/x-pack/test/functional_enterprise_search/apps/enterprise_search/with_host_configured/app_search/engines.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import { EsArchiver } from '@kbn/es-archiver'; import { AppSearchService, IEngine } from '../../../../services/app_search_service'; import { Browser } from '../../../../../../../test/functional/services/common'; import { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -15,11 +14,10 @@ export default function enterpriseSearchSetupEnginesTests({ getService, getPageObjects, }: FtrProviderContext) { - const esArchiver = getService('esArchiver') as EsArchiver; const browser = getService('browser') as Browser; const retry = getService('retry'); const appSearch = getService('appSearch') as AppSearchService; - + const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['appSearch', 'security']); describe('Engines Overview', function () { @@ -28,14 +26,14 @@ export default function enterpriseSearchSetupEnginesTests({ let metaEngine: IEngine; before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); engine1 = await appSearch.createEngine(); engine2 = await appSearch.createEngine(); metaEngine = await appSearch.createMetaEngine([engine1.name, engine2.name]); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); appSearch.destroyEngine(engine1.name); appSearch.destroyEngine(engine2.name); appSearch.destroyEngine(metaEngine.name); diff --git a/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/app_search/setup_guide.ts b/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/app_search/setup_guide.ts index e7bec22936d12..2995150d73d07 100644 --- a/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/app_search/setup_guide.ts +++ b/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/app_search/setup_guide.ts @@ -12,16 +12,17 @@ export default function enterpriseSearchSetupGuideTests({ getService, getPageObjects, }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); const browser = getService('browser'); const retry = getService('retry'); - + const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['appSearch']); describe('Setup Guide', function () { - before(async () => await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('when no enterpriseSearch.host is configured', () => { diff --git a/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/workplace_search/setup_guide.ts b/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/workplace_search/setup_guide.ts index e1e78885e6401..0be3156d29c02 100644 --- a/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/workplace_search/setup_guide.ts +++ b/x-pack/test/functional_enterprise_search/apps/enterprise_search/without_host_configured/workplace_search/setup_guide.ts @@ -12,16 +12,17 @@ export default function enterpriseSearchSetupGuideTests({ getService, getPageObjects, }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); const browser = getService('browser'); const retry = getService('retry'); - + const kibanaServer = getService('kibanaServer'); const PageObjects = getPageObjects(['workplaceSearch']); describe('Setup Guide', function () { - before(async () => await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana')); + before(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('when no enterpriseSearch.host is configured', () => { diff --git a/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts b/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts index a7bcdf2ddc52c..961efb82a90d1 100644 --- a/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts +++ b/x-pack/test/plugin_api_integration/test_suites/event_log/public_api_integration.ts @@ -21,6 +21,7 @@ export default function ({ getService }: FtrProviderContext) { const retry = getService('retry'); const spacesService = getService('spaces'); const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); describe('Event Log public API', () => { before(async () => { @@ -32,7 +33,7 @@ export default function ({ getService }: FtrProviderContext) { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); for (const namespace of [undefined, 'namespace-a']) { diff --git a/x-pack/test/reporting_functional/reporting_without_security/management.ts b/x-pack/test/reporting_functional/reporting_without_security/management.ts index 36589d375b0e0..f9444c7e4c729 100644 --- a/x-pack/test/reporting_functional/reporting_without_security/management.ts +++ b/x-pack/test/reporting_functional/reporting_without_security/management.ts @@ -40,7 +40,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const supertest = getService('supertestWithoutAuth'); const kibanaServer = getService('kibanaServer'); const testSubjects = getService('testSubjects'); - const esArchiver = getService('esArchiver'); const reportingApi = getService('reportingAPI'); const ecommerceSOPath = 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json'; @@ -55,12 +54,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Polling for jobs', () => { beforeEach(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.importExport.load(ecommerceSOPath); }); afterEach(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.importExport.unload(ecommerceSOPath); await reportingApi.deleteAllReports(); }); diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_telemetry.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_telemetry.ts index efc87330eb822..3dc4f9fb3f3a4 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_telemetry.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_telemetry.ts @@ -11,17 +11,18 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const telemetryTestResources = getService('telemetryTestResources'); + const kibanaServer = getService('kibanaServer'); // The source of the data for these tests have changed and need to be updated // There are currently tests in the security_solution application being maintained describe.skip('security solution endpoint telemetry', () => { after(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('when no agents are connected', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('reports no endpoints or policies', async () => { diff --git a/x-pack/test/visual_regression/tests/login_page.ts b/x-pack/test/visual_regression/tests/login_page.ts index 34e1132134744..3e2b410024036 100644 --- a/x-pack/test/visual_regression/tests/login_page.ts +++ b/x-pack/test/visual_regression/tests/login_page.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const visualTesting = getService('visualTesting'); const testSubjects = getService('testSubjects'); const retry = getService('retry'); @@ -17,12 +17,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe.skip('Security', () => { describe('Login Page', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); await PageObjects.security.forceLogout(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/empty_kibana'); + await kibanaServer.savedObjects.cleanStandardList(); }); afterEach(async () => { From 239def566c1d254b9d8831a43ded9d569934eb10 Mon Sep 17 00:00:00 2001 From: Catherine Liu Date: Tue, 23 Aug 2022 12:49:35 -0700 Subject: [PATCH 38/41] [Controls] Removes timeslider in favor of new timeslider control (#138931) * Removed timeslider in favor of new timeslider control * Removed time slider import * [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' * Fixed i18n errors Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../time_slider_persistable_state.ts | 47 --- .../common/control_types/time_slider/types.ts | 15 - src/plugins/controls/common/index.ts | 2 - .../storybook_control_factories.ts | 6 - .../time_slider.component.stories.tsx | 196 ---------- .../public/control_types/time_slider/index.ts | 11 - .../time_slider/time_slider.component.scss | 47 --- .../time_slider/time_slider.component.tsx | 343 ------------------ .../control_types/time_slider/time_slider.tsx | 79 ---- .../time_slider_embeddable.test.ts | 300 --------------- .../time_slider/time_slider_embeddable.tsx | 334 ----------------- .../time_slider_embeddable_factory.tsx | 69 ---- .../time_slider/time_slider_reducers.ts | 20 - .../time_slider/time_slider_strings.ts | 46 --- .../public/control_types/time_slider/types.ts | 30 -- src/plugins/controls/public/index.ts | 7 +- src/plugins/controls/public/plugin.ts | 24 -- .../control_group_telemetry.test.ts | 10 +- .../time_slider_embeddable_factory.ts | 22 -- src/plugins/controls/server/plugin.ts | 8 +- .../controls/replace_controls.ts | 47 +-- .../translations/translations/fr-FR.json | 7 - .../translations/translations/ja-JP.json | 7 - .../translations/translations/zh-CN.json | 7 - 24 files changed, 7 insertions(+), 1677 deletions(-) delete mode 100644 src/plugins/controls/common/control_types/time_slider/time_slider_persistable_state.ts delete mode 100644 src/plugins/controls/common/control_types/time_slider/types.ts delete mode 100644 src/plugins/controls/public/control_types/time_slider/__stories__/time_slider.component.stories.tsx delete mode 100644 src/plugins/controls/public/control_types/time_slider/index.ts delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider.component.scss delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider.component.tsx delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider.tsx delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.test.ts delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.tsx delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider_embeddable_factory.tsx delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider_reducers.ts delete mode 100644 src/plugins/controls/public/control_types/time_slider/time_slider_strings.ts delete mode 100644 src/plugins/controls/public/control_types/time_slider/types.ts delete mode 100644 src/plugins/controls/server/control_types/time_slider/time_slider_embeddable_factory.ts diff --git a/src/plugins/controls/common/control_types/time_slider/time_slider_persistable_state.ts b/src/plugins/controls/common/control_types/time_slider/time_slider_persistable_state.ts deleted file mode 100644 index b8b3a5f16b51f..0000000000000 --- a/src/plugins/controls/common/control_types/time_slider/time_slider_persistable_state.ts +++ /dev/null @@ -1,47 +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 { - EmbeddableStateWithType, - EmbeddablePersistableStateService, -} from '@kbn/embeddable-plugin/common'; -import { SavedObjectReference } from '@kbn/core/types'; -import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common'; -import { TimeSliderControlEmbeddableInput } from './types'; - -type TimeSliderInputWithType = Partial & { type: string }; -const dataViewReferenceName = 'timeSliderDataView'; - -export const createTimeSliderInject = (): EmbeddablePersistableStateService['inject'] => { - return (state: EmbeddableStateWithType, references: SavedObjectReference[]) => { - const workingState = { ...state } as EmbeddableStateWithType | TimeSliderInputWithType; - references.forEach((reference) => { - if (reference.name === dataViewReferenceName) { - (workingState as TimeSliderInputWithType).dataViewId = reference.id; - } - }); - return workingState as EmbeddableStateWithType; - }; -}; - -export const createTimeSliderExtract = (): EmbeddablePersistableStateService['extract'] => { - return (state: EmbeddableStateWithType) => { - const workingState = { ...state } as EmbeddableStateWithType | TimeSliderInputWithType; - const references: SavedObjectReference[] = []; - - if ('dataViewId' in workingState) { - references.push({ - name: dataViewReferenceName, - type: DATA_VIEW_SAVED_OBJECT_TYPE, - id: workingState.dataViewId!, - }); - delete workingState.dataViewId; - } - return { state: workingState as EmbeddableStateWithType, references }; - }; -}; diff --git a/src/plugins/controls/common/control_types/time_slider/types.ts b/src/plugins/controls/common/control_types/time_slider/types.ts deleted file mode 100644 index 31272380becde..0000000000000 --- a/src/plugins/controls/common/control_types/time_slider/types.ts +++ /dev/null @@ -1,15 +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 { DataControlInput } from '../../types'; - -export const TIME_SLIDER_CONTROL = 'timeSlider'; - -export interface TimeSliderControlEmbeddableInput extends DataControlInput { - value?: [number | null, number | null]; -} diff --git a/src/plugins/controls/common/index.ts b/src/plugins/controls/common/index.ts index c3361c29232bd..a201553c09ec1 100644 --- a/src/plugins/controls/common/index.ts +++ b/src/plugins/controls/common/index.ts @@ -36,5 +36,3 @@ export { // Control Type exports export { OPTIONS_LIST_CONTROL, type OptionsListEmbeddableInput } from './options_list/types'; export { type RangeSliderEmbeddableInput, RANGE_SLIDER_CONTROL } from './range_slider/types'; - -export { TIME_SLIDER_CONTROL } from './control_types/time_slider/types'; diff --git a/src/plugins/controls/public/__stories__/storybook_control_factories.ts b/src/plugins/controls/public/__stories__/storybook_control_factories.ts index 9b0b41f6393e7..2e27339a9eaf8 100644 --- a/src/plugins/controls/public/__stories__/storybook_control_factories.ts +++ b/src/plugins/controls/public/__stories__/storybook_control_factories.ts @@ -8,7 +8,6 @@ import { OptionsListEmbeddableFactory } from '../options_list'; import { RangeSliderEmbeddableFactory } from '../range_slider'; -import { TimesliderEmbeddableFactory } from '../control_types/time_slider'; import { ControlsService } from '../services/controls'; import { ControlFactory } from '..'; @@ -26,9 +25,4 @@ export const populateStorybookControlFactories = (controlsServiceStub: ControlsS const rangeSliderControlFactory = rangeSliderFactoryStub as unknown as ControlFactory; rangeSliderControlFactory.getDefaultInput = () => ({}); controlsServiceStub.registerControlType(rangeSliderControlFactory); - - const timesliderFactoryStub = new TimesliderEmbeddableFactory(); - const timeSliderControlFactory = timesliderFactoryStub as unknown as ControlFactory; - timeSliderControlFactory.getDefaultInput = () => ({}); - controlsServiceStub.registerControlType(timeSliderControlFactory); }; diff --git a/src/plugins/controls/public/control_types/time_slider/__stories__/time_slider.component.stories.tsx b/src/plugins/controls/public/control_types/time_slider/__stories__/time_slider.component.stories.tsx deleted file mode 100644 index 90ea07dc276bd..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/__stories__/time_slider.component.stories.tsx +++ /dev/null @@ -1,196 +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 React, { FC, useCallback, useState } from 'react'; -import moment from 'moment'; -import { EuiFormControlLayout } from '@elastic/eui'; - -import { TimeSliderProps, TimeSlider } from '../time_slider.component'; - -export default { - title: 'Time Slider', - description: '', -}; - -const TimeSliderWrapper: FC> = (props) => { - const [value, setValue] = useState(props.value); - const onChange = useCallback( - (newValue: [number | null, number | null]) => { - const lowValue = newValue[0]; - const highValue = newValue[1]; - - setValue([lowValue, highValue]); - }, - [setValue] - ); - - return ( -
- - - -
- ); -}; - -const undefinedValue: [null, null] = [null, null]; -const undefinedRange: [undefined, undefined] = [undefined, undefined]; - -export const TimeSliderNoValuesOrRange = () => { - // If range is undefined, that should be inndicate that we are loading the range - return ; -}; - -export const TimeSliderUndefinedRangeNoValue = () => { - // If a range is [undefined, undefined] then it was loaded, but no values were found. - return ; -}; - -export const TimeSliderUndefinedRangeWithValue = () => { - const lastWeek = moment().subtract(7, 'days'); - const now = moment(); - - return ( - - ); -}; - -export const TimeSliderWithRangeAndNoValue = () => { - const lastWeek = moment().subtract(7, 'days'); - const now = moment(); - - return ( - - ); -}; - -export const TimeSliderWithRangeAndLowerValue = () => { - const lastWeek = moment().subtract(7, 'days'); - const now = moment(); - - const threeDays = moment().subtract(3, 'days'); - - return ( - - ); -}; - -export const TimeSliderWithRangeAndUpperValue = () => { - const lastWeek = moment().subtract(7, 'days'); - const now = moment(); - - const threeDays = moment().subtract(3, 'days'); - - return ( - - ); -}; - -export const TimeSliderWithLowRangeOverlap = () => { - const lastWeek = moment().subtract(7, 'days'); - const now = moment(); - - const threeDays = moment().subtract(3, 'days'); - const twoDays = moment().subtract(2, 'days'); - - return ( - - ); -}; - -export const TimeSliderWithLowRangeOverlapAndIgnoredValidation = () => { - const lastWeek = moment().subtract(7, 'days'); - const now = moment(); - - const threeDays = moment().subtract(3, 'days'); - const twoDays = moment().subtract(2, 'days'); - - return ( - - ); -}; - -export const TimeSliderWithRangeLowerThanValue = () => { - const twoWeeksAgo = moment().subtract(14, 'days'); - const lastWeek = moment().subtract(7, 'days'); - - const now = moment(); - const threeDays = moment().subtract(3, 'days'); - - return ( - - ); -}; - -export const TimeSliderWithRangeHigherThanValue = () => { - const twoWeeksAgo = moment().subtract(14, 'days'); - const lastWeek = moment().subtract(7, 'days'); - - const now = moment(); - const threeDays = moment().subtract(3, 'days'); - - return ( - - ); -}; - -export const PartialValueLowerThanRange = () => { - // Selected value is March 8 -> March 9 - // Range is March 11 -> 25 - const eightDaysAgo = moment().subtract(8, 'days'); - - const lastWeek = moment().subtract(7, 'days'); - const today = moment(); - - return ( - - ); -}; - -export const PartialValueHigherThanRange = () => { - // Selected value is March 8 -> March 9 - // Range is March 11 -> 25 - const eightDaysAgo = moment().subtract(8, 'days'); - - const lastWeek = moment().subtract(7, 'days'); - const today = moment(); - - return ( - - ); -}; diff --git a/src/plugins/controls/public/control_types/time_slider/index.ts b/src/plugins/controls/public/control_types/time_slider/index.ts deleted file mode 100644 index 1cd5900164676..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/index.ts +++ /dev/null @@ -1,11 +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. - */ - -export { TimesliderEmbeddableFactory } from './time_slider_embeddable_factory'; -export { type TimeSliderControlEmbeddableInput } from '../../../common/control_types/time_slider/types'; -export {} from '../../../common'; diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider.component.scss b/src/plugins/controls/public/control_types/time_slider/time_slider.component.scss deleted file mode 100644 index 3f8a37ec44d37..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider.component.scss +++ /dev/null @@ -1,47 +0,0 @@ -.timeSlider__anchorOverride { - display:block; - >div { - height: 100%; - } -} - -.timeSlider__popoverOverride { - width: 100%; - max-width: 100%; - height: 100%; -} - -.timeSlider__panelOverride { - min-width: $euiSizeXXL * 15; -} - -.timeSlider__anchor { - text-decoration: none; - width: 100%; - background-color: $euiFormBackgroundColor; - box-shadow: none; - @include euiFormControlSideBorderRadius($euiFormControlBorderRadius, $side: 'right', $internal: true); - overflow: hidden; - height: 100%; - - &:enabled:focus { - background-color: $euiFormBackgroundColor; - } - - .euiText { - background-color: $euiFormBackgroundColor; - } - - .timeSlider__anchorText { - font-weight: $euiFontWeightBold; - } - - .timeSlider__anchorText--default { - color: $euiColorMediumShade; - } - - .timeSlider__anchorText--invalid { - text-decoration: line-through; - color: $euiColorMediumShade; - } -} \ No newline at end of file diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider.component.tsx b/src/plugins/controls/public/control_types/time_slider/time_slider.component.tsx deleted file mode 100644 index 1bb2f90b44121..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider.component.tsx +++ /dev/null @@ -1,343 +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 React, { FC, useState, useMemo, useCallback } from 'react'; -import { isNil } from 'lodash'; -import { - EuiText, - EuiLoadingSpinner, - EuiInputPopover, - EuiPopoverTitle, - EuiSpacer, - EuiFlexItem, - EuiFlexGroup, - EuiToolTip, - EuiButtonIcon, -} from '@elastic/eui'; -import { EuiRangeTick } from '@elastic/eui/src/components/form/range/range_ticks'; -import moment from 'moment-timezone'; -import { calcAutoIntervalNear } from '@kbn/data-plugin/common'; -import { ValidatedDualRange } from '@kbn/kibana-react-plugin/public'; -import { TimeSliderStrings } from './time_slider_strings'; -import './time_slider.component.scss'; - -function getScaledDateFormat(interval: number): string { - if (interval >= moment.duration(1, 'y').asMilliseconds()) { - return 'YYYY'; - } - - if (interval >= moment.duration(1, 'd').asMilliseconds()) { - return 'MMM D'; - } - - if (interval >= moment.duration(6, 'h').asMilliseconds()) { - return 'Do HH'; - } - - if (interval >= moment.duration(1, 'h').asMilliseconds()) { - return 'HH:mm'; - } - - if (interval >= moment.duration(1, 'm').asMilliseconds()) { - return 'HH:mm'; - } - - if (interval >= moment.duration(1, 's').asMilliseconds()) { - return 'mm:ss'; - } - - return 'ss.SSS'; -} - -export function getInterval(min: number, max: number, steps = 6): number { - const duration = max - min; - let interval = calcAutoIntervalNear(steps, duration).asMilliseconds(); - // Sometimes auto interval is not quite right and returns 2X or 3X requested ticks - // Adjust the interval to get closer to the requested number of ticks - const actualSteps = duration / interval; - if (actualSteps > steps * 1.5) { - const factor = Math.round(actualSteps / steps); - interval *= factor; - } else if (actualSteps < 5) { - interval *= 0.5; - } - return interval; -} - -export interface TimeSliderProps { - id: string; - range?: [number | undefined, number | undefined]; - value: [number | null, number | null]; - onChange: (range: [number | null, number | null]) => void; - dateFormat?: string; - timezone?: string; - fieldName: string; - ignoreValidation?: boolean; -} - -const isValidRange = (maybeRange: TimeSliderProps['range']): maybeRange is [number, number] => { - return maybeRange !== undefined && !isNil(maybeRange[0]) && !isNil(maybeRange[1]); -}; - -const unselectedClass = 'timeSlider__anchorText--default'; -const validClass = 'timeSlider__anchorText'; -const invalidClass = 'timeSlider__anchorText--invalid'; - -export const TimeSlider: FC = (props) => { - const defaultProps = { - dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', - ignoreValidation: false, - timezone: 'Browser', - ...props, - }; - const { range, value, timezone, dateFormat, fieldName, ignoreValidation } = defaultProps; - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const togglePopover = useCallback(() => { - setIsPopoverOpen(!isPopoverOpen); - }, [isPopoverOpen, setIsPopoverOpen]); - - const getTimezone = useCallback(() => { - const detectedTimezone = moment.tz.guess(); - - return timezone === 'Browser' ? detectedTimezone : timezone; - }, [timezone]); - - const epochToKbnDateFormat = useCallback( - (epoch: number) => { - const tz = getTimezone(); - return moment.tz(epoch, tz).format(dateFormat); - }, - [dateFormat, getTimezone] - ); - - // If we don't have a range or we have is loading, show the loading state - const hasRange = range !== undefined; - - // We have values if we have a range or value entry for both position - const hasValues = - (value[0] !== null || (hasRange && range[0] !== undefined)) && - (value[1] !== null || (hasRange && range[1] !== undefined)); - - let valueText: JSX.Element | null = null; - if (hasValues) { - let lower = value[0] !== null ? value[0] : range![0]!; - let upper = value[1] !== null ? value[1] : range![1]!; - - if (value[0] !== null && lower > upper) { - upper = lower; - } else if (value[1] !== null && lower > upper) { - lower = upper; - } - - const hasLowerValueInRange = - value[0] !== null && isValidRange(range) && value[0] >= range[0] && value[0] <= range[1]; - // It's out of range if the upper value is above the upper range or below the lower range - const hasUpperValueInRange = - value[1] !== null && isValidRange(range) && value[1] <= range[1] && value[1] >= range[0]; - - let lowClass = unselectedClass; - let highClass = unselectedClass; - if (value[0] !== null && (hasLowerValueInRange || ignoreValidation)) { - lowClass = validClass; - } else if (value[0] !== null) { - lowClass = invalidClass; - } - - if (value[1] !== null && (hasUpperValueInRange || ignoreValidation)) { - highClass = validClass; - } else if (value[1] !== null) { - highClass = invalidClass; - } - - // if no value then anchorText default - // if hasLowerValueInRange || skipValidation then anchor text - // else strikethrough - - valueText = ( - - {epochToKbnDateFormat(lower)} -   →   - {epochToKbnDateFormat(upper)} - - ); - } - - const button = ( - - ); - - return ( - setIsPopoverOpen(false)} - panelPaddingSize="s" - anchorPosition="downCenter" - disableFocusTrap - attachToAnchor={false} - > - {isValidRange(range) ? ( - - ) : ( - - )} - - ); -}; - -const TimeSliderComponentPopoverNoDocuments: FC = () => { - return {TimeSliderStrings.noDocumentsPopover.getLabel()}; -}; - -export const TimeSliderComponentPopover: FC< - TimeSliderProps & { - range: [number, number]; - getTimezone: () => string; - epochToKbnDateFormat: (epoch: number) => string; - } -> = ({ range, value, onChange, getTimezone, epochToKbnDateFormat, fieldName }) => { - const [lowerBound, upperBound] = range; - let [lowerValue, upperValue] = value; - - if (lowerValue === null) { - lowerValue = lowerBound; - } - - if (upperValue === null) { - upperValue = upperBound; - } - - const fullRange = useMemo( - () => [Math.min(lowerValue!, lowerBound), Math.max(upperValue!, upperBound)], - [lowerValue, lowerBound, upperValue, upperBound] - ); - - const getTicks = useCallback( - (min: number, max: number, interval: number): EuiRangeTick[] => { - const format = getScaledDateFormat(interval); - const tz = getTimezone(); - - let tick = Math.ceil(min / interval) * interval; - const ticks: EuiRangeTick[] = []; - while (tick < max) { - ticks.push({ - value: tick, - label: moment.tz(tick, tz).format(format), - }); - tick += interval; - } - - return ticks; - }, - [getTimezone] - ); - - const ticks = useMemo(() => { - const interval = getInterval(fullRange[0], fullRange[1]); - return getTicks(fullRange[0], fullRange[1], interval); - }, [fullRange, getTicks]); - - const onChangeHandler = useCallback( - ([_min, _max]: [number | string, number | string]) => { - // If a value is undefined and the number that is given here matches the range bounds - // then we will ignore it, becuase they probably didn't actually select that value - const report: [number | null, number | null] = [null, null]; - - let min: number; - let max: number; - if (typeof _min === 'string') { - min = parseFloat(_min); - min = isNaN(min) ? range[0] : min; - } else { - min = _min; - } - - if (typeof _max === 'string') { - max = parseFloat(_max); - max = isNaN(max) ? range[0] : max; - } else { - max = _max; - } - - if (value[0] !== null || min !== range[0]) { - report[0] = min; - } - if (value[1] !== null || max !== range[1]) { - report[1] = max; - } - - onChange(report); - }, - [onChange, value, range] - ); - - const levels = [{ min: range[0], max: range[1], color: 'success' }]; - - return ( - <> - {fieldName} - - {epochToKbnDateFormat(lowerValue)} - {epochToKbnDateFormat(upperValue)} - - - - - - - - - onChange([null, null])} - aria-label={TimeSliderStrings.resetButton.getLabel()} - data-test-subj="timeSlider__clearRangeButton" - /> - - - - - - ); -}; diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider.tsx b/src/plugins/controls/public/control_types/time_slider/time_slider.tsx deleted file mode 100644 index 0b519406ccf8d..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider.tsx +++ /dev/null @@ -1,79 +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 React, { FC, useCallback, useMemo } from 'react'; -import { BehaviorSubject } from 'rxjs'; -import { debounce } from 'lodash'; -import { useReduxEmbeddableContext } from '@kbn/presentation-util-plugin/public'; - -import { timeSliderReducers } from './time_slider_reducers'; -import { TimeSlider as Component } from './time_slider.component'; -import { TimeSliderReduxState, TimeSliderSubjectState } from './types'; - -interface TimeSliderProps { - componentStateSubject: BehaviorSubject; - dateFormat: string; - timezone: string; - fieldName: string; - ignoreValidation: boolean; -} - -export const TimeSlider: FC = ({ - componentStateSubject, - dateFormat, - timezone, - fieldName, - ignoreValidation, -}) => { - const { - useEmbeddableDispatch, - useEmbeddableSelector: select, - actions: { selectRange }, - } = useReduxEmbeddableContext(); - const dispatch = useEmbeddableDispatch(); - - const availableRange = select((state) => state.componentState.range); - const value = select((state) => state.explicitInput.value); - const id = select((state) => state.explicitInput.id); - - const { min, max } = availableRange - ? availableRange - : ({} as { - min?: number; - max?: number; - }); - - const dispatchChange = useCallback( - (range: [number | null, number | null]) => { - dispatch(selectRange(range)); - }, - [dispatch, selectRange] - ); - - const debouncedDispatchChange = useMemo(() => debounce(dispatchChange, 500), [dispatchChange]); - - const onChangeComplete = useCallback( - (range: [number | null, number | null]) => { - debouncedDispatchChange(range); - }, - [debouncedDispatchChange] - ); - - return ( - - ); -}; diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.test.ts b/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.test.ts deleted file mode 100644 index 4db5277a0e2f9..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.test.ts +++ /dev/null @@ -1,300 +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 { of } from 'rxjs'; -import { delay, map } from 'rxjs/operators'; -import { TimeSliderControlEmbeddableInput } from '.'; -import { TimeSliderControlEmbeddable } from './time_slider_embeddable'; -import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; -import { pluginServices } from '../../services'; -import { TestScheduler } from 'rxjs/testing'; -import { buildRangeFilter } from '@kbn/es-query'; -import { ReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public'; - -const buildFilter = (range: [number | null, number | null]) => { - const filterPieces: Record = {}; - if (range[0] !== null) { - filterPieces.gte = range[0]; - } - if (range[1] !== null) { - filterPieces.lte = range[1]; - } - - const filter = buildRangeFilter( - stubLogstashDataView.getFieldByName('bytes')!, - filterPieces, - stubLogstashDataView - ); - filter.meta.key = 'bytes'; - - return filter; -}; - -const rangeMin = 20; -const rangeMax = 30; -const range = { min: rangeMin, max: rangeMax }; - -const lowerValue: [number, number] = [15, 25]; -const upperValue: [number, number] = [25, 35]; -const partialLowValue: [number, null] = [25, null]; -const partialHighValue: [null, number] = [null, 25]; -const withinRangeValue: [number, number] = [21, 29]; -const outOfRangeValue: [number, number] = [31, 40]; - -const rangeFilter = buildFilter([rangeMin, rangeMax]); -const lowerValueFilter = buildFilter(lowerValue); -const lowerValuePartialFilter = buildFilter([20, 25]); -const upperValueFilter = buildFilter(upperValue); -const upperValuePartialFilter = buildFilter([25, 30]); - -const partialLowValueFilter = buildFilter(partialLowValue); -const partialHighValueFilter = buildFilter(partialHighValue); -const withinRangeValueFilter = buildFilter(withinRangeValue); -const outOfRangeValueFilter = buildFilter(outOfRangeValue); - -const baseInput: TimeSliderControlEmbeddableInput = { - id: 'id', - fieldName: 'bytes', - dataViewId: stubLogstashDataView.id!, -}; - -const mockReduxEmbeddablePackage = { - createTools: () => {}, -} as unknown as ReduxEmbeddablePackage; - -describe('Time Slider Control Embeddable', () => { - const services = pluginServices.getServices(); - const fetchRange = jest.spyOn(services.data, 'fetchFieldRange'); - const getDataView = jest.spyOn(services.data, 'getDataView'); - const fetchRange$ = jest.spyOn(services.data, 'fetchFieldRange$'); - const getDataView$ = jest.spyOn(services.data, 'getDataView$'); - - beforeEach(() => { - jest.resetAllMocks(); - - fetchRange.mockResolvedValue(range); - fetchRange$.mockReturnValue(of(range).pipe(delay(100))); - getDataView.mockResolvedValue(stubLogstashDataView); - getDataView$.mockReturnValue(of(stubLogstashDataView)); - }); - - describe('outputting filters', () => { - let testScheduler: TestScheduler; - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); - - const testFilterOutput = ( - input: any, - expectedFilterAfterRangeFetch: any, - mockRange: { min?: number; max?: number } = range - ) => { - testScheduler.run(({ expectObservable, cold }) => { - fetchRange$.mockReturnValue(cold('--b', { b: mockRange })); - const expectedMarbles = 'a-b'; - const expectedValues = { - a: undefined, - b: expectedFilterAfterRangeFetch ? [expectedFilterAfterRangeFetch] : undefined, - }; - - const embeddable = new TimeSliderControlEmbeddable(mockReduxEmbeddablePackage, input, {}); - const source$ = embeddable.getOutput$().pipe(map((o) => o.filters)); - - expectObservable(source$).toBe(expectedMarbles, expectedValues); - }); - }; - - it('outputs no filter when no value is given', () => { - testFilterOutput(baseInput, undefined); - }); - - it('outputs the value filter after the range is fetched', () => { - testFilterOutput({ ...baseInput, value: withinRangeValue }, withinRangeValueFilter); - }); - - it('outputs a partial filter for a low partial value', () => { - testFilterOutput({ ...baseInput, value: partialLowValue }, partialLowValueFilter); - }); - - it('outputs a partial filter for a high partial value', () => { - testFilterOutput({ ...baseInput, value: partialHighValue }, partialHighValueFilter); - }); - - describe('with validation', () => { - it('outputs a partial value filter if value is below range', () => { - testFilterOutput({ ...baseInput, value: lowerValue }, lowerValuePartialFilter); - }); - - it('outputs a partial value filter if value is above range', () => { - testFilterOutput({ ...baseInput, value: upperValue }, upperValuePartialFilter); - }); - - it('outputs range filter value if value is completely out of range', () => { - testFilterOutput({ ...baseInput, value: outOfRangeValue }, rangeFilter); - }); - - it('outputs no filter when no range available', () => { - testFilterOutput({ ...baseInput, value: withinRangeValue }, undefined, {}); - }); - }); - - describe('with validation off', () => { - it('outputs the lower value filter', () => { - testFilterOutput( - { ...baseInput, ignoreParentSettings: { ignoreValidations: true }, value: lowerValue }, - lowerValueFilter - ); - }); - - it('outputs the uppwer value filter', () => { - testFilterOutput( - { ...baseInput, ignoreParentSettings: { ignoreValidations: true }, value: upperValue }, - upperValueFilter - ); - }); - - it('outputs the out of range filter', () => { - testFilterOutput( - { - ...baseInput, - ignoreParentSettings: { ignoreValidations: true }, - value: outOfRangeValue, - }, - outOfRangeValueFilter - ); - }); - - it('outputs the value filter when no range found', () => { - testFilterOutput( - { - ...baseInput, - ignoreParentSettings: { ignoreValidations: true }, - value: withinRangeValue, - }, - withinRangeValueFilter, - { min: undefined, max: undefined } - ); - }); - }); - }); - - describe('fetching range', () => { - it('fetches range on init', () => { - const testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - - testScheduler.run(({ cold, expectObservable }) => { - const mockRange = { min: 1, max: 2 }; - fetchRange$.mockReturnValue(cold('--b', { b: mockRange })); - - const expectedMarbles = 'a-b'; - const expectedValues = { - a: undefined, - b: mockRange, - }; - - const embeddable = new TimeSliderControlEmbeddable( - mockReduxEmbeddablePackage, - baseInput, - {} - ); - const source$ = embeddable.getComponentState$().pipe(map((state) => state.range)); - - const { fieldName, ...inputForFetch } = baseInput; - - expectObservable(source$).toBe(expectedMarbles, expectedValues); - expect(fetchRange$).toBeCalledWith(stubLogstashDataView, fieldName, { - ...inputForFetch, - filters: undefined, - query: undefined, - timeRange: undefined, - viewMode: 'edit', - }); - }); - }); - - it('fetches range on input change', () => { - const testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - - testScheduler.run(({ cold, expectObservable, flush }) => { - const mockRange = { min: 1, max: 2 }; - fetchRange$.mockReturnValue(cold('a', { a: mockRange })); - - const embeddable = new TimeSliderControlEmbeddable( - mockReduxEmbeddablePackage, - baseInput, - {} - ); - const updatedInput = { ...baseInput, fieldName: '@timestamp' }; - - embeddable.updateInput(updatedInput); - - expect(fetchRange$).toBeCalledTimes(2); - expect(fetchRange$.mock.calls[1][1]).toBe(updatedInput.fieldName); - }); - }); - - it('passes input to fetch range to build the query', () => { - const testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - - testScheduler.run(({ cold, expectObservable, flush }) => { - const mockRange = { min: 1, max: 2 }; - fetchRange$.mockReturnValue(cold('a', { a: mockRange })); - - const input = { - ...baseInput, - query: {} as any, - filters: {} as any, - timeRange: {} as any, - }; - - new TimeSliderControlEmbeddable(mockReduxEmbeddablePackage, input, {}); - - expect(fetchRange$).toBeCalledTimes(1); - const args = fetchRange$.mock.calls[0][2]; - expect(args.query).toBe(input.query); - expect(args.filters).toBe(input.filters); - expect(args.timeRange).toBe(input.timeRange); - }); - }); - - it('does not pass ignored parent settings', () => { - const testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - - testScheduler.run(({ cold, expectObservable, flush }) => { - const mockRange = { min: 1, max: 2 }; - fetchRange$.mockReturnValue(cold('a', { a: mockRange })); - - const input = { - ...baseInput, - query: '' as any, - filters: {} as any, - timeRange: {} as any, - ignoreParentSettings: { ignoreFilters: true, ignoreQuery: true, ignoreTimerange: true }, - }; - - new TimeSliderControlEmbeddable(mockReduxEmbeddablePackage, input, {}); - - expect(fetchRange$).toBeCalledTimes(1); - const args = fetchRange$.mock.calls[0][2]; - expect(args.query).not.toBe(input.query); - expect(args.filters).not.toBe(input.filters); - expect(args.timeRange).not.toBe(input.timeRange); - }); - }); - }); -}); diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.tsx b/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.tsx deleted file mode 100644 index a4098a72dfe1a..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable.tsx +++ /dev/null @@ -1,334 +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 { compareFilters, buildRangeFilter, RangeFilterParams } from '@kbn/es-query'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { isEqual } from 'lodash'; -import deepEqual from 'fast-deep-equal'; -import { merge, Subscription, BehaviorSubject, Observable } from 'rxjs'; -import { map, distinctUntilChanged, skip, take, mergeMap } from 'rxjs/operators'; - -import { Embeddable, IContainer } from '@kbn/embeddable-plugin/public'; -import { ReduxEmbeddableTools, ReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public'; -import { DataView } from '@kbn/data-views-plugin/public'; - -import { TimeSliderControlEmbeddableInput } from '../../../common/control_types/time_slider/types'; -import { TIME_SLIDER_CONTROL } from '../..'; -import { ControlsSettingsService } from '../../services/settings'; -import { ControlsDataService } from '../../services/data'; -import { ControlOutput } from '../..'; -import { pluginServices } from '../../services'; - -import { TimeSlider as TimeSliderComponent } from './time_slider'; -import { timeSliderReducers } from './time_slider_reducers'; -import { TimeSliderReduxState, TimeSliderSubjectState } from './types'; - -const diffDataFetchProps = (current?: any, last?: any) => { - if (!current || !last) return false; - const { filters: currentFilters, ...currentWithoutFilters } = current; - const { filters: lastFilters, ...lastWithoutFilters } = last; - if (!deepEqual(currentWithoutFilters, lastWithoutFilters)) return false; - if (!compareFilters(lastFilters ?? [], currentFilters ?? [])) return false; - return true; -}; - -export class TimeSliderControlEmbeddable extends Embeddable< - TimeSliderControlEmbeddableInput, - ControlOutput -> { - public readonly type = TIME_SLIDER_CONTROL; - public deferEmbeddableLoad = true; - - private subscriptions: Subscription = new Subscription(); - private node?: HTMLElement; - - // Internal data fetching state for this input control. - private dataView?: DataView; - - private componentState: TimeSliderSubjectState; - private componentStateSubject$ = new BehaviorSubject({ - range: undefined, - loading: false, - }); - - // Internal state subject will let us batch updates to the externally accessible state subject - private internalComponentStateSubject$ = new BehaviorSubject({ - range: undefined, - loading: false, - }); - - private internalOutput: ControlOutput; - - private fetchRange$: ControlsDataService['fetchFieldRange$']; - private getDataView$: ControlsDataService['getDataView$']; - private getDateFormat: ControlsSettingsService['getDateFormat']; - private getTimezone: ControlsSettingsService['getTimezone']; - - private reduxEmbeddableTools: ReduxEmbeddableTools< - TimeSliderReduxState, - typeof timeSliderReducers - >; - - constructor( - reduxEmbeddablePackage: ReduxEmbeddablePackage, - input: TimeSliderControlEmbeddableInput, - output: ControlOutput, - parent?: IContainer - ) { - super(input, output, parent); // get filters for initial output... - - const { - data: { fetchFieldRange$, getDataView$ }, - settings: { getDateFormat, getTimezone }, - } = pluginServices.getServices(); - this.fetchRange$ = fetchFieldRange$; - this.getDataView$ = getDataView$; - this.getDateFormat = getDateFormat; - this.getTimezone = getTimezone; - - this.componentState = { loading: true }; - this.updateComponentState(this.componentState, true); - - this.internalOutput = {}; - - // build redux embeddable tools - this.reduxEmbeddableTools = reduxEmbeddablePackage.createTools< - TimeSliderReduxState, - typeof timeSliderReducers - >({ - embeddable: this, - reducers: timeSliderReducers, - }); - - this.initialize(); - } - - private initialize() { - // If value is undefined, then we can be finished with initialization because we're not going to output a filter - if (this.getInput().value === undefined) { - this.setInitializationFinished(); - } - - this.setupSubscriptions(); - } - - private setupSubscriptions() { - // We need to fetch data when any of these values change - const dataFetchPipe = this.getInput$().pipe( - map((newInput) => ({ - lastReloadRequestTime: newInput.lastReloadRequestTime, - dataViewId: newInput.dataViewId, - fieldName: newInput.fieldName, - timeRange: newInput.timeRange, - filters: newInput.filters, - query: newInput.query, - })), - distinctUntilChanged(diffDataFetchProps) - ); - - // When data fetch pipe emits, we start the fetch - this.subscriptions.add(dataFetchPipe.subscribe(this.fetchAvailableTimerange)); - - const availableRangePipe = this.internalComponentStateSubject$.pipe( - map((state) => (state.range ? { min: state.range.min, max: state.range.max } : {})), - distinctUntilChanged((a, b) => isEqual(a, b)) - ); - - this.subscriptions.add( - merge( - this.getInput$().pipe( - skip(1), // Skip the first input value - distinctUntilChanged((a, b) => isEqual(a.value, b.value)) - ), - availableRangePipe.pipe(skip(1)) - ).subscribe(() => { - this.setInitializationFinished(); - this.buildFilter(); - - this.componentStateSubject$.next(this.componentState); - }) - ); - } - - private buildFilter = () => { - const { fieldName, value, ignoreParentSettings } = this.getInput(); - - const min = value ? value[0] : null; - const max = value ? value[1] : null; - const hasRange = - this.componentState.range?.max !== undefined && this.componentState.range?.min !== undefined; - - this.getCurrentDataView$().subscribe((dataView) => { - const range: RangeFilterParams = {}; - let filterMin: number | undefined; - let filterMax: number | undefined; - const field = dataView.getFieldByName(fieldName); - - if (ignoreParentSettings?.ignoreValidations) { - if (min !== null) { - range.gte = min; - } - - if (max !== null) { - range.lte = max; - } - } else { - // If we have a value or a range use the min/max of those, otherwise undefined - if (min !== null && this.componentState.range!.min !== undefined) { - filterMin = Math.max(min || 0, this.componentState.range!.min || 0); - } - - if (max !== null && this.componentState.range!.max) { - filterMax = Math.min( - max || Number.MAX_SAFE_INTEGER, - this.componentState.range!.max || Number.MAX_SAFE_INTEGER - ); - } - - // Last check, if the value is completely outside the range then we will just default to the range - if ( - hasRange && - ((min !== null && min > this.componentState.range!.max!) || - (max !== null && max < this.componentState.range!.min!)) - ) { - filterMin = this.componentState.range!.min; - filterMax = this.componentState.range!.max; - } - - if (hasRange && filterMin !== undefined) { - range.gte = filterMin; - } - if (hasRange && filterMax !== undefined) { - range.lte = filterMax; - } - } - - if (range.lte !== undefined || range.gte !== undefined) { - const rangeFilter = buildRangeFilter(field!, range, dataView); - rangeFilter.meta.key = field?.name; - - this.updateInternalOutput({ filters: [rangeFilter] }, true); - this.updateComponentState({ loading: false }); - } else { - this.updateInternalOutput({ filters: undefined, dataViewId: dataView.id }, true); - this.updateComponentState({ loading: false }); - } - }); - }; - - private updateComponentState(changes: Partial, publish = false) { - this.componentState = { - ...this.componentState, - ...changes, - }; - - this.internalComponentStateSubject$.next(this.componentState); - - if (publish) { - this.componentStateSubject$.next(this.componentState); - } - } - - private updateInternalOutput(changes: Partial, publish = false) { - this.internalOutput = { - ...this.internalOutput, - ...changes, - }; - - if (publish) { - this.updateOutput(this.internalOutput); - } - } - - private getCurrentDataView$ = () => { - const { dataViewId } = this.getInput(); - if (this.dataView && this.dataView.id === dataViewId) - return new Observable((subscriber) => { - subscriber.next(this.dataView); - subscriber.complete(); - }); - - return this.getDataView$(dataViewId); - }; - - private fetchAvailableTimerange = () => { - this.updateComponentState({ loading: true }, true); - this.updateInternalOutput({ loading: true }, true); - - const { fieldName, ignoreParentSettings, query, filters, timeRange, ...input } = - this.getInput(); - - const inputForFetch = { - ...input, - ...(ignoreParentSettings?.ignoreQuery ? {} : { query }), - ...(ignoreParentSettings?.ignoreFilters ? {} : { filters }), - ...(ignoreParentSettings?.ignoreTimerange ? {} : { timeRange }), - }; - - try { - this.getCurrentDataView$() - .pipe( - mergeMap((dataView) => this.fetchRange$(dataView, fieldName, inputForFetch)), - take(1) - ) - .subscribe(({ min, max }) => { - this.updateInternalOutput({ loading: false }); - this.updateComponentState({ - range: { - min: min === null ? undefined : min, - max: max === null ? undefined : max, - }, - loading: false, - }); - }); - } catch (e) { - this.updateComponentState({ loading: false }, true); - this.updateInternalOutput({ loading: false }, true); - } - }; - - public getComponentState$ = () => { - return this.componentStateSubject$; - }; - - public destroy = () => { - super.destroy(); - this.subscriptions.unsubscribe(); - }; - - public reload = () => { - this.fetchAvailableTimerange(); - }; - - public render = (node: HTMLElement) => { - if (this.node) { - ReactDOM.unmountComponentAtNode(this.node); - } - this.node = node; - - const { Wrapper: TimeSliderControlReduxWrapper } = this.reduxEmbeddableTools; - - ReactDOM.render( - - - , - node - ); - }; -} diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable_factory.tsx b/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable_factory.tsx deleted file mode 100644 index 51048489ccae9..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider_embeddable_factory.tsx +++ /dev/null @@ -1,69 +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 deepEqual from 'fast-deep-equal'; - -import { lazyLoadReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public'; -import { EmbeddableFactoryDefinition, IContainer } from '@kbn/embeddable-plugin/public'; - -import { TIME_SLIDER_CONTROL } from '../..'; -import { ControlEmbeddable, DataControlField, IEditableControlFactory } from '../../types'; -import { - createOptionsListExtract, - createOptionsListInject, -} from '../../../common/options_list/options_list_persistable_state'; -import { TimeSliderControlEmbeddableInput } from '../../../common/control_types/time_slider/types'; -import { TimeSliderStrings } from './time_slider_strings'; - -export class TimesliderEmbeddableFactory - implements EmbeddableFactoryDefinition, IEditableControlFactory -{ - public type = TIME_SLIDER_CONTROL; - public canCreateNew = () => false; - - constructor() {} - - public async create(initialInput: TimeSliderControlEmbeddableInput, parent?: IContainer) { - const reduxEmbeddablePackage = await lazyLoadReduxEmbeddablePackage(); - const { TimeSliderControlEmbeddable } = await import('./time_slider_embeddable'); - - return Promise.resolve( - new TimeSliderControlEmbeddable(reduxEmbeddablePackage, initialInput, {}, parent) - ); - } - - public presaveTransformFunction = ( - newInput: Partial, - embeddable?: ControlEmbeddable - ) => { - if ( - embeddable && - ((newInput.fieldName && !deepEqual(newInput.fieldName, embeddable.getInput().fieldName)) || - (newInput.dataViewId && !deepEqual(newInput.dataViewId, embeddable.getInput().dataViewId))) - ) { - // if the field name or data view id has changed in this editing session, selected options are invalid, so reset them. - newInput.value = undefined; - } - return newInput; - }; - - public isFieldCompatible = (dataControlField: DataControlField) => { - if (dataControlField.field.type === 'date') { - dataControlField.compatibleControlTypes.push(this.type); - } - }; - - public isEditable = () => Promise.resolve(false); - - public getDisplayName = () => TimeSliderStrings.getDisplayName(); - public getIconType = () => 'clock'; - public getDescription = () => TimeSliderStrings.getDescription(); - - public inject = createOptionsListInject(); - public extract = createOptionsListExtract(); -} diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider_reducers.ts b/src/plugins/controls/public/control_types/time_slider/time_slider_reducers.ts deleted file mode 100644 index 95b8d87dc902e..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider_reducers.ts +++ /dev/null @@ -1,20 +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 { PayloadAction } from '@reduxjs/toolkit'; -import { WritableDraft } from 'immer/dist/types/types-external'; -import { TimeSliderReduxState } from './types'; - -export const timeSliderReducers = { - selectRange: ( - state: WritableDraft, - action: PayloadAction<[number | null, number | null]> - ) => { - state.explicitInput.value = action.payload; - }, -}; diff --git a/src/plugins/controls/public/control_types/time_slider/time_slider_strings.ts b/src/plugins/controls/public/control_types/time_slider/time_slider_strings.ts deleted file mode 100644 index 2c61d7d43a797..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/time_slider_strings.ts +++ /dev/null @@ -1,46 +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 { i18n } from '@kbn/i18n'; - -export const TimeSliderStrings = { - getDisplayName: () => - i18n.translate('controls.timeSlider.displayName', { - defaultMessage: 'Time slider', - }), - getDescription: () => - i18n.translate('controls.timeSlider.description', { - defaultMessage: 'Add a slider for selecting a time range', - }), - editor: { - getDataViewTitle: () => - i18n.translate('controls.timeSlider.editor.dataViewTitle', { - defaultMessage: 'Data view', - }), - getNoDataViewTitle: () => - i18n.translate('controls.timeSlider.editor.noDataViewTitle', { - defaultMessage: 'Select data view', - }), - getFieldTitle: () => - i18n.translate('controls.timeSlider.editor.fieldTitle', { - defaultMessage: 'Field', - }), - }, - resetButton: { - getLabel: () => - i18n.translate('controls.timeSlider.resetButton.label', { - defaultMessage: 'Reset selections', - }), - }, - noDocumentsPopover: { - getLabel: () => - i18n.translate('controls.timeSlider.noDocuments.label', { - defaultMessage: 'There were no documents found. Range selection unavailable.', - }), - }, -}; diff --git a/src/plugins/controls/public/control_types/time_slider/types.ts b/src/plugins/controls/public/control_types/time_slider/types.ts deleted file mode 100644 index fc147dc3ba959..0000000000000 --- a/src/plugins/controls/public/control_types/time_slider/types.ts +++ /dev/null @@ -1,30 +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 { ReduxEmbeddableState } from '@kbn/presentation-util-plugin/public'; - -import { ControlOutput } from '../../types'; -import { TimeSliderControlEmbeddableInput } from '../../../common/control_types/time_slider/types'; - -export * from '../../../common/control_types/time_slider/types'; - -// Component state is only used by public components. -export interface TimeSliderSubjectState { - range?: { - min?: number; - max?: number; - }; - loading: boolean; -} - -// public only - redux embeddable state type -export type TimeSliderReduxState = ReduxEmbeddableState< - TimeSliderControlEmbeddableInput, - ControlOutput, - TimeSliderSubjectState ->; diff --git a/src/plugins/controls/public/index.ts b/src/plugins/controls/public/index.ts index f55df5fa0f53a..ecf430f6cc927 100644 --- a/src/plugins/controls/public/index.ts +++ b/src/plugins/controls/public/index.ts @@ -24,12 +24,7 @@ export type { ControlInput, } from '../common/types'; -export { - CONTROL_GROUP_TYPE, - OPTIONS_LIST_CONTROL, - RANGE_SLIDER_CONTROL, - TIME_SLIDER_CONTROL, -} from '../common'; +export { CONTROL_GROUP_TYPE, OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL } from '../common'; export { ControlGroupContainer, diff --git a/src/plugins/controls/public/plugin.ts b/src/plugins/controls/public/plugin.ts index da45ba2e68684..01375b174a934 100644 --- a/src/plugins/controls/public/plugin.ts +++ b/src/plugins/controls/public/plugin.ts @@ -14,7 +14,6 @@ import { CONTROL_GROUP_TYPE, OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL, - // TIME_SLIDER_CONTROL, } from '.'; import { OptionsListEmbeddableFactory, OptionsListEmbeddableInput } from './options_list'; import { RangeSliderEmbeddableFactory, RangeSliderEmbeddableInput } from './range_slider'; @@ -29,13 +28,6 @@ import { ControlInput, } from './types'; -/* -import { - TimesliderEmbeddableFactory, - TimeSliderControlEmbeddableInput, -} from './control_types/time_slider'; -*/ - export class ControlsPlugin implements Plugin< @@ -101,22 +93,6 @@ export class ControlsPlugin rangeSliderFactory ); registerControlType(rangeSliderFactory); - - // Time Slider Control Factory Setup - /* Temporary disabling Time Slider - const timeSliderFactoryDef = new TimesliderEmbeddableFactory(); - const timeSliderFactory = embeddable.registerEmbeddableFactory( - TIME_SLIDER_CONTROL, - timeSliderFactoryDef - )(); - this.transferEditorFunctions( - timeSliderFactoryDef, - timeSliderFactory - ); - - - registerControlType(timeSliderFactory); - */ }); return { diff --git a/src/plugins/controls/server/control_group/control_group_telemetry.test.ts b/src/plugins/controls/server/control_group/control_group_telemetry.test.ts index 140b58fd790fc..1e66bb15fbc2b 100644 --- a/src/plugins/controls/server/control_group/control_group_telemetry.test.ts +++ b/src/plugins/controls/server/control_group/control_group_telemetry.test.ts @@ -24,7 +24,7 @@ const rawControlAttributes2: RawControlGroupAttributes = { controlStyle: 'oneLine', chainingSystem: 'NONE', panelsJSON: - '{"9cf90205-e94d-43c9-a3aa-45f359a7522f":{"order":0,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceKilometers","fieldName":"DistanceKilometers","id":"9cf90205-e94d-43c9-a3aa-45f359a7522f","enhancements":{}}},"b47916fd-fc03-4dcd-bef1-5c3b7a315723":{"order":1,"width":"auto","type":"timeSlider","explicitInput":{"title":"timestamp","fieldName":"timestamp","id":"b47916fd-fc03-4dcd-bef1-5c3b7a315723","enhancements":{}}},"f6b076c6-9ef5-483e-b08d-d313d60d4b8c":{"order":2,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceMiles","fieldName":"DistanceMiles","id":"f6b076c6-9ef5-483e-b08d-d313d60d4b8c","enhancements":{}}}}', + '{"9cf90205-e94d-43c9-a3aa-45f359a7522f":{"order":0,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceKilometers","fieldName":"DistanceKilometers","id":"9cf90205-e94d-43c9-a3aa-45f359a7522f","enhancements":{}}},"f6b076c6-9ef5-483e-b08d-d313d60d4b8c":{"order":2,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceMiles","fieldName":"DistanceMiles","id":"f6b076c6-9ef5-483e-b08d-d313d60d4b8c","enhancements":{}}}}', ignoreParentSettingsJSON: '{"ignoreFilters":true,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}', }; @@ -34,7 +34,7 @@ const rawControlAttributes3: RawControlGroupAttributes = { controlStyle: 'oneLine', chainingSystem: 'HIERARCHICAL', panelsJSON: - '{"9cf90205-e94d-43c9-a3aa-45f359a7522f":{"order":0,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceKilometers","fieldName":"DistanceKilometers","id":"9cf90205-e94d-43c9-a3aa-45f359a7522f","enhancements":{}}},"b47916fd-fc03-4dcd-bef1-5c3b7a315723":{"order":1,"width":"auto","type":"timeSlider","explicitInput":{"title":"timestamp","fieldName":"timestamp","id":"b47916fd-fc03-4dcd-bef1-5c3b7a315723","enhancements":{}}},"ee325e9e-6ec1-41f9-953f-423d59850d44":{"order":2,"width":"auto","type":"optionsListControl","explicitInput":{"title":"Carrier","fieldName":"Carrier","id":"ee325e9e-6ec1-41f9-953f-423d59850d44","enhancements":{}}},"cb0f5fcd-9ad9-4d4a-b489-b75bd060399b":{"order":3,"width":"auto","type":"optionsListControl","explicitInput":{"title":"DestCityName","fieldName":"DestCityName","id":"cb0f5fcd-9ad9-4d4a-b489-b75bd060399b","enhancements":{}}}}', + '{"9cf90205-e94d-43c9-a3aa-45f359a7522f":{"order":0,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceKilometers","fieldName":"DistanceKilometers","id":"9cf90205-e94d-43c9-a3aa-45f359a7522f","enhancements":{}}},"ee325e9e-6ec1-41f9-953f-423d59850d44":{"order":2,"width":"auto","type":"optionsListControl","explicitInput":{"title":"Carrier","fieldName":"Carrier","id":"ee325e9e-6ec1-41f9-953f-423d59850d44","enhancements":{}}},"cb0f5fcd-9ad9-4d4a-b489-b75bd060399b":{"order":3,"width":"auto","type":"optionsListControl","explicitInput":{"title":"DestCityName","fieldName":"DestCityName","id":"cb0f5fcd-9ad9-4d4a-b489-b75bd060399b","enhancements":{}}}}', ignoreParentSettingsJSON: '{"ignoreFilters":false,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}', }; @@ -97,7 +97,7 @@ describe('Control group telemetry function', () => { }); test('counts all telemetry over multiple runs', () => { - expect(finalTelemetry.total).toBe(10); + expect(finalTelemetry.total).toBe(8); }); test('counts control types over multiple runs.', () => { @@ -110,10 +110,6 @@ describe('Control group telemetry function', () => { details: {}, total: 3, }, - timeSlider: { - details: {}, - total: 2, - }, }); }); diff --git a/src/plugins/controls/server/control_types/time_slider/time_slider_embeddable_factory.ts b/src/plugins/controls/server/control_types/time_slider/time_slider_embeddable_factory.ts deleted file mode 100644 index 8e8920f12f554..0000000000000 --- a/src/plugins/controls/server/control_types/time_slider/time_slider_embeddable_factory.ts +++ /dev/null @@ -1,22 +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 { EmbeddableRegistryDefinition } from '@kbn/embeddable-plugin/server'; -import { TIME_SLIDER_CONTROL } from '../../../common'; -import { - createTimeSliderExtract, - createTimeSliderInject, -} from '../../../common/control_types/time_slider/time_slider_persistable_state'; - -export const timeSliderPersistableStateServiceFactory = (): EmbeddableRegistryDefinition => { - return { - id: TIME_SLIDER_CONTROL, - extract: createTimeSliderExtract(), - inject: createTimeSliderInject(), - }; -}; diff --git a/src/plugins/controls/server/plugin.ts b/src/plugins/controls/server/plugin.ts index 00d9688815796..019430166ff6f 100644 --- a/src/plugins/controls/server/plugin.ts +++ b/src/plugins/controls/server/plugin.ts @@ -14,7 +14,6 @@ import { setupOptionsListSuggestionsRoute } from './options_list/options_list_su import { controlGroupContainerPersistableStateServiceFactory } from './control_group/control_group_container_factory'; import { optionsListPersistableStateServiceFactory } from './options_list/options_list_embeddable_factory'; import { rangeSliderPersistableStateServiceFactory } from './range_slider/range_slider_embeddable_factory'; -// import { timeSliderPersistableStateServiceFactory } from './control_types/time_slider/time_slider_embeddable_factory'; interface SetupDeps { embeddable: EmbeddableSetup; @@ -24,14 +23,11 @@ interface SetupDeps { export class ControlsPlugin implements Plugin { public setup(core: CoreSetup, { embeddable, unifiedSearch }: SetupDeps) { - embeddable.registerEmbeddableFactory(optionsListPersistableStateServiceFactory()); - embeddable.registerEmbeddableFactory(rangeSliderPersistableStateServiceFactory()); - // Temporary disabling Time Slider - // embeddable.registerEmbeddableFactory(timeSliderPersistableStateServiceFactory()); - embeddable.registerEmbeddableFactory( controlGroupContainerPersistableStateServiceFactory(embeddable) ); + embeddable.registerEmbeddableFactory(optionsListPersistableStateServiceFactory()); + embeddable.registerEmbeddableFactory(rangeSliderPersistableStateServiceFactory()); setupOptionsListSuggestionsRoute(core, unifiedSearch.autocomplete.getAutocompleteSettings); return {}; diff --git a/test/functional/apps/dashboard_elements/controls/replace_controls.ts b/test/functional/apps/dashboard_elements/controls/replace_controls.ts index 2d1f4509f04ce..ff4efebf9cac9 100644 --- a/test/functional/apps/dashboard_elements/controls/replace_controls.ts +++ b/test/functional/apps/dashboard_elements/controls/replace_controls.ts @@ -6,11 +6,7 @@ * Side Public License, v 1. */ -import { - OPTIONS_LIST_CONTROL, - RANGE_SLIDER_CONTROL, - TIME_SLIDER_CONTROL, -} from '@kbn/controls-plugin/common'; +import { OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL } from '@kbn/controls-plugin/common'; import { FtrProviderContext } from '../../../ftr_provider_context'; @@ -49,12 +45,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }; - const replaceWithTimeSlider = async (controlId: string) => { - await changeFieldType(controlId, '@timestamp', TIME_SLIDER_CONTROL); - await testSubjects.waitForDeleted('timeSlider-loading-spinner'); - await dashboardControls.verifyControlType(controlId, 'timeSlider'); - }; - describe('Replacing controls', async () => { let controlId: string; @@ -89,12 +79,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('with range slider', async () => { await replaceWithRangeSlider(controlId); }); - - /** Because the time slider is temporarily disabled as of https://github.com/elastic/kibana/pull/130978, - ** I simply skipped all time slider tests for now :) **/ - it.skip('with time slider', async () => { - await replaceWithTimeSlider(controlId); - }); }); describe('Replace range slider', async () => { @@ -116,35 +100,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('with options list', async () => { await replaceWithOptionsList(controlId); }); - - it.skip('with time slider', async () => { - await replaceWithTimeSlider(controlId); - }); - }); - - describe.skip('Replace time slider', async () => { - beforeEach(async () => { - await dashboardControls.clearAllControls(); - await dashboardControls.createControl({ - controlType: TIME_SLIDER_CONTROL, - dataViewTitle: 'animals-*', - fieldName: '@timestamp', - }); - await testSubjects.waitForDeleted('timeSlider-loading-spinner'); - controlId = (await dashboardControls.getAllControlIds())[0]; - }); - - afterEach(async () => { - await dashboard.clearUnsavedChanges(); - }); - - it('with options list', async () => { - await replaceWithOptionsList(controlId); - }); - - it('with range slider', async () => { - await replaceWithRangeSlider(controlId); - }); }); }); } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index f8ae6a357f90a..0b2b72de83099 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -390,13 +390,6 @@ "controls.rangeSlider.popover.clearRangeTitle": "Effacer la plage", "controls.rangeSlider.popover.noAvailableDataHelpText": "Il n'y a aucune donnée à afficher. Ajustez la plage temporelle et les filtres.", "controls.rangeSlider.popover.noDataHelpText": "La plage sélectionnée n'a généré aucune donnée. Aucun filtre n'a été appliqué.", - "controls.timeSlider.description": "Ajouter un curseur pour la sélection d'une plage temporelle", - "controls.timeSlider.displayName": "Curseur temporel", - "controls.timeSlider.editor.dataViewTitle": "Vue de données", - "controls.timeSlider.editor.fieldTitle": "Champ", - "controls.timeSlider.editor.noDataViewTitle": "Sélectionner la vue de données", - "controls.timeSlider.noDocuments.label": "Aucun document n'a été trouvé. Sélection de plage non disponible.", - "controls.timeSlider.resetButton.label": "Réinitialiser les sélections", "core.chrome.browserDeprecationWarning": "La prise en charge d'Internet Explorer sera abandonnée dans les futures versions de ce logiciel. Veuillez consulter le site {link}.", "core.deprecations.deprecations.fetchFailedMessage": "Impossible d'extraire les informations de déclassement pour le plug-in {domainId}.", "core.deprecations.deprecations.fetchFailedTitle": "Impossible d'extraire les déclassements pour {domainId}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7029e1e2ed77d..0e8650985261d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -390,13 +390,6 @@ "controls.rangeSlider.popover.clearRangeTitle": "範囲を消去", "controls.rangeSlider.popover.noAvailableDataHelpText": "表示するデータがありません。時間範囲とフィルターを調整します。", "controls.rangeSlider.popover.noDataHelpText": "選択された範囲にはデータがありません。フィルターが適用されませんでした。", - "controls.timeSlider.description": "時間範囲を選択するためのスライダーを追加", - "controls.timeSlider.displayName": "時間スライダー", - "controls.timeSlider.editor.dataViewTitle": "データビュー", - "controls.timeSlider.editor.fieldTitle": "フィールド", - "controls.timeSlider.editor.noDataViewTitle": "データビューを選択", - "controls.timeSlider.noDocuments.label": "ドキュメントが見つかりませんでした。 範囲選択を使用できません。", - "controls.timeSlider.resetButton.label": "選択項目をリセット", "core.chrome.browserDeprecationWarning": "このソフトウェアの将来のバージョンでは、Internet Explorerのサポートが削除されます。{link}をご確認ください。", "core.deprecations.deprecations.fetchFailedMessage": "プラグイン{domainId}の廃止予定情報を取得できません。", "core.deprecations.deprecations.fetchFailedTitle": "{domainId}の廃止予定を取得できませんでした", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 466249148fec7..650d9f9b89da3 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -390,13 +390,6 @@ "controls.rangeSlider.popover.clearRangeTitle": "清除范围", "controls.rangeSlider.popover.noAvailableDataHelpText": "没有可显示的数据。调整时间范围和筛选。", "controls.rangeSlider.popover.noDataHelpText": "选定范围未生成任何数据。未应用任何筛选。", - "controls.timeSlider.description": "添加用于选择时间范围的滑块", - "controls.timeSlider.displayName": "时间滑块", - "controls.timeSlider.editor.dataViewTitle": "数据视图", - "controls.timeSlider.editor.fieldTitle": "字段", - "controls.timeSlider.editor.noDataViewTitle": "选择数据视图", - "controls.timeSlider.noDocuments.label": "找不到文档。 范围选择不可用。", - "controls.timeSlider.resetButton.label": "重置选择", "core.chrome.browserDeprecationWarning": "本软件的未来版本将放弃对 Internet Explorer 的支持,请查看{link}。", "core.deprecations.deprecations.fetchFailedMessage": "无法提取插件 {domainId} 的弃用信息。", "core.deprecations.deprecations.fetchFailedTitle": "无法提取 {domainId} 的弃用信息", From 4473863d797f74efb113a74c5007ce6dc8bfa149 Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Tue, 23 Aug 2022 15:01:52 -0500 Subject: [PATCH 39/41] [Enterprise Search] auto-select index when creating engine (#139152) * [Enterprise Search] auto-select index when creating engine Updated the link to create an App Engine from an elasticsearch index detail page so that it automatically selects that engine on the engine creation page. * [Enterprise Search] disable create engine for hidden indices You cannot create an App Search engine for a hidden index so we are disabling the "Create a new App Search engine" menu item for hidden indices. There is an exception for workplace search document indices, but we are intentionally ignoring this case since the create new engine page will not show any hidden indices by default. You have to first create an alias for the index. So while technically possible, we are choosing to not support it from this page. * [Enterprise Search] added index action for create engine Added an action to handle initializing the create engine page with an es index. * removed addQueryParameter utility This was added to help with encoding parameters, but I opted to use the existing function `generateEncodedPath` instead so this is no longer needed. * improving type usage in fetch_indices * update hidden to required on index type Updated the ElasticsearchIndex type to make hidden required instead of optional since we only really care if its true, otherwise we can treat undefined as not hidden and remove the undefined state. --- .../enterprise_search/common/types/indices.ts | 1 + .../__mocks__/engine_creation_logic.mock.ts | 7 +++ .../engine_creation/engine_creation.tsx | 9 ++- .../engine_creation/engine_creation_logic.ts | 9 +++ .../__mocks__/search_indices.mock.ts | 3 + .../__mocks__/view_index.mock.ts | 3 + .../create_engine_menu_item.tsx | 63 +++++++++++++++++++ .../header_actions/header_actions.tsx | 2 +- .../header_actions/search_engines_popover.tsx | 43 +++++++------ .../applications/shared/constants/index.ts | 1 + .../shared/constants/query_params.ts | 8 +++ .../server/__mocks__/fetch_indices.mock.ts | 2 + .../server/lib/indices/fetch_index.test.ts | 2 + .../server/lib/indices/fetch_indices.test.ts | 9 +++ .../server/lib/indices/fetch_indices.ts | 20 +++--- 15 files changed, 153 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx create mode 100644 x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.ts diff --git a/x-pack/plugins/enterprise_search/common/types/indices.ts b/x-pack/plugins/enterprise_search/common/types/indices.ts index 38f4b9873eba2..08f4125ef8efa 100644 --- a/x-pack/plugins/enterprise_search/common/types/indices.ts +++ b/x-pack/plugins/enterprise_search/common/types/indices.ts @@ -18,6 +18,7 @@ import { Crawler } from './crawler'; export interface ElasticsearchIndex { count: number; // Elasticsearch _count health?: HealthStatus; + hidden: boolean; name: IndexName; status?: IndicesStatsIndexMetadataState; total: { diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts index 6cfba782698b5..42e9c546d85ae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/__mocks__/engine_creation_logic.mock.ts @@ -38,6 +38,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 0, health: 'yellow', + hidden: false, status: 'open', name: 'search-my-index-1', uuid: 'ydlR_QQJTeyZP66tzQSmMQ', @@ -56,6 +57,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'my-index-2', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -74,6 +76,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'search-my-index-2', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -92,6 +95,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'alias-my-index-2', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -110,6 +114,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'index-without-read-privilege', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -128,6 +133,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'index-without-manage-privilege', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', @@ -146,6 +152,7 @@ export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [ { count: 100, health: 'green', + hidden: false, status: 'open', name: 'alias-without-manage-privilege', uuid: '4dlR_QQJTe2ZP6qtzQSmMQ', diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx index 95ed3875888f4..b9fd23ac904f0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation.tsx @@ -12,6 +12,7 @@ import { useLocation } from 'react-router-dom'; import { Location } from 'history'; import { useActions, useValues } from 'kea'; +import { ESINDEX_QUERY_PARAMETER } from '../../../shared/constants'; import { parseQueryParams } from '../../../shared/query_params'; import { ENGINES_TITLE } from '../engines'; import { AppSearchPageTemplate } from '../layout'; @@ -25,15 +26,19 @@ import { SelectEngineType } from './select_engine_type'; export const EngineCreation: React.FC = () => { const { search } = useLocation() as Location; - const { method } = parseQueryParams(search); + const { method, ...params } = parseQueryParams(search); const { engineType, currentEngineCreationStep } = useValues(EngineCreationLogic); - const { setIngestionMethod } = useActions(EngineCreationLogic); + const { setIngestionMethod, initializeWithESIndex } = useActions(EngineCreationLogic); useEffect(() => { if (typeof method === 'string') { setIngestionMethod(method); } + const esIndexParam = params[ESINDEX_QUERY_PARAMETER]; + if (typeof esIndexParam === 'string') { + initializeWithESIndex(esIndexParam); + } }, []); return ( diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts index dbf7efa907c74..347846686b5cd 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/engine_creation/engine_creation_logic.ts @@ -42,6 +42,7 @@ interface EngineCreationActions { setSelectedIndex(selectedIndexName: string): { selectedIndexName: string }; setEngineType(engineType: EngineType): { engineType: EngineType }; setIsAliasAllowed(isAliasAllowed: boolean): { isAliasAllowed: boolean }; + initializeWithESIndex(indexName: string): { indexName: string }; } interface EngineCreationValues { @@ -82,6 +83,7 @@ export const EngineCreationLogic = kea ({ engineType }), setCreationStep: (currentEngineCreationStep) => currentEngineCreationStep, setIsAliasAllowed: (isAliasAllowed) => ({ isAliasAllowed }), + initializeWithESIndex: (indexName) => ({ indexName }), }, reducers: { ingestionMethod: [ @@ -118,6 +120,10 @@ export const EngineCreationLogic = kea + indexName.length === 0 || indexName.startsWith('search-') + ? '' + : `search-${indexName}-alias`, }, ], isAliasAllowed: [ @@ -145,18 +151,21 @@ export const EngineCreationLogic = kea selectedIndexName, onSubmitError: () => '', + initializeWithESIndex: (_, { indexName }) => indexName, }, ], engineType: [ 'appSearch', { setEngineType: (_, { engineType }) => engineType, + initializeWithESIndex: () => 'elasticsearch', }, ], currentEngineCreationStep: [ EngineCreationSteps.SelectStep, { setCreationStep: (_, currentEngineCreationStep) => currentEngineCreationStep, + initializeWithESIndex: () => EngineCreationSteps.ConfigureStep, }, ], }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts index ba72c8ada0dd1..e39ff051f962b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/search_indices.mock.ts @@ -11,6 +11,7 @@ import { ElasticsearchIndexWithIngestion } from '../../../../common/types/indice export const indices: ElasticsearchIndexWithIngestion[] = [ { count: 1, + hidden: false, name: 'api', total: { docs: { @@ -41,6 +42,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [ sync_now: false, }, count: 1, + hidden: false, name: 'connector', total: { docs: { @@ -56,6 +58,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [ id: '3', index_name: 'crawler', }, + hidden: false, name: 'crawler', total: { docs: { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts index 9ade186d55380..bc226baa77f7f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/__mocks__/view_index.mock.ts @@ -20,6 +20,7 @@ export const apiIndex: ApiViewIndex = { ingestionMethod: IngestionMethod.API, ingestionStatus: IngestionStatus.CONNECTED, lastUpdated: null, + hidden: false, name: 'api', total: { docs: { @@ -50,6 +51,7 @@ export const connectorIndex: ConnectorViewIndex = { sync_now: false, }, count: 1, + hidden: false, ingestionMethod: IngestionMethod.CONNECTOR, ingestionStatus: IngestionStatus.INCOMPLETE, lastUpdated: 'never', @@ -68,6 +70,7 @@ export const crawlerIndex: CrawlerViewIndex = { id: '3', index_name: 'crawler', }, + hidden: false, ingestionMethod: IngestionMethod.CRAWLER, ingestionStatus: IngestionStatus.INCOMPLETE, lastUpdated: null, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx new file mode 100644 index 0000000000000..a5667327a8208 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/create_engine_menu_item.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { EuiBetaBadge, EuiContextMenuItem, EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { APP_SEARCH_PLUGIN } from '../../../../../../../common/constants'; +import { ENGINE_CREATION_PATH } from '../../../../../app_search/routes'; +import { ESINDEX_QUERY_PARAMETER } from '../../../../../shared/constants'; +import { generateEncodedPath } from '../../../../../shared/encode_path_params'; +import { KibanaLogic } from '../../../../../shared/kibana'; + +export interface CreateEngineMenuItemProps { + indexName?: string; + isHiddenIndex?: boolean; +} + +export const CreateEngineMenuItem: React.FC = ({ + indexName, + isHiddenIndex, +}) => { + const engineCreationPath = !indexName + ? `${APP_SEARCH_PLUGIN.URL}${ENGINE_CREATION_PATH}` + : generateEncodedPath(`${APP_SEARCH_PLUGIN.URL}${ENGINE_CREATION_PATH}?:indexKey=:indexName`, { + indexKey: ESINDEX_QUERY_PARAMETER, + indexName, + }); + + return ( + + + { + KibanaLogic.values.navigateToUrl(engineCreationPath, { + shouldNotCreateHref: true, + }); + }} + disabled={isHiddenIndex} + > + +

+ {i18n.translate('xpack.enterpriseSearch.content.index.searchEngines.createEngine', { + defaultMessage: 'Create an App Search engine', + })} +

+
+
+
+ + + +
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx index 3809483e053e7..9f04dd7ba16ce 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/header_actions.tsx @@ -18,5 +18,5 @@ import { SyncButton } from './sync_button'; export const getHeaderActions = (indexData?: ElasticsearchIndexWithIngestion) => [ ...(isCrawlerIndex(indexData) ? [] : []), ...(isConnectorIndex(indexData) ? [] : []), - , + , ]; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx index d535d37a4a8ee..2ac1682f8676c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/header_actions/search_engines_popover.tsx @@ -15,17 +15,26 @@ import { EuiContextMenuPanel, EuiContextMenuItem, EuiText, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { APP_SEARCH_PLUGIN } from '../../../../../../../common/constants'; -import { ENGINE_CREATION_PATH } from '../../../../../app_search/routes'; import { KibanaLogic } from '../../../../../shared/kibana'; +import { CreateEngineMenuItem } from './create_engine_menu_item'; import { SearchEnginesPopoverLogic } from './search_engines_popover_logic'; -export const SearchEnginesPopover: React.FC = () => { +export interface SearchEnginesPopoverProps { + indexName?: string; + isHiddenIndex?: boolean; +} + +export const SearchEnginesPopover: React.FC = ({ + indexName, + isHiddenIndex, +}) => { const { isSearchEnginesPopoverOpen } = useValues(SearchEnginesPopoverLogic); const { toggleSearchEnginesPopover } = useActions(SearchEnginesPopoverLogic); @@ -60,22 +69,20 @@ export const SearchEnginesPopover: React.FC = () => {

, - { - KibanaLogic.values.navigateToUrl(APP_SEARCH_PLUGIN.URL + ENGINE_CREATION_PATH, { - shouldNotCreateHref: true, - }); - }} - > - -

- {i18n.translate('xpack.enterpriseSearch.content.index.searchEngines.createEngine', { - defaultMessage: 'Create a new App Search engine', - })} -

-
-
, + isHiddenIndex ? ( + + ) : ( + + ), ]} /> diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts index 6075f6e9822d3..fa9eb67cf9fe4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/constants/index.ts @@ -7,6 +7,7 @@ export * from './actions'; export * from './labels'; +export * from './query_params'; export * from './tables'; export * from './units'; export { DEFAULT_META } from './default_meta'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.ts b/x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.ts new file mode 100644 index 0000000000000..1a95b9734043e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/shared/constants/query_params.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 const ESINDEX_QUERY_PARAMETER = 'esindex'; diff --git a/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts b/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts index 5305cc8ecdb55..a860069af9e93 100644 --- a/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts +++ b/x-pack/plugins/enterprise_search/server/__mocks__/fetch_indices.mock.ts @@ -15,6 +15,7 @@ export const mockSingleIndexStatsResponse = { indices: { 'search-regular-index': { health: 'green', + hidden: false, status: 'open', total: { docs: { @@ -115,6 +116,7 @@ export const getIndexReturnValue = (indexName: string) => { alias: indexName.startsWith('alias') || indexName.startsWith('search-alias'), count: 100, name: indexName, + hidden: indexName.includes('hidden'), privileges: { manage: true, read: true }, total: { ...mockMultiStatsResponse.indices[indexName].total, diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts index 9bf9f2b2d2f1d..49384f564a988 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_index.test.ts @@ -43,6 +43,7 @@ describe('fetchIndex lib function', () => { indices: { index_name: { health: 'green', + hidden: false, size: new ByteSizeValue(108000).toString(), status: 'open', total: { @@ -63,6 +64,7 @@ describe('fetchIndex lib function', () => { aliases: [], count: 100, health: 'green', + hidden: false, name: 'index_name', status: 'open', total: { diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts index 1fc8f4cc07186..4a01295fbeaa8 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.test.ts @@ -86,6 +86,7 @@ describe('fetchIndices lib function', () => { alias: false, count: 100, health: 'green', + hidden: false, name: 'search-regular-index', privileges: { manage: true, read: true }, status: 'open', @@ -135,6 +136,7 @@ describe('fetchIndices lib function', () => { alias: false, count: 100, health: 'green', + hidden: false, name: 'search-regular-index', privileges: { manage: true, read: true }, status: 'open', @@ -195,6 +197,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'index-without-prefix', status: 'open', alias: false, @@ -213,6 +216,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'search-aliased', status: 'open', alias: true, @@ -231,6 +235,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'search-double-aliased', status: 'open', alias: true, @@ -249,6 +254,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'second-index', status: 'open', alias: false, @@ -298,6 +304,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'index-without-prefix', status: 'open', alias: false, @@ -316,6 +323,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: 'green', + hidden: false, name: 'second-index', status: 'open', alias: false, @@ -350,6 +358,7 @@ describe('fetchIndices lib function', () => { { count: 100, health: undefined, + hidden: false, name: 'search-regular-index', status: undefined, alias: false, diff --git a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts index 28a5373d50ac5..5a1bfec87b9b7 100644 --- a/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts +++ b/x-pack/plugins/enterprise_search/server/lib/indices/fetch_indices.ts @@ -13,13 +13,16 @@ import { import { ByteSizeValue } from '@kbn/config-schema'; import { IScopedClusterClient } from '@kbn/core/server'; -import { ElasticsearchIndexWithPrivileges } from '../../../common/types'; +import { + ElasticsearchIndex, + ElasticsearchIndexWithPrivileges, +} from '../../../common/types/indices'; export const mapIndexStats = ( indexData: IndicesIndexState, indexStats: IndicesStatsIndicesStats, indexName: string -) => { +): Omit & { aliases: string[] } => { const aliases = Object.keys(indexData.aliases!); const sizeInBytes = new ByteSizeValue(indexStats?.total?.store?.size_in_bytes ?? 0).toString(); @@ -38,6 +41,7 @@ export const mapIndexStats = ( return { aliases, health: indexStats?.health, + hidden: Boolean(indexData.settings?.index?.hidden), name: indexName, status: indexStats?.status, total, @@ -132,17 +136,17 @@ export const fetchIndices = async ( return mapIndexStats(indexData, indexStats, indexName); }) .flatMap(({ name, aliases, ...indexData }) => { - const indicesAndAliases = [] as ElasticsearchIndexWithPrivileges[]; + const indicesAndAliases: ElasticsearchIndexWithPrivileges[] = []; if (includeAliases) { aliases.forEach((alias) => { if (alias.startsWith(alwaysShowSearchPattern)) { indicesAndAliases.push({ + ...indexData, alias: true, count: indexCounts[alias] ?? 0, name: alias, privileges: { manage: false, read: false, ...indexPrivileges[name] }, - ...indexData, }); } }); @@ -160,23 +164,23 @@ export const fetchIndices = async ( }) .flatMap(({ name, aliases, ...indexData }) => { // expand aliases and add to results - const indicesAndAliases = [] as ElasticsearchIndexWithPrivileges[]; + const indicesAndAliases: ElasticsearchIndexWithPrivileges[] = []; indicesAndAliases.push({ + ...indexData, alias: false, count: indexCounts[name] ?? 0, name, privileges: { manage: false, read: false, ...indexPrivileges[name] }, - ...indexData, }); if (includeAliases) { aliases.forEach((alias) => { indicesAndAliases.push({ + ...indexData, alias: true, count: indexCounts[alias] ?? 0, name: alias, privileges: { manage: false, read: false, ...indexPrivileges[name] }, - ...indexData, }); }); } @@ -191,7 +195,7 @@ export const fetchIndices = async ( const itemsToInclude = alwaysShowIndices.filter(({ name }) => indexNamesToInclude.includes(name)); const indicesData = alwaysShowSearchPattern - ? ([...regularIndexData, ...itemsToInclude] as ElasticsearchIndexWithPrivileges[]) + ? [...regularIndexData, ...itemsToInclude] : regularIndexData; return indicesData.filter( From 908a01b5a695ea50002c3a372031c90e3f37d66f Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 23 Aug 2022 13:12:19 -0700 Subject: [PATCH 40/41] Update docs for KQL autocomplete when DLS is enabled (#139248) --- docs/management/advanced-options.asciidoc | 2 +- src/plugins/data/server/ui_settings.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 7a1eaae676906..e98561ce50108 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -89,7 +89,7 @@ Set this property to `false` to prevent the filter editor and KQL autocomplete from suggesting values for fields. [[autocomplete-valuesuggestionmethod]]`autocomplete:valueSuggestionMethod`:: -When set to `terms_enum`, autocomplete uses the terms enum API for value suggestions. Kibana returns results faster, but suggestions are approximate, sorted alphabetically, and can be outside the selected time range. +When set to `terms_enum`, autocomplete uses the terms enum API for value suggestions. Kibana returns results faster, but suggestions are approximate, sorted alphabetically, and can be outside the selected time range. (Note that this API is incompatible with {ref}/document-level-security.html[Document-Level-Security].) When set to `terms_agg`, Kibana uses a terms aggregation for value suggestions, which is slower, but suggestions include all values that optionally match your time range and are sorted by popularity. diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index 31c360e761078..fce2680f5fc03 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -493,8 +493,9 @@ export function getUiSettings( description: i18n.translate('data.advancedSettings.autocompleteValueSuggestionMethodText', { defaultMessage: 'The method used for querying suggestions for values in KQL autocomplete. Select terms_enum to use the ' + - 'Elasticsearch terms enum API for improved autocomplete suggestion performance. Select terms_agg to use an ' + - 'Elasticsearch terms aggregation. {learnMoreLink}', + 'Elasticsearch terms enum API for improved autocomplete suggestion performance. (Note that terms_enum is ' + + 'incompatible with Document Level Security.) Select terms_agg to use an Elasticsearch terms aggregation. ' + + '{learnMoreLink}', values: { learnMoreLink: `
` + From fe646b297dfe79d04dbe6275c319c648b25f9c1a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 23 Aug 2022 14:21:37 -0700 Subject: [PATCH 41/41] [Security Solution][Tech debt] T-Grid cleanup (#138581) * [Security Solution][Tech debt] T-Grid cleanup: removed unused logic * Renamed folder to correspond the logic inside * Fixed types for isEventViewer * Fixed tests, corrected names * Fixed due to comments --- .../common/components/events_viewer/index.tsx | 2 - .../additional_filters_action/index.test.tsx | 80 ++++ .../additional_filters_action/index.tsx | 94 ++++ .../additional_filters_action/translations.ts | 36 ++ .../alerts_utility_bar/index.test.tsx | 419 ------------------ .../alerts_table/alerts_utility_bar/index.tsx | 284 ------------ .../alerts_utility_bar/translations.ts | 85 ---- .../components/alerts_table/index.test.tsx | 4 +- .../components/alerts_table/index.tsx | 210 +-------- .../components/take_action_dropdown/index.tsx | 2 +- .../components/graph_overlay/index.tsx | 7 +- .../public/components/t_grid/helpers.test.tsx | 22 +- .../public/components/t_grid/helpers.tsx | 25 +- .../t_grid/integrated/index.test.tsx | 3 - .../components/t_grid/integrated/index.tsx | 51 +-- .../components/t_grid/standalone/index.tsx | 48 +- .../translations/translations/fr-FR.json | 7 - .../translations/translations/ja-JP.json | 7 - .../translations/translations/zh-CN.json | 7 - 19 files changed, 259 insertions(+), 1134 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx create mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx delete mode 100644 x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index 0556b3678d4db..14921512819ee 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -61,7 +61,6 @@ export interface Props { onRuleChange?: () => void; renderCellValue: (props: CellValueElementProps) => React.ReactNode; rowRenderers: RowRenderer[]; - utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode; additionalFilters?: React.ReactNode; hasAlertsCrud?: boolean; unit?: (n: number) => string; @@ -86,7 +85,6 @@ const StatefulEventsViewerComponent: React.FC = ({ rowRenderers, start, scopeId, - utilityBar, additionalFilters, hasAlertsCrud = false, unit, diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx new file mode 100644 index 0000000000000..ec4fdb5cb6e8d --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.test.tsx @@ -0,0 +1,80 @@ +/* + * 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 { render, screen, fireEvent } from '@testing-library/react'; + +import { AdditionalFiltersAction } from '.'; +import { TestProviders } from '../../../../common/mock/test_providers'; + +jest.useFakeTimers(); +jest.mock('../../../../common/lib/kibana'); + +describe('AdditionalFiltersAction', () => { + describe('UtilityBarAdditionalFiltersContent', () => { + test('does not show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is false', async () => { + const onShowBuildingBlockAlertsChanged = jest.fn(); + render( + + + + ); + // click the filters button to popup the checkbox to make it visible + const additionalFiltersButton = screen.findByTestId('additionalFilters-popover'); + fireEvent.click(await additionalFiltersButton); + + // The check box should be false + expect(await screen.findByTestId('showBuildingBlockAlertsCheckbox')).not.toBeChecked(); + }); + + test('does not show the showOnlyThreatIndicatorAlerts checked if the showOnlyThreatIndicatorAlerts is true', async () => { + render( + + + + ); + // click the filters button to popup the checkbox to make it visible + const additionalFiltersButton = screen.findByTestId('additionalFilters-popover'); + fireEvent.click(await additionalFiltersButton); + + expect(await screen.findByTestId('showOnlyThreatIndicatorAlertsCheckbox')).toBeChecked(); + }); + + test('does show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is true', async () => { + const onShowBuildingBlockAlertsChanged = jest.fn(); + render( + + + + ); + // click the filters button to popup the checkbox to make it visible + const additionalFiltersButton = screen.findByTestId('additionalFilters-popover'); + fireEvent.click(await additionalFiltersButton); + + // The check box should be true + expect(await screen.findByTestId('showBuildingBlockAlertsCheckbox')).toBeChecked(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx new file mode 100644 index 0000000000000..ef780f783e924 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/index.tsx @@ -0,0 +1,94 @@ +/* + * 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, { useCallback } from 'react'; + +import { EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui'; +import styled from 'styled-components'; + +import { UtilityBarAction } from '../../../../common/components/utility_bar'; +import * as i18n from './translations'; + +const UtilityBarFlexGroup = styled(EuiFlexGroup)` + min-width: 175px; +`; + +const AdditionalFiltersItem = styled(EuiFlexItem)` + padding: ${({ theme }) => theme.eui.euiSizeS}; +`; + +const BuildingBlockContainer = styled(AdditionalFiltersItem)` + background: ${({ theme }) => theme.eui.euiColorHighlight}; +`; + +export const AdditionalFiltersAction = ({ + areEventsLoading, + onShowBuildingBlockAlertsChanged, + showBuildingBlockAlerts, + onShowOnlyThreatIndicatorAlertsChanged, + showOnlyThreatIndicatorAlerts, +}: { + areEventsLoading: boolean; + onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void; + showBuildingBlockAlerts: boolean; + onShowOnlyThreatIndicatorAlertsChanged: (showOnlyThreatIndicatorAlerts: boolean) => void; + showOnlyThreatIndicatorAlerts: boolean; +}) => { + const UtilityBarAdditionalFiltersContent = useCallback( + (closePopover: () => void) => ( + + + ) => { + closePopover(); + onShowBuildingBlockAlertsChanged(e.target.checked); + }} + checked={showBuildingBlockAlerts} + color="text" + data-test-subj="showBuildingBlockAlertsCheckbox" + label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK} + /> + + + ) => { + closePopover(); + onShowOnlyThreatIndicatorAlertsChanged(e.target.checked); + }} + checked={showOnlyThreatIndicatorAlerts} + color="text" + data-test-subj="showOnlyThreatIndicatorAlertsCheckbox" + label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS} + /> + + + ), + [ + onShowBuildingBlockAlertsChanged, + onShowOnlyThreatIndicatorAlertsChanged, + showBuildingBlockAlerts, + showOnlyThreatIndicatorAlerts, + ] + ); + + return ( + + {i18n.ADDITIONAL_FILTERS_ACTIONS} + + ); +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts new file mode 100644 index 0000000000000..eb421c67ff39a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/additional_filters_action/translations.ts @@ -0,0 +1,36 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export const ADDITIONAL_FILTERS_ACTIONS = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle', + { + defaultMessage: 'Additional filters', + } +); + +export const ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle', + { + defaultMessage: 'Include building block alerts', + } +); + +export const ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts', + { + defaultMessage: 'Show only threat indicator alerts', + } +); + +export const TAKE_ACTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle', + { + defaultMessage: 'Take action', + } +); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx deleted file mode 100644 index f4372631cf0f4..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.test.tsx +++ /dev/null @@ -1,419 +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 React from 'react'; -import { shallow, mount } from 'enzyme'; - -import type { AlertsUtilityBarProps } from '.'; -import { AlertsUtilityBar } from '.'; -import { TestProviders } from '../../../../common/mock/test_providers'; - -jest.useFakeTimers(); -jest.mock('../../../../common/lib/kibana'); - -describe('AlertsUtilityBar', () => { - test('renders correctly', () => { - const wrapper = shallow( - - ); - - expect(wrapper.find('[dataTestSubj="alertActionPopover"]')).toBeTruthy(); - }); - - describe('UtilityBarAdditionalFiltersContent', () => { - test('does not show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is false', () => { - const onShowBuildingBlockAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be false - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - }); - - test('does not show the showOnlyThreatIndicatorAlerts checked if the showThreatMatchOnly is false', () => { - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be false - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - }); - - test('does show the showBuildingBlockAlerts checked if the showBuildingBlockAlerts is true', () => { - const onShowBuildingBlockAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - - test('does show the showOnlyThreatIndicatorAlerts checked if the showOnlyThreatIndicatorAlerts is true', () => { - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - - test('calls the onShowBuildingBlockAlertsChanged when the check box is clicked', () => { - const onShowBuildingBlockAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // check the box - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .simulate('change', { target: { checked: true } }); - - // Make sure our callback is called - expect(onShowBuildingBlockAlertsChanged).toHaveBeenCalled(); - }); - - test('calls the onShowOnlyThreatIndicatorAlertsChanged when the check box is clicked', () => { - const onShowOnlyThreatIndicatorAlertsChanged = jest.fn(); - const wrapper = mount( - - - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // check the box - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .simulate('change', { target: { checked: true } }); - - // Make sure our callback is called - expect(onShowOnlyThreatIndicatorAlertsChanged).toHaveBeenCalled(); - }); - - test('can update showBuildingBlockAlerts from false to true', () => { - const Proxy = (props: AlertsUtilityBarProps) => ( - - - - ); - - const wrapper = mount( - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should false now since we initially set the showBuildingBlockAlerts to false - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - - wrapper.setProps({ showBuildingBlockAlerts: true }); - wrapper.update(); - - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true now since we changed the showBuildingBlockAlerts from false to true - expect( - wrapper - .find('[data-test-subj="showBuildingBlockAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - - test('can update showOnlyThreatIndicatorAlerts from false to true', () => { - const Proxy = (props: AlertsUtilityBarProps) => ( - - - - ); - - const wrapper = mount( - - ); - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should false now since we initially set the showBuildingBlockAlerts to false - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(false); - - wrapper.setProps({ showOnlyThreatIndicatorAlerts: true }); - wrapper.update(); - - // click the filters button to popup the checkbox to make it visible - wrapper - .find('[data-test-subj="additionalFilters"] button') - .first() - .simulate('click') - .update(); - - // The check box should be true now since we changed the showBuildingBlockAlerts from false to true - expect( - wrapper - .find('[data-test-subj="showOnlyThreatIndicatorAlertsCheckbox"] input') - .first() - .prop('checked') - ).toEqual(true); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx deleted file mode 100644 index 91425ab90e60b..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/index.tsx +++ /dev/null @@ -1,284 +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 { isEmpty } from 'lodash/fp'; -import React, { useCallback } from 'react'; -import numeral from '@elastic/numeral'; - -import { EuiFlexGroup, EuiFlexItem, EuiCheckbox } from '@elastic/eui'; -import styled from 'styled-components'; - -import type { Status } from '../../../../../common/detection_engine/schemas/common/schemas'; -import { Link } from '../../../../common/components/link_icon'; -import { DEFAULT_NUMBER_FORMAT } from '../../../../../common/constants'; -import { - UtilityBar, - UtilityBarAction, - UtilityBarGroup, - UtilityBarSection, - UtilityBarSpacer, - UtilityBarText, -} from '../../../../common/components/utility_bar'; -import * as i18n from './translations'; -import { useUiSetting$ } from '../../../../common/lib/kibana'; -import type { TimelineNonEcsData } from '../../../../../common/search_strategy/timeline'; -import type { UpdateAlertsStatus } from '../types'; -import { FILTER_CLOSED, FILTER_ACKNOWLEDGED, FILTER_OPEN } from '../alerts_filter_group'; - -export interface AlertsUtilityBarProps { - areEventsLoading: boolean; - clearSelection: () => void; - currentFilter: Status; - hasIndexMaintenance: boolean; - hasIndexWrite: boolean; - onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void; - onShowOnlyThreatIndicatorAlertsChanged: (showOnlyThreatIndicatorAlerts: boolean) => void; - selectAll: () => void; - selectedEventIds: Readonly>; - showBuildingBlockAlerts: boolean; - showClearSelection: boolean; - showOnlyThreatIndicatorAlerts: boolean; - totalCount: number; - updateAlertsStatus: UpdateAlertsStatus; -} - -const UtilityBarFlexGroup = styled(EuiFlexGroup)` - min-width: 175px; -`; - -const AdditionalFiltersItem = styled(EuiFlexItem)` - padding: ${({ theme }) => theme.eui.euiSizeS}; -`; - -const BuildingBlockContainer = styled(AdditionalFiltersItem)` - background: ${({ theme }) => theme.eui.euiColorHighlight}; -`; - -const AlertsUtilityBarComponent: React.FC = ({ - areEventsLoading, - clearSelection, - currentFilter, - hasIndexMaintenance, - hasIndexWrite, - onShowBuildingBlockAlertsChanged, - onShowOnlyThreatIndicatorAlertsChanged, - selectAll, - selectedEventIds, - showBuildingBlockAlerts, - showClearSelection, - showOnlyThreatIndicatorAlerts, - totalCount, - updateAlertsStatus, -}) => { - const [defaultNumberFormat] = useUiSetting$(DEFAULT_NUMBER_FORMAT); - - const handleUpdateStatus = useCallback( - async (selectedStatus: Status) => { - await updateAlertsStatus({ - alertIds: Object.keys(selectedEventIds), - status: currentFilter, - selectedStatus, - }); - }, - [currentFilter, selectedEventIds, updateAlertsStatus] - ); - - const formattedTotalCount = numeral(totalCount).format(defaultNumberFormat); - const formattedSelectedEventsCount = numeral(Object.keys(selectedEventIds).length).format( - defaultNumberFormat - ); - - const UtilityBarPopoverContent = (closePopover: () => void) => ( - - {currentFilter !== FILTER_OPEN && ( - - { - closePopover(); - handleUpdateStatus('open'); - }} - color="text" - data-test-subj="openSelectedAlertsButton" - > - {i18n.BATCH_ACTION_OPEN_SELECTED} - - - )} - - {currentFilter !== FILTER_CLOSED && ( - - { - closePopover(); - handleUpdateStatus('closed'); - }} - color="text" - data-test-subj="closeSelectedAlertsButton" - > - {i18n.BATCH_ACTION_CLOSE_SELECTED} - - - )} - - {currentFilter !== FILTER_ACKNOWLEDGED && ( - - { - closePopover(); - handleUpdateStatus('acknowledged'); - }} - color="text" - data-test-subj="markSelectedAlertsAcknowledgedButton" - > - {i18n.BATCH_ACTION_ACKNOWLEDGED_SELECTED} - - - )} - - ); - - const handleSelectAllAlertsClick = useCallback(() => { - if (!showClearSelection) { - selectAll(); - } else { - clearSelection(); - } - }, [clearSelection, selectAll, showClearSelection]); - - return ( - <> - - - - - {i18n.SHOWING_ALERTS(formattedTotalCount, totalCount)} - - - - - {hasIndexWrite && hasIndexMaintenance && ( - <> - - {i18n.SELECTED_ALERTS( - showClearSelection ? formattedTotalCount : formattedSelectedEventsCount, - showClearSelection ? totalCount : Object.keys(selectedEventIds).length - )} - - - - {i18n.TAKE_ACTION} - - - - {showClearSelection - ? i18n.CLEAR_SELECTION - : i18n.SELECT_ALL_ALERTS(formattedTotalCount, totalCount)} - - - )} - - - - - - - ); -}; - -export const AlertsUtilityBar = React.memo( - AlertsUtilityBarComponent, - (prevProps, nextProps) => - prevProps.areEventsLoading === nextProps.areEventsLoading && - prevProps.selectedEventIds === nextProps.selectedEventIds && - prevProps.totalCount === nextProps.totalCount && - prevProps.showClearSelection === nextProps.showClearSelection && - prevProps.showBuildingBlockAlerts === nextProps.showBuildingBlockAlerts && - prevProps.showOnlyThreatIndicatorAlerts === nextProps.showOnlyThreatIndicatorAlerts -); - -export const AditionalFiltersAction = ({ - areEventsLoading, - onShowBuildingBlockAlertsChanged, - showBuildingBlockAlerts, - onShowOnlyThreatIndicatorAlertsChanged, - showOnlyThreatIndicatorAlerts, -}: { - areEventsLoading: boolean; - onShowBuildingBlockAlertsChanged: (showBuildingBlockAlerts: boolean) => void; - showBuildingBlockAlerts: boolean; - onShowOnlyThreatIndicatorAlertsChanged: (showOnlyThreatIndicatorAlerts: boolean) => void; - showOnlyThreatIndicatorAlerts: boolean; -}) => { - const UtilityBarAdditionalFiltersContent = (closePopover: () => void) => ( - - - ) => { - closePopover(); - onShowBuildingBlockAlertsChanged(e.target.checked); - }} - checked={showBuildingBlockAlerts} - color="text" - data-test-subj="showBuildingBlockAlertsCheckbox" - label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK} - /> - - - ) => { - closePopover(); - onShowOnlyThreatIndicatorAlertsChanged(e.target.checked); - }} - checked={showOnlyThreatIndicatorAlerts} - color="text" - data-test-subj="showOnlyThreatIndicatorAlertsCheckbox" - label={i18n.ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS} - /> - - - ); - - return ( - - {i18n.ADDITIONAL_FILTERS_ACTIONS} - - ); -}; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts deleted file mode 100644 index 5da63a5ab9598..0000000000000 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_utility_bar/translations.ts +++ /dev/null @@ -1,85 +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 { i18n } from '@kbn/i18n'; - -export const SHOWING_ALERTS = (totalAlertsFormatted: string, totalAlerts: number) => - i18n.translate('xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle', { - values: { totalAlertsFormatted, totalAlerts }, - defaultMessage: - 'Showing {totalAlertsFormatted} {totalAlerts, plural, =1 {alert} other {alerts}}', - }); - -export const SELECTED_ALERTS = (selectedAlertsFormatted: string, selectedAlerts: number) => - i18n.translate('xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle', { - values: { selectedAlertsFormatted, selectedAlerts }, - defaultMessage: - 'Selected {selectedAlertsFormatted} {selectedAlerts, plural, =1 {alert} other {alerts}}', - }); - -export const SELECT_ALL_ALERTS = (totalAlertsFormatted: string, totalAlerts: number) => - i18n.translate('xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle', { - values: { totalAlertsFormatted, totalAlerts }, - defaultMessage: - 'Select all {totalAlertsFormatted} {totalAlerts, plural, =1 {alert} other {alerts}}', - }); - -export const ADDITIONAL_FILTERS_ACTIONS = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle', - { - defaultMessage: 'Additional filters', - } -); - -export const ADDITIONAL_FILTERS_ACTIONS_SHOW_BUILDING_BLOCK = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle', - { - defaultMessage: 'Include building block alerts', - } -); - -export const ADDITIONAL_FILTERS_ACTIONS_SHOW_ONLY_THREAT_INDICATOR_ALERTS = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts', - { - defaultMessage: 'Show only threat indicator alerts', - } -); - -export const CLEAR_SELECTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle', - { - defaultMessage: 'Clear selection', - } -); - -export const TAKE_ACTION = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle', - { - defaultMessage: 'Take action', - } -); - -export const BATCH_ACTION_OPEN_SELECTED = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle', - { - defaultMessage: 'Open selected', - } -); - -export const BATCH_ACTION_CLOSE_SELECTED = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle', - { - defaultMessage: 'Close selected', - } -); - -export const BATCH_ACTION_ACKNOWLEDGED_SELECTED = i18n.translate( - 'xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle', - { - defaultMessage: 'Mark as acknowledged', - } -); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx index 304f0ac180821..34378594a952d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.test.tsx @@ -33,13 +33,11 @@ describe('AlertsTableComponent', () => { loadingEventIds={[]} selectedEventIds={{}} isSelectAllChecked={false} - clearSelected={jest.fn()} - setEventsLoading={jest.fn()} - setEventsDeleted={jest.fn()} showBuildingBlockAlerts={false} onShowBuildingBlockAlertsChanged={jest.fn()} showOnlyThreatIndicatorAlerts={false} onShowOnlyThreatIndicatorAlertsChanged={jest.fn()} + dispatch={jest.fn()} /> ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 9c11f4499db95..d4dead20989a6 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -6,22 +6,15 @@ */ import { isEmpty } from 'lodash/fp'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo } from 'react'; import type { ConnectedProps } from 'react-redux'; import { connect, useDispatch } from 'react-redux'; -import type { Dispatch } from 'redux'; import type { Filter } from '@kbn/es-query'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; import type { Status } from '../../../../common/detection_engine/schemas/common/schemas'; import type { RowRendererId, TimelineIdLiteral } from '../../../../common/types/timeline'; import { StatefulEventsViewer } from '../../../common/components/events_viewer'; -import { - displayErrorToast, - displaySuccessToast, - useStateToaster, -} from '../../../common/components/toasters'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; -import { useAppToasts } from '../../../common/hooks/use_app_toasts'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; import { defaultCellActions } from '../../../common/lib/cell_actions/default_cell_actions'; @@ -29,7 +22,6 @@ import { useKibana } from '../../../common/lib/kibana'; import type { inputsModel, State } from '../../../common/store'; import { inputsSelectors } from '../../../common/store'; import { SourcererScopeName } from '../../../common/store/sourcerer/model'; -import * as i18nCommon from '../../../common/translations'; import { DEFAULT_COLUMN_MIN_WIDTH } from '../../../timelines/components/timeline/body/constants'; import { getDefaultControlColumn } from '../../../timelines/components/timeline/body/control_columns'; import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; @@ -38,8 +30,7 @@ import { timelineActions, timelineSelectors } from '../../../timelines/store/tim import { timelineDefaults } from '../../../timelines/store/timeline/defaults'; import type { TimelineModel } from '../../../timelines/store/timeline/model'; import { columns, RenderCellValue } from '../../configurations/security_solution_detections'; -import { updateAlertStatusAction } from './actions'; -import { AditionalFiltersAction, AlertsUtilityBar } from './alerts_utility_bar'; +import { AdditionalFiltersAction } from './additional_filters_action'; import { alertsDefaultModel, buildAlertStatusFilter, @@ -47,13 +38,6 @@ import { } from './default_config'; import { buildTimeRangeFilter } from './helpers'; import * as i18n from './translations'; -import type { - SetEventsDeletedProps, - SetEventsLoadingProps, - UpdateAlertsStatusCallback, - UpdateAlertsStatusProps, -} from './types'; - interface OwnProps { defaultFilters?: Filter[]; from: string; @@ -73,7 +57,6 @@ interface OwnProps { type AlertsTableComponentProps = OwnProps & PropsFromRedux; export const AlertsTableComponent: React.FC = ({ - clearSelected, defaultFilters, from, globalFilters, @@ -86,9 +69,6 @@ export const AlertsTableComponent: React.FC = ({ onRuleChange, onShowBuildingBlockAlertsChanged, onShowOnlyThreatIndicatorAlertsChanged, - selectedEventIds, - setEventsDeleted, - setEventsLoading, showBuildingBlockAlerts, showOnlyThreatIndicatorAlerts, timelineId, @@ -96,15 +76,12 @@ export const AlertsTableComponent: React.FC = ({ filterGroup = 'open', }) => { const dispatch = useDispatch(); - const [showClearSelectionAction, setShowClearSelectionAction] = useState(false); const { browserFields, indexPattern: indexPatterns, selectedPatterns, } = useSourcererDataView(SourcererScopeName.detections); const kibana = useKibana(); - const [, dispatchToaster] = useStateToaster(); - const { addWarning } = useAppToasts(); const ACTION_BUTTON_COUNT = 5; const getGlobalQuery = useCallback( @@ -123,7 +100,6 @@ export const AlertsTableComponent: React.FC = ({ ], kqlQuery: globalQuery, kqlMode: globalQuery.language, - isEventViewer: true, }); } return null; @@ -140,66 +116,6 @@ export const AlertsTableComponent: React.FC = ({ endDate: to, }); - const setEventsLoadingCallback = useCallback( - ({ eventIds, isLoading }: SetEventsLoadingProps) => { - setEventsLoading({ id: timelineId, eventIds, isLoading }); - }, - [setEventsLoading, timelineId] - ); - - const setEventsDeletedCallback = useCallback( - ({ eventIds, isDeleted }: SetEventsDeletedProps) => { - setEventsDeleted({ id: timelineId, eventIds, isDeleted }); - }, - [setEventsDeleted, timelineId] - ); - - const onAlertStatusUpdateSuccess = useCallback( - (updated: number, conflicts: number, status: Status) => { - if (conflicts > 0) { - // Partial failure - addWarning({ - title: i18nCommon.UPDATE_ALERT_STATUS_FAILED(conflicts), - text: i18nCommon.UPDATE_ALERT_STATUS_FAILED_DETAILED(updated, conflicts), - }); - } else { - let title = ''; - switch (status) { - case 'closed': - title = i18n.CLOSED_ALERT_SUCCESS_TOAST(updated); - break; - case 'open': - title = i18n.OPENED_ALERT_SUCCESS_TOAST(updated); - break; - case 'acknowledged': - case 'in-progress': - title = i18n.ACKNOWLEDGED_ALERT_SUCCESS_TOAST(updated); - } - displaySuccessToast(title, dispatchToaster); - } - }, - [addWarning, dispatchToaster] - ); - - const onAlertStatusUpdateFailure = useCallback( - (status: Status, error: Error) => { - let title = ''; - switch (status) { - case 'closed': - title = i18n.CLOSED_ALERT_FAILED_TOAST; - break; - case 'open': - title = i18n.OPENED_ALERT_FAILED_TOAST; - break; - case 'acknowledged': - case 'in-progress': - title = i18n.ACKNOWLEDGED_ALERT_FAILED_TOAST; - } - displayErrorToast(title, [error.message], dispatchToaster); - }, - [dispatchToaster] - ); - // Catches state change isSelectAllChecked->false upon user selection change to reset utility bar useEffect(() => { if (isSelectAllChecked) { @@ -209,107 +125,12 @@ export const AlertsTableComponent: React.FC = ({ selectAll: false, }) ); - } else { - setShowClearSelectionAction(false); } }, [dispatch, isSelectAllChecked, timelineId]); - // Callback for clearing entire selection from utility bar - const clearSelectionCallback = useCallback(() => { - clearSelected({ id: timelineId }); - dispatch( - timelineActions.setTGridSelectAll({ - id: timelineId, - selectAll: false, - }) - ); - setShowClearSelectionAction(false); - }, [clearSelected, dispatch, timelineId]); - - // Callback for selecting all events on all pages from utility bar - // Dispatches to stateful_body's selectAll via TimelineTypeContext props - // as scope of response data required to actually set selectedEvents - const selectAllOnAllPagesCallback = useCallback(() => { - dispatch( - timelineActions.setTGridSelectAll({ - id: timelineId, - selectAll: true, - }) - ); - setShowClearSelectionAction(true); - }, [dispatch, timelineId]); - - const updateAlertsStatusCallback: UpdateAlertsStatusCallback = useCallback( - async ( - refetchQuery: inputsModel.Refetch, - { status, selectedStatus }: UpdateAlertsStatusProps - ) => { - await updateAlertStatusAction({ - query: showClearSelectionAction - ? getGlobalQuery(buildAlertStatusFilter(status))?.filterQuery - : undefined, - alertIds: Object.keys(selectedEventIds), - selectedStatus, - setEventsDeleted: setEventsDeletedCallback, - setEventsLoading: setEventsLoadingCallback, - onAlertStatusUpdateSuccess, - onAlertStatusUpdateFailure, - }); - refetchQuery(); - }, - [ - getGlobalQuery, - selectedEventIds, - setEventsDeletedCallback, - setEventsLoadingCallback, - showClearSelectionAction, - onAlertStatusUpdateSuccess, - onAlertStatusUpdateFailure, - ] - ); - - // Callback for creating the AlertsUtilityBar which receives totalCount from EventsViewer component - const utilityBarCallback = useCallback( - (refetchQuery: inputsModel.Refetch, totalCount: number) => { - return ( - 0} - clearSelection={clearSelectionCallback} - currentFilter={filterGroup} - hasIndexMaintenance={hasIndexMaintenance} - hasIndexWrite={hasIndexWrite} - onShowBuildingBlockAlertsChanged={onShowBuildingBlockAlertsChanged} - onShowOnlyThreatIndicatorAlertsChanged={onShowOnlyThreatIndicatorAlertsChanged} - selectAll={selectAllOnAllPagesCallback} - selectedEventIds={selectedEventIds} - showBuildingBlockAlerts={showBuildingBlockAlerts} - showClearSelection={showClearSelectionAction} - showOnlyThreatIndicatorAlerts={showOnlyThreatIndicatorAlerts} - totalCount={totalCount} - updateAlertsStatus={updateAlertsStatusCallback.bind(null, refetchQuery)} - /> - ); - }, - [ - clearSelectionCallback, - filterGroup, - hasIndexMaintenance, - hasIndexWrite, - loadingEventIds.length, - onShowBuildingBlockAlertsChanged, - onShowOnlyThreatIndicatorAlertsChanged, - selectAllOnAllPagesCallback, - selectedEventIds, - showBuildingBlockAlerts, - showClearSelectionAction, - showOnlyThreatIndicatorAlerts, - updateAlertsStatusCallback, - ] - ); - const additionalFiltersComponent = useMemo( () => ( - 0} onShowBuildingBlockAlertsChanged={onShowBuildingBlockAlertsChanged} showBuildingBlockAlerts={showBuildingBlockAlerts} @@ -387,7 +208,6 @@ export const AlertsTableComponent: React.FC = ({ rowRenderers={defaultRowRenderers} scopeId={SourcererScopeName.detections} start={from} - utilityBar={utilityBarCallback} /> ); }; @@ -414,29 +234,7 @@ const makeMapStateToProps = () => { return mapStateToProps; }; -const mapDispatchToProps = (dispatch: Dispatch) => ({ - clearSelected: ({ id }: { id: string }) => dispatch(timelineActions.clearSelected({ id })), - setEventsLoading: ({ - id, - eventIds, - isLoading, - }: { - id: string; - eventIds: string[]; - isLoading: boolean; - }) => dispatch(timelineActions.setEventsLoading({ id, eventIds, isLoading })), - setEventsDeleted: ({ - id, - eventIds, - isDeleted, - }: { - id: string; - eventIds: string[]; - isDeleted: boolean; - }) => dispatch(timelineActions.setEventsDeleted({ id, eventIds, isDeleted })), -}); - -const connector = connect(makeMapStateToProps, mapDispatchToProps); +const connector = connect(makeMapStateToProps); type PropsFromRedux = ConnectedProps; diff --git a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx index ea66ebb132d8a..197d655d2420b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/take_action_dropdown/index.tsx @@ -10,7 +10,7 @@ import { EuiButton, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import type { ExceptionListType } from '@kbn/securitysolution-io-ts-list-types'; import { useResponderActionItem } from '../endpoint_responder'; import type { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; -import { TAKE_ACTION } from '../alerts_table/alerts_utility_bar/translations'; +import { TAKE_ACTION } from '../alerts_table/additional_filters_action/translations'; import { useExceptionActions } from '../alerts_table/timeline_actions/use_add_exception_actions'; import { useAlertsActions } from '../alerts_table/timeline_actions/use_alerts_actions'; import { useInvestigateInTimeline } from '../alerts_table/timeline_actions/use_investigate_in_timeline'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx index 6ecaa56bc12db..681de8ac4cb0c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx @@ -84,11 +84,8 @@ const GraphOverlayComponent: React.FC = ({ const { timelineFullScreen } = useTimelineFullScreen(); const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const graphEventId = useDeepEqualSelector( - (state) => (getTimeline(state, timelineId) ?? timelineDefaults).graphEventId - ); - const sessionViewConfig = useDeepEqualSelector( - (state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewConfig + const { graphEventId, sessionViewConfig } = useDeepEqualSelector( + (state) => getTimeline(state, timelineId) ?? timelineDefaults ); const fullScreen = useMemo( diff --git a/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx index 535c856d51e8f..7d60cbc5d0e00 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/helpers.test.tsx @@ -225,7 +225,7 @@ describe('Combined Queries', () => { ignoreFilterIfFieldNotInIndex: true, dateFormatTZ: 'America/New_York', }; - test('No Data Provider & No kqlQuery & and isEventViewer is false', () => { + test('No Data Provider & No kqlQuery', () => { expect( combineQueries({ config, @@ -239,26 +239,7 @@ describe('Combined Queries', () => { ).toBeNull(); }); - test('No Data Provider & No kqlQuery & isEventViewer is true', () => { - const isEventViewer = true; - expect( - combineQueries({ - config, - dataProviders: [], - indexPattern: mockIndexPattern, - browserFields: mockBrowserFields, - filters: [], - kqlQuery: { query: '', language: 'kuery' }, - kqlMode: 'search', - isEventViewer, - }) - ).toEqual({ - filterQuery: '{"bool":{"must":[],"filter":[],"should":[],"must_not":[]}}', - }); - }); - test('No Data Provider & No kqlQuery & with Filters', () => { - const isEventViewer = true; expect( combineQueries({ config, @@ -293,7 +274,6 @@ describe('Combined Queries', () => { ], kqlQuery: { query: '', language: 'kuery' }, kqlMode: 'search', - isEventViewer, }) ).toEqual({ filterQuery: diff --git a/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx b/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx index 03830339761bc..34fb215e708d5 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/helpers.tsx @@ -141,7 +141,6 @@ interface CombineQueries { filters: Filter[]; kqlQuery: Query; kqlMode: string; - isEventViewer?: boolean; } export const combineQueries = ({ @@ -152,23 +151,10 @@ export const combineQueries = ({ filters = [], kqlQuery, kqlMode, - isEventViewer, }: CombineQueries): { filterQuery: string | undefined; kqlError: Error | undefined } | null => { const kuery: Query = { query: '', language: kqlQuery.language }; - if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters) && !isEventViewer) { + if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEmpty(filters)) { return null; - } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && isEventViewer) { - const [filterQuery, kqlError] = convertToBuildEsQuery({ - config, - queries: [kuery], - indexPattern, - filters, - }); - - return { - filterQuery, - kqlError, - }; } else if (isEmpty(dataProviders) && isEmpty(kqlQuery.query) && !isEmpty(filters)) { const [filterQuery, kqlError] = convertToBuildEsQuery({ config, @@ -229,15 +215,6 @@ export const combineQueries = ({ }; }; -export const buildCombinedQuery = (combineQueriesParams: CombineQueries) => { - const combinedQuery = combineQueries(combineQueriesParams); - return combinedQuery?.filterQuery - ? { - filterQuery: combinedQuery.filterQuery, - } - : null; -}; - export const buildTimeRangeFilter = (from: string, to: string): Filter => ({ range: { diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx index 15fd4d2ce75cf..d33d2fb5635b8 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.test.tsx @@ -41,9 +41,6 @@ jest.mock('../helpers', () => { filter: [], }, }), - buildCombinedQuery: () => ({ - filterQuery: '{"bool":{"must":[],"filter":[]}}', - }), }; }); const defaultProps: TGridIntegratedProps = tGridIntegratedProps; diff --git a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx index 7183c164a24be..898611d073a95 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/integrated/index.tsx @@ -39,7 +39,7 @@ import type { import { useDeepEqualSelector } from '../../../hooks/use_selector'; import { defaultHeaders } from '../body/column_headers/default_headers'; -import { buildCombinedQuery, getCombinedFilterQuery, resolverIsShowing } from '../helpers'; +import { getCombinedFilterQuery, resolverIsShowing } from '../helpers'; import { tGridActions, tGridSelectors } from '../../../store/t_grid'; import { useTimelineEvents, InspectResponse, Refetch } from '../../../container'; import { StatefulBody } from '../body'; @@ -194,26 +194,32 @@ const TGridIntegratedComponent: React.FC = ({ }, [dispatch, id, isQueryLoading]); const justTitle = useMemo(() => {title}, [title]); + const esQueryConfig = getEsQueryConfig(uiSettings); - const combinedQueries = buildCombinedQuery({ - config: getEsQueryConfig(uiSettings), - dataProviders, - indexPattern, - browserFields, - filters, - kqlQuery: query, - kqlMode, - isEventViewer: true, - }); + const filterQuery = useMemo( + () => + getCombinedFilterQuery({ + config: esQueryConfig, + browserFields, + dataProviders, + filters, + from: start, + indexPattern, + kqlMode, + kqlQuery: query, + to: end, + }), + [esQueryConfig, dataProviders, indexPattern, browserFields, filters, start, end, query, kqlMode] + ); const canQueryTimeline = useMemo( () => - combinedQueries != null && + filterQuery != null && isLoadingIndexPattern != null && !isLoadingIndexPattern && !isEmpty(start) && !isEmpty(end), - [isLoadingIndexPattern, combinedQueries, start, end] + [isLoadingIndexPattern, filterQuery, start, end] ); const fields = useMemo( @@ -241,7 +247,7 @@ const TGridIntegratedComponent: React.FC = ({ endDate: end, entityType, fields, - filterQuery: combinedQueries?.filterQuery, + filterQuery, id, indexNames, limit: itemsPerPage, @@ -251,23 +257,6 @@ const TGridIntegratedComponent: React.FC = ({ startDate: start, }); - const filterQuery = useMemo( - () => - getCombinedFilterQuery({ - config: getEsQueryConfig(uiSettings), - browserFields, - dataProviders, - filters, - from: start, - indexPattern, - isEventViewer: true, - kqlMode, - kqlQuery: query, - to: end, - }), - [uiSettings, dataProviders, indexPattern, browserFields, filters, start, end, query, kqlMode] - ); - const totalCountMinusDeleted = useMemo( () => (totalCount > 0 ? totalCount - deletedEventIds.length : 0), [deletedEventIds.length, totalCount] diff --git a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx index 1eb327d95827a..14a03e8bd5049 100644 --- a/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx +++ b/x-pack/plugins/timelines/public/components/t_grid/standalone/index.tsx @@ -30,7 +30,7 @@ import type { } from '../../../../common/types/timeline'; import { useDeepEqualSelector } from '../../../hooks/use_selector'; import { defaultHeaders } from '../body/column_headers/default_headers'; -import { combineQueries, getCombinedFilterQuery } from '../helpers'; +import { getCombinedFilterQuery } from '../helpers'; import { tGridActions, tGridSelectors } from '../../../store/t_grid'; import type { State } from '../../../store/t_grid'; import { useTimelineEvents } from '../../../container'; @@ -170,25 +170,32 @@ const TGridStandaloneComponent: React.FC = ({ }, [dispatch, isQueryLoading]); const justTitle = useMemo(() => {title}, [title]); + const esQueryConfig = getEsQueryConfig(uiSettings); - const combinedQueries = useMemo( + const filterQuery = useMemo( () => - combineQueries({ - config: getEsQueryConfig(uiSettings), - dataProviders: EMPTY_DATA_PROVIDERS, - indexPattern: indexPatterns, + getCombinedFilterQuery({ + config: esQueryConfig, browserFields, + dataProviders: EMPTY_DATA_PROVIDERS, filters, - kqlQuery: query, + from: start, + indexPattern: indexPatterns, kqlMode: 'search', - isEventViewer: true, + kqlQuery: query, + to: end, }), - [uiSettings, indexPatterns, browserFields, filters, query] + [esQueryConfig, indexPatterns, browserFields, filters, start, end, query] ); const canQueryTimeline = useMemo( - () => !indexPatternsLoading && combinedQueries != null && !isEmpty(start) && !isEmpty(end), - [indexPatternsLoading, combinedQueries, start, end] + () => + filterQuery != null && + indexPatternsLoading != null && + !indexPatternsLoading && + !isEmpty(start) && + !isEmpty(end), + [indexPatternsLoading, filterQuery, start, end] ); const fields = useMemo( @@ -221,7 +228,7 @@ const TGridStandaloneComponent: React.FC = ({ entityType, excludeEcsData: true, fields, - filterQuery: combinedQueries?.filterQuery, + filterQuery, id: STANDALONE_ID, indexNames, limit: itemsPerPageStore, @@ -266,23 +273,6 @@ const TGridStandaloneComponent: React.FC = ({ [deletedEventIds, events] ); - const filterQuery = useMemo( - () => - getCombinedFilterQuery({ - config: getEsQueryConfig(uiSettings), - dataProviders: EMPTY_DATA_PROVIDERS, - indexPattern: indexPatterns, - browserFields, - filters, - kqlQuery: query, - kqlMode: 'search', - isEventViewer: true, - from: start, - to: end, - }), - [uiSettings, indexPatterns, browserFields, filters, query, start, end] - ); - useEffect(() => { setIsQueryLoading(loading); }, [loading]); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0b2b72de83099..d7053e47a137a 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -25285,9 +25285,6 @@ "xpack.securitySolution.detectionEngine.alerts.histogram.showingAlertsTitle": "Affichage de : {modifier}{totalAlertsFormatted} {totalAlerts, plural, =1 {alerte} other {alertes}}", "xpack.securitySolution.detectionEngine.alerts.histogram.topNLabel": "Premiers {fieldName}", "xpack.securitySolution.detectionEngine.alerts.openedAlertSuccessToastMessage": "Ouverture réussie de {totalAlerts} {totalAlerts, plural, =1 {alerte} other {alertes}}.", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle": "Sélectionner un total de {totalAlertsFormatted} {totalAlerts, plural, =1 {alerte} other {alertes}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle": "{selectedAlertsFormatted} {selectedAlerts, plural, =1 {alerte} other {alertes}} sélectionnée(s)", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle": "Affichage de {totalAlertsFormatted} {totalAlerts, plural, =1 {alerte} other {alertes}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "Modifier {customRulesCount, plural, =1 {# règle personnalisée} other {# règles personnalisées}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setIndexPatternsWarningCallout": "Vous êtes sur le point d'écraser les modèles d'indexation pour {rulesCount, plural, one {# règle sélectionnée} other {# règles sélectionnées}}. Sélectionnez Enregistrer pour appliquer les modifications.", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "Vous êtes sur le point d'écraser les balises pour {rulesCount, plural, one {# règle sélectionnée} other {# règles sélectionnées}}. Sélectionnez Enregistrer pour appliquer les modifications.", @@ -26167,10 +26164,6 @@ "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle": "Inclure les alertes fondamentales", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts": "Afficher uniquement les alertes d'indicateur de menaces", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle": "Filtres supplémentaires", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle": "Marquer comme reconnue", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle": "Fermer la sélection", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle": "Ouvrir la sélection", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle": "Effacer la sélection", "xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle": "Entreprendre une action", "xpack.securitySolution.detectionEngine.alertTitle": "Alertes", "xpack.securitySolution.detectionEngine.buttonManageRules": "Gérer les règles", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 0e8650985261d..f5361e3c867bd 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -25264,9 +25264,6 @@ "xpack.securitySolution.detectionEngine.alerts.histogram.showingAlertsTitle": "{modifier}{totalAlertsFormatted} {totalAlerts, plural, other {件のアラート}}を表示しています", "xpack.securitySolution.detectionEngine.alerts.histogram.topNLabel": "トップ{fieldName}", "xpack.securitySolution.detectionEngine.alerts.openedAlertSuccessToastMessage": "{totalAlerts} {totalAlerts, plural, other {件のアラート}}を正常に開きました。", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle": "すべての{totalAlertsFormatted} {totalAlerts, plural, other {件のアラート}}を選択", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle": "Selected {selectedAlertsFormatted} {selectedAlerts, plural, other {件のアラート}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle": "すべての{totalAlertsFormatted} {totalAlerts, plural, other {件のアラート}}を表示しています", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "{customRulesCount, plural, other {# 個のカスタムルール}}を編集", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setIndexPatternsWarningCallout": "{rulesCount, plural, other {# 個の選択したルール}} のインデックスパターンを上書きしようとしています。[保存]をクリックすると、変更が適用されます。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "{rulesCount, plural, other {# 個の選択したルール}}のタグを上書きしようとしています。[保存]をクリックすると、変更が適用されます。\n", @@ -26144,10 +26141,6 @@ "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle": "基本アラートを含める", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts": "脅威インジケーターアラートのみを表示", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle": "追加のフィルター", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle": "確認済みに設定", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle": "選択した項目を閉じる", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle": "選択した項目を開く", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle": "選択した項目をクリア", "xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle": "アクションを実行", "xpack.securitySolution.detectionEngine.alertTitle": "アラート", "xpack.securitySolution.detectionEngine.buttonManageRules": "ルールの管理", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 650d9f9b89da3..3082af48e77af 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -25293,9 +25293,6 @@ "xpack.securitySolution.detectionEngine.alerts.histogram.showingAlertsTitle": "正在显示:{modifier}{totalAlertsFormatted} 个{totalAlerts, plural, other {告警}}", "xpack.securitySolution.detectionEngine.alerts.histogram.topNLabel": "排名靠前的{fieldName}", "xpack.securitySolution.detectionEngine.alerts.openedAlertSuccessToastMessage": "已成功打开 {totalAlerts} 个{totalAlerts, plural, other {告警}}。", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectAllAlertsTitle": "选择全部 {totalAlertsFormatted} 个{totalAlerts, plural, other {告警}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.selectedAlertsTitle": "已选择 {selectedAlertsFormatted} 个{selectedAlerts, plural, other {告警}}", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.showingAlertsTitle": "正在显示 {totalAlertsFormatted} 个{totalAlerts, plural, other {告警}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditConfirmation.confirmButtonLabel": "编辑 {customRulesCount, plural, other {# 个定制规则}}", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setIndexPatternsWarningCallout": "您即将覆盖 {rulesCount, plural, other {# 个选定规则}}的索引模式,按“保存”可应用更改。", "xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.setTagsWarningCallout": "您即将覆盖 {rulesCount, plural, other {# 个选定规则}}的标签,按“保存”可应用更改。", @@ -26175,10 +26172,6 @@ "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showBuildingBlockTitle": "包括构建块告警", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersActions.showOnlyThreatIndicatorAlerts": "仅显示威胁指标告警", "xpack.securitySolution.detectionEngine.alerts.utilityBar.additionalFiltersTitle": "其他筛选", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.acknowledgedSelectedTitle": "标记为已确认", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.closeSelectedTitle": "关闭所选", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.batchActions.openSelectedTitle": "打开所选", - "xpack.securitySolution.detectionEngine.alerts.utilityBar.clearSelectionTitle": "清除所选内容", "xpack.securitySolution.detectionEngine.alerts.utilityBar.takeActionTitle": "采取操作", "xpack.securitySolution.detectionEngine.alertTitle": "告警", "xpack.securitySolution.detectionEngine.buttonManageRules": "管理规则",