diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index cc574b7a74c85..6aefc30411141 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -91,9 +91,6 @@ disabled: - x-pack/test_serverless/api_integration/test_suites/security/config.feature_flags.ts - x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts - # Failing: See https://github.com/elastic/kibana/issues/174020 - - x-pack/test/api_integration/apis/asset_manager/config_when_enabled.ts - defaultQueue: 'n2-4-spot' enabled: - test/accessibility/config.ts @@ -188,6 +185,7 @@ enabled: - x-pack/test/api_integration/config_security_trial.ts - x-pack/test/api_integration/apis/aiops/config.ts - x-pack/test/api_integration/apis/asset_manager/config_when_disabled.ts + - x-pack/test/api_integration/apis/asset_manager/config_when_enabled.ts - x-pack/test/api_integration/apis/cases/config.ts - x-pack/test/api_integration/apis/cloud_security_posture/config.ts - x-pack/test/api_integration/apis/console/config.ts @@ -459,6 +457,7 @@ enabled: - x-pack/performance/journeys/tags_listing_page.ts - x-pack/performance/journeys/cloud_security_dashboard.ts - x-pack/performance/journeys/apm_service_inventory.ts + - x-pack/performance/journeys/infra_hosts_view.ts - x-pack/test/custom_branding/config.ts - x-pack/test/profiling_api_integration/cloud/config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/exceptions/workflows/configs/serverless.config.ts diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml index 7cdc07ec861f2..a1de7f41a2100 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml @@ -27,6 +27,11 @@ steps: - label: ":cookie: 24h bake time before continuing promotion" if: build.env("ENVIRONMENT") == "production-canary" command: "sleep 86400" + soft_fail: + # A manual cancel of that step produces return code 255. + # We're treating this case as a soft fail to allow manual bake time skipping. + # To stop the promotion entirely, instead click the "Cancel" button at the top of the page + - exit_status: 255 agents: # How long can this agent live for in minutes - 25 hours instanceMaxAge: 1500 diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 4a4cd69e2aa5b..ef15d64e1daa5 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: 2024-01-12 +date: 2024-01-16 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 801fdc0dc6fdc..bce59ddcbe809 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_observability.mdx b/api_docs/ai_assistant_management_observability.mdx index 5ae7a00cf21c7..45f6c19de1412 100644 --- a/api_docs/ai_assistant_management_observability.mdx +++ b/api_docs/ai_assistant_management_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementObservability title: "aiAssistantManagementObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementObservability plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementObservability'] --- import aiAssistantManagementObservabilityObj from './ai_assistant_management_observability.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index 0687bae7fb452..30bf53e64a6cf 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index bb450834a6ee6..bdbfc23ffb260 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 94686050fa732..5b6ba7327d94b 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -3553,14 +3553,6 @@ "plugin": "infra", "path": "x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts" }, - { - "plugin": "monitoring", - "path": "x-pack/plugins/monitoring/server/alerts/base_rule.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts" diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index edf4a3f1e26fe..c954d70b23147 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: 2024-01-12 +date: 2024-01-16 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 1d4b3b8d7b3e6..05d8dc1ac48cc 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 39906bb7452f5..acfcca07b1180 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index b142f139f5ba8..42f46aa3e5fb2 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 5c89a58df37e6..0a587611207ba 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: 2024-01-12 +date: 2024-01-16 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 67999f046d8b2..da1d0bc3b8be4 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: 2024-01-12 +date: 2024-01-16 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 d995354def43e..adb0cb7568343 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: 2024-01-12 +date: 2024-01-16 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 e8e38e9848ec8..2f020ef71aabb 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: 2024-01-12 +date: 2024-01-16 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 c445ccbe6e55e..cead91ffa90a0 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: 2024-01-12 +date: 2024-01-16 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 c589b045ac910..00d0ee108c1cf 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 0dce451ea5561..df3c9d261eba5 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 8c4c2fe6c45d2..bf8cffca75b54 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index dfef6997454ca..5a8cf1363af06 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index cc07af8b97374..7a0a3ee24bb73 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: 2024-01-12 +date: 2024-01-16 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 95ba204652c04..2a22f048b8dd1 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index 0a682f92f80e0..1ebc44e6856fa 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index cc35c59230293..112130541349a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index f9e91c186da4a..8921bc1d206c8 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: 2024-01-12 +date: 2024-01-16 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 be703edda57f9..2f25b4cf22646 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: 2024-01-12 +date: 2024-01-16 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 6c8cbd63634e8..7c22a93bb3977 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: 2024-01-12 +date: 2024-01-16 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 a1bb897ebee3a..5c3bff8715f59 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -5310,6 +5310,51 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-public.AggFunctionsMapping.aggIpPrefix", + "type": "Object", + "tags": [], + "label": "aggIpPrefix", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionFunctionDefinition", + "text": "ExpressionFunctionDefinition" + }, + "<\"aggIpPrefix\", any, Arguments, ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.AggExpressionType", + "text": "AggExpressionType" + }, + ", ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExecutionContext", + "text": "ExecutionContext" + }, + "<", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + ">>" + ], + "path": "src/plugins/data/common/search/aggs/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-public.AggFunctionsMapping.aggIpRange", diff --git a/api_docs/data.mdx b/api_docs/data.mdx index c94f347fae379..bb501ccbfcf92 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3188 | 31 | 2537 | 22 | +| 3220 | 31 | 2569 | 23 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index a5c2514985eea..3265719a90495 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3188 | 31 | 2537 | 22 | +| 3220 | 31 | 2569 | 23 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index cfa083d446c5c..539ec9594e118 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -11686,6 +11686,23 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.aggIpPrefix", + "type": "Function", + "tags": [], + "label": "aggIpPrefix", + "description": [], + "signature": [ + "() => FunctionDefinition" + ], + "path": "src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.aggIpRange", @@ -14064,6 +14081,39 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.getIpPrefixBucketAgg", + "type": "Function", + "tags": [], + "label": "getIpPrefixBucketAgg", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.BucketAggType", + "text": "BucketAggType" + }, + "<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IBucketAggConfig", + "text": "IBucketAggConfig" + }, + ">" + ], + "path": "src/plugins/data/common/search/aggs/buckets/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.getIpRangeBucketAgg", @@ -15499,6 +15549,60 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixToAst", + "type": "Function", + "tags": [], + "label": "ipPrefixToAst", + "description": [], + "signature": [ + "(ipPrefix: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefix", + "text": "IpPrefix" + }, + ") => ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionAstExpression", + "text": "ExpressionAstExpression" + } + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix_to_ast.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.ipPrefixToAst.$1", + "type": "Object", + "tags": [], + "label": "ipPrefix", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefix", + "text": "IpPrefix" + } + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix_to_ast.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.ipRangeToAst", @@ -17362,6 +17466,51 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-common.AggFunctionsMapping.aggIpPrefix", + "type": "Object", + "tags": [], + "label": "aggIpPrefix", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionFunctionDefinition", + "text": "ExpressionFunctionDefinition" + }, + "<\"aggIpPrefix\", any, Arguments, ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.AggExpressionType", + "text": "AggExpressionType" + }, + ", ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExecutionContext", + "text": "ExecutionContext" + }, + "<", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + ">>" + ], + "path": "src/plugins/data/common/search/aggs/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-common.AggFunctionsMapping.aggIpRange", @@ -21051,6 +21200,69 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.AggParamsIpPrefix", + "type": "Interface", + "tags": [], + "label": "AggParamsIpPrefix", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.AggParamsIpPrefix", + "text": "AggParamsIpPrefix" + }, + " extends ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.BaseAggParams", + "text": "BaseAggParams" + } + ], + "path": "src/plugins/data/common/search/aggs/buckets/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.AggParamsIpPrefix.field", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "path": "src/plugins/data/common/search/aggs/buckets/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.AggParamsIpPrefix.ipPrefix", + "type": "Object", + "tags": [], + "label": "ipPrefix", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefix", + "text": "IpPrefix" + }, + " | undefined" + ], + "path": "src/plugins/data/common/search/aggs/buckets/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.AggParamsIpRange", @@ -21175,6 +21387,26 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-common.AggParamsMapping.BUCKET_TYPES.IP_PREFIX", + "type": "Object", + "tags": [], + "label": "[BUCKET_TYPES.IP_PREFIX]", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.AggParamsIpPrefix", + "text": "AggParamsIpPrefix" + } + ], + "path": "src/plugins/data/common/search/aggs/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-common.AggParamsMapping.BUCKET_TYPES.IP_RANGE", @@ -27547,6 +27779,48 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.IpPrefix", + "type": "Interface", + "tags": [], + "label": "IpPrefix", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.IpPrefix.prefixLength", + "type": "number", + "tags": [], + "label": "prefixLength", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.IpPrefix.isIpv6", + "type": "CompoundType", + "tags": [], + "label": "isIpv6", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.IpRange", @@ -30689,6 +30963,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.aggIpPrefixFnName", + "type": "string", + "tags": [], + "label": "aggIpPrefixFnName", + "description": [], + "signature": [ + "\"aggIpPrefix\"" + ], + "path": "src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.aggIpRangeFnName", @@ -32099,6 +32388,60 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.ExpressionFunctionIpPrefix", + "type": "Type", + "tags": [], + "label": "ExpressionFunctionIpPrefix", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionFunctionDefinition", + "text": "ExpressionFunctionDefinition" + }, + "<\"ipPrefix\", null, ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefix", + "text": "IpPrefix" + }, + ", ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefixOutput", + "text": "IpPrefixOutput" + }, + ", ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExecutionContext", + "text": "ExecutionContext" + }, + "<", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + ">>" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.ExpressionFunctionIpRange", @@ -33215,6 +33558,43 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.IpPrefixKey", + "type": "Type", + "tags": [], + "label": "IpPrefixKey", + "description": [], + "signature": [ + "IpPrefixAggKey" + ], + "path": "src/plugins/data/common/search/aggs/buckets/lib/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "data", + "id": "def-common.IpPrefixOutput", + "type": "Type", + "tags": [], + "label": "IpPrefixOutput", + "description": [], + "signature": [ + "{ type: \"ip_prefix\"; } & ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefix", + "text": "IpPrefix" + } + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.IpRangeKey", @@ -36509,6 +36889,223 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction", + "type": "Object", + "tags": [], + "label": "ipPrefixFunction", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "\"ipPrefix\"" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "\"ip_prefix\"" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.inputTypes", + "type": "Array", + "tags": [], + "label": "inputTypes", + "description": [], + "signature": [ + "\"null\"[]" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.help", + "type": "string", + "tags": [], + "label": "help", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.args", + "type": "Object", + "tags": [], + "label": "args", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.args.prefixLength", + "type": "Object", + "tags": [], + "label": "prefixLength", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.args.prefixLength.types", + "type": "Array", + "tags": [], + "label": "types", + "description": [], + "signature": [ + "\"number\"[]" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.args.prefixLength.help", + "type": "string", + "tags": [], + "label": "help", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.args.isIpv6", + "type": "Object", + "tags": [], + "label": "isIpv6", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.args.isIpv6.types", + "type": "Array", + "tags": [], + "label": "types", + "description": [], + "signature": [ + "\"boolean\"[]" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.args.isIpv6.help", + "type": "string", + "tags": [], + "label": "help", + "description": [], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ] + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.fn", + "type": "Function", + "tags": [], + "label": "fn", + "description": [], + "signature": [ + "(input: null, { prefixLength, isIpv6 }: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefix", + "text": "IpPrefix" + }, + ") => { type: \"ip_prefix\"; prefixLength: number | undefined; isIpv6: boolean | undefined; }" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.fn.$1", + "type": "Uncategorized", + "tags": [], + "label": "input", + "description": [], + "signature": [ + "null" + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "data", + "id": "def-common.ipPrefixFunction.fn.$2", + "type": "Object", + "tags": [], + "label": "{ prefixLength, isIpv6 }", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.IpPrefix", + "text": "IpPrefix" + } + ], + "path": "src/plugins/data/common/search/expressions/ip_prefix.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.ipRangeFunction", diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 400d5aade46ab..fdae1425a8a7a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3188 | 31 | 2537 | 22 | +| 3220 | 31 | 2569 | 23 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 41b6482d59b35..e58b239c5bab7 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: 2024-01-12 +date: 2024-01-16 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 3327f25079833..3708bf74874a8 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: 2024-01-12 +date: 2024-01-16 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 c264c23204640..88518c4396a25 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: 2024-01-12 +date: 2024-01-16 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 e862b0c6e544e..b7a69eaab7a97 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: 2024-01-12 +date: 2024-01-16 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 48949dfa589b8..457d5251cf5fc 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index a3882a2d39f12..dcd80a2909f6b 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index fe0543e6c58f3..1e0b5f123480a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -29,9 +29,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | triggersActionsUi | - | | | inspector, data, savedObjects, runtimeFields, indexManagement, dataViewEditor, unifiedSearch, embeddable, visualizations, dashboard, licensing, savedObjectsTagging, dataViewFieldEditor, lens, security, triggersActionsUi, cases, observabilityShared, advancedSettings, telemetry, maps, exploratoryView, fleet, timelines, banners, reporting, cloudSecurityPosture, dashboardEnhanced, imageEmbeddable, graph, monitoring, securitySolution, synthetics, uptime, cloudLinks, console, dataViewManagement, eventAnnotationListing, filesManagement, uiActions, visTypeVislib | - | | | @kbn/core, visualizations, triggersActionsUi, advancedSettings | - | -| | ruleRegistry, observability, infra, monitoring, securitySolution, synthetics, uptime | - | +| | ruleRegistry, observability, infra, securitySolution, synthetics, uptime | - | | | observability, @kbn/securitysolution-data-table, securitySolution | - | -| | monitoring | - | | | alerting, discover, securitySolution | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, fleet, graph, lists, osquery, securitySolution, alerting | - | @@ -63,6 +62,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-plugins-browser-internal, @kbn/core-root-browser-internal, home, savedObjects, unifiedSearch, visualizations, fileUpload, dashboardEnhanced, transform, discover, dataVisualizer | - | | | @kbn/core-saved-objects-browser-mocks, discover, @kbn/core-saved-objects-browser-internal | - | | | @kbn/management-settings-field-definition, advancedSettings, discover | - | +| | monitoring | - | | | @kbn/core-saved-objects-api-browser, @kbn/core, savedObjects, savedObjectsManagement, visualizations, savedObjectsTagging, eventAnnotation, lens, graph, dashboard, savedObjectsTaggingOss, kibanaUtils, expressions, data, embeddable, controls, uiActionsEnhanced, maps, canvas, dashboardEnhanced, globalSearchProviders | - | | | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, home, savedObjects, visualizations, lens, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, savedObjects | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 1489dbdaa742e..66f08b3a867c9 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -1106,7 +1106,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [base_rule.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/server/alerts/base_rule.ts#:~:text=alertFactory) | - | | | [url_state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/url_state.ts#:~:text=syncQueryStateWithUrl), [url_state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/url_state.ts#:~:text=syncQueryStateWithUrl) | - | | | [use_request_error_handler.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/hooks/use_request_error_handler.tsx#:~:text=toMountPoint), [use_request_error_handler.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/hooks/use_request_error_handler.tsx#:~:text=toMountPoint), [use_request_error_handler.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/hooks/use_request_error_handler.tsx#:~:text=toMountPoint), [alerts_toast.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx#:~:text=toMountPoint), [alerts_toast.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/alerts/lib/alerts_toast.tsx#:~:text=toMountPoint), [ingest_pipeline_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ingest_pipeline_modal.tsx#:~:text=toMountPoint), [ingest_pipeline_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/pages/elasticsearch/ingest_pipeline_modal.tsx#:~:text=toMountPoint), [listing.js](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js#:~:text=toMountPoint), [listing.js](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js#:~:text=toMountPoint), [listing.js](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js#:~:text=toMountPoint) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/index.tsx#:~:text=KibanaThemeProvider), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/index.tsx#:~:text=KibanaThemeProvider), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/monitoring/public/application/index.tsx#:~:text=KibanaThemeProvider) | - | @@ -1336,7 +1335,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [legacy_rules_notification_alert_type.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts#:~:text=alertFactory), [route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts#:~:text=alertFactory) | - | +| | [route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts#:~:text=alertFactory) | - | | | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts#:~:text=create) | - | | | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch) | - | | | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=migrationVersion)+ 12 more | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 8b909a630e7e3..131a66172341f 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index c724c83394fa3..9479cda0b595e 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: 2024-01-12 +date: 2024-01-16 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 99c0d75cf3c5a..d92704d38b2e5 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: 2024-01-12 +date: 2024-01-16 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 ee32ab91c775f..873544b6aec24 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index ea2a0896bc7c2..b9233d670575d 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 8beafd95adbe0..4907c3a900cc6 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index c5e2b38e707a9..3a379886e479d 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: 2024-01-12 +date: 2024-01-16 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 ebdff417545ce..fada598b1587a 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: 2024-01-12 +date: 2024-01-16 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 c1d8e4e3ef14d..325f70cfaa7ed 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: 2024-01-12 +date: 2024-01-16 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 28bad9dad4977..0a533c6b1621a 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: 2024-01-12 +date: 2024-01-16 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 07e381e5d4db4..15c8157020fbf 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: 2024-01-12 +date: 2024-01-16 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 1887d9c4e79cb..46fe241c01248 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index 6ec02f9cb32e3..f1fb16d30a348 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index b83eb97b5f624..268fa6ada7726 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 079ab091cc52b..36aa72cc3f6fd 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 459bb4a89e273..3f750c169d195 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.devdocs.json b/api_docs/expression_gauge.devdocs.json index b38c5c31347ff..a36125a9b469d 100644 --- a/api_docs/expression_gauge.devdocs.json +++ b/api_docs/expression_gauge.devdocs.json @@ -1257,7 +1257,15 @@ "CustomXDomain", " | undefined>; ariaDescription?: string | undefined; ariaDescribedBy?: string | undefined; ariaLabelledBy?: string | undefined; ariaTableCaption?: string | undefined; legendAction?: \"ignore\" | undefined; legendStrategy?: ", "LegendStrategy", - " | undefined; onLegendItemClick?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onResize?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; noResults?: React.ReactChild | React.ComponentType<{}> | undefined; legendSort?: \"ignore\" | undefined; }>> & Partial>) | undefined; }" + " | undefined; onLegendItemClick?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onResize?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; noResults?: React.ReactChild | React.ComponentType<{}> | undefined; legendSort?: \"ignore\" | undefined; }>> & Partial>) | undefined; shouldUseVeil: boolean; setChartSize: (d: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.ChartSizeSpec", + "text": "ChartSizeSpec" + }, + ") => void; }" ], "path": "src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts", "deprecated": false, diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 58e6b98d07ee3..00bd74141b9c3 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: 2024-01-12 +date: 2024-01-16 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 9b802a870b74a..def3779f2a3cd 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: 2024-01-12 +date: 2024-01-16 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 9aca7b114a4ba..788ac35c0c10d 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: 2024-01-12 +date: 2024-01-16 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 6bdeb516c08d7..259b77a4c89b5 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: 2024-01-12 +date: 2024-01-16 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 7d5732ed7ea75..ebdb389aeb189 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: 2024-01-12 +date: 2024-01-16 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 721f111ad9405..1de8571d9e0fb 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: 2024-01-12 +date: 2024-01-16 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 e03c44df8aa3d..95d5ddc497b71 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: 2024-01-12 +date: 2024-01-16 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 3e367482c0575..e776b5208f29a 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: 2024-01-12 +date: 2024-01-16 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 7579d384dcd1f..33c00c2eefe8f 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: 2024-01-12 +date: 2024-01-16 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 e89af79627537..f3b6e03c8d85b 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: 2024-01-12 +date: 2024-01-16 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 03071541eea77..f0c1ef429ce36 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: 2024-01-12 +date: 2024-01-16 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 1b36d2b299a09..783d0221c0eb0 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.devdocs.json b/api_docs/expressions.devdocs.json index 93beda5bfdfba..1f662da2bca54 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -3794,7 +3794,7 @@ "id": "def-public.ExpressionRenderHandler.Unnamed.$2", "type": "Object", "tags": [], - "label": "{\n onRenderError,\n renderMode,\n syncColors,\n syncTooltips,\n syncCursor,\n interactive,\n hasCompatibleActions = async () => false,\n getCompatibleCellValueActions = async () => [],\n executionContext,\n }", + "label": "{\n onRenderError,\n renderMode,\n syncColors,\n syncTooltips,\n syncCursor,\n shouldUseSizeTransitionVeil,\n interactive,\n hasCompatibleActions = async () => false,\n getCompatibleCellValueActions = async () => [],\n executionContext,\n }", "description": [], "signature": [ "ExpressionRenderHandlerParams" @@ -7261,6 +7261,24 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "expressions", + "id": "def-public.ExecutionContext.shouldUseSizeTransitionVeil", + "type": "Function", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [ + "\nReturns whether or not to use the size transition veil when resizing visualizations." + ], + "signature": [ + "(() => boolean) | undefined" + ], + "path": "src/plugins/expressions/common/execution/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "expressions", "id": "def-public.ExecutionContext.getExecutionContext", @@ -10880,6 +10898,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-public.IExpressionLoaderParams.shouldUseSizeTransitionVeil", + "type": "CompoundType", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/public/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-public.IExpressionLoaderParams.hasCompatibleActions", @@ -11311,6 +11343,22 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "expressions", + "id": "def-public.IInterpreterRenderHandlers.shouldUseSizeTransitionVeil", + "type": "Function", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "src/plugins/expressions/common/expression_renderers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "expressions", "id": "def-public.IInterpreterRenderHandlers.uiState", @@ -18648,6 +18696,24 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "expressions", + "id": "def-server.ExecutionContext.shouldUseSizeTransitionVeil", + "type": "Function", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [ + "\nReturns whether or not to use the size transition veil when resizing visualizations." + ], + "signature": [ + "(() => boolean) | undefined" + ], + "path": "src/plugins/expressions/common/execution/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "expressions", "id": "def-server.ExecutionContext.getExecutionContext", @@ -21335,6 +21401,22 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "expressions", + "id": "def-server.IInterpreterRenderHandlers.shouldUseSizeTransitionVeil", + "type": "Function", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "src/plugins/expressions/common/expression_renderers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "expressions", "id": "def-server.IInterpreterRenderHandlers.uiState", @@ -30687,6 +30769,24 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "expressions", + "id": "def-common.ExecutionContext.shouldUseSizeTransitionVeil", + "type": "Function", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [ + "\nReturns whether or not to use the size transition veil when resizing visualizations." + ], + "signature": [ + "(() => boolean) | undefined" + ], + "path": "src/plugins/expressions/common/execution/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "expressions", "id": "def-common.ExecutionContext.getExecutionContext", @@ -32341,6 +32441,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "expressions", + "id": "def-common.ExpressionExecutionParams.shouldUseSizeTransitionVeil", + "type": "CompoundType", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/expressions/common/service/expressions_services.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "expressions", "id": "def-common.ExpressionExecutionParams.inspectorAdapters", @@ -35599,6 +35713,22 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "expressions", + "id": "def-common.IInterpreterRenderHandlers.shouldUseSizeTransitionVeil", + "type": "Function", + "tags": [], + "label": "shouldUseSizeTransitionVeil", + "description": [], + "signature": [ + "() => boolean" + ], + "path": "src/plugins/expressions/common/expression_renderers/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "expressions", "id": "def-common.IInterpreterRenderHandlers.uiState", diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index aeb782d21c8b5..05de08b6b0c37 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2211 | 17 | 1752 | 5 | +| 2219 | 17 | 1757 | 5 | ## Client diff --git a/api_docs/features.mdx b/api_docs/features.mdx index d896e22d905a7..7e5f598bdbf82 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: 2024-01-12 +date: 2024-01-16 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 adbe1488182b7..0364641ee1596 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: 2024-01-12 +date: 2024-01-16 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 7a03f108e7c08..9531000dce89f 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: 2024-01-12 +date: 2024-01-16 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 fb2ba6d073e9f..465fde8007a49 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index 28d5462432e4c..ad24c30e734d5 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index bee291812120e..60a897149589d 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: 2024-01-12 +date: 2024-01-16 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 c9884a363ed86..ac4435db92392 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index a650b53873aa1..e3be4612c6bc5 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 28aef23b2e75d..ef4a4141fc63d 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index 52daf6a439124..92d679088f65b 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index b61ba01b10b40..263c495ae7fbc 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: 2024-01-12 +date: 2024-01-16 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 706d6ac6d796e..7ff8fd4760986 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: 2024-01-12 +date: 2024-01-16 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 c9e4faac744eb..3b68fc7c85ab9 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index 3d216d9bb3625..27c1551d27758 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 86107611e4cab..a61b522c1ad91 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: 2024-01-12 +date: 2024-01-16 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 15f84421c5a7f..46b41c53b03e6 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: 2024-01-12 +date: 2024-01-16 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 258b97d66b729..744ece524df37 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index e43b1ea2beb82..6f4ba99ae5d71 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 30e8810aaf22b..a6be03da04fae 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: 2024-01-12 +date: 2024-01-16 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 e3ef428971803..28c66ab486295 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index 4d473b3f89bd6..f9f8b611f743e 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index fee719741631e..135c229adb524 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index cf4f5198f3c0a..6bd0719348106 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index cb5724a59867e..ebf82ed658329 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index b4a410cbd3df1..2159f3b5efcc3 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 1481f168995a9..df7ead3c3a5b7 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: 2024-01-12 +date: 2024-01-16 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 1fe2972b42d48..ac0eeae370fdf 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index b107bb882591b..fa8ac5b2efd7b 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.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 dd8c945d44c27..3157c2f84b2f1 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: 2024-01-12 +date: 2024-01-16 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 86dc8f6e24a83..4956970565cfa 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: 2024-01-12 +date: 2024-01-16 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 a3a1a19e6b20b..5a0c7cef8d8a2 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: 2024-01-12 +date: 2024-01-16 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 a9d2700115412..e26ccd8389f19 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: 2024-01-12 +date: 2024-01-16 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 b352537a17323..dab6977c81566 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: 2024-01-12 +date: 2024-01-16 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.devdocs.json b/api_docs/kbn_apm_synthtrace.devdocs.json index c591fc9fd2533..2d3c49ff1a341 100644 --- a/api_docs/kbn_apm_synthtrace.devdocs.json +++ b/api_docs/kbn_apm_synthtrace.devdocs.json @@ -430,6 +430,145 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient", + "type": "Class", + "tags": [], + "label": "InfraSynthtraceKibanaClient", + "description": [], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.Unnamed.$1.logger", + "type": "Object", + "tags": [], + "label": "logger", + "description": [], + "signature": [ + "Logger" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.Unnamed.$1.target", + "type": "string", + "tags": [], + "label": "target", + "description": [], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.Unnamed.$1.username", + "type": "string", + "tags": [], + "label": "username", + "description": [], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.Unnamed.$1.password", + "type": "string", + "tags": [], + "label": "password", + "description": [], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.fetchLatestSystemPackageVersion", + "type": "Function", + "tags": [], + "label": "fetchLatestSystemPackageVersion", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.installSystemPackage", + "type": "Function", + "tags": [], + "label": "installSystemPackage", + "description": [], + "signature": [ + "(packageVersion: string) => Promise" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.installSystemPackage.$1", + "type": "string", + "tags": [], + "label": "packageVersion", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/apm-synthtrace", "id": "def-server.LogsSynthtraceEsClient", diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 707892ebf5aad..3519abcc89887 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 34 | 0 | 34 | 8 | +| 44 | 0 | 44 | 8 | ## Server diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 7c3f4871b5096..3c0f67f711df4 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index c3a8856f43205..e0ba697ec64fd 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: 2024-01-12 +date: 2024-01-16 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 ea1240ce8a9dd..3e8f5deb059c9 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index 0bacd9d6fbb07..8b05f980dac23 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index 48ad66ae66793..1d60d7d63a6d2 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index 37c33b7589b46..c026a22968047 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 5b68cfcea55c6..b7470273f0418 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index eea452458a73d..2b59e7f9387c3 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.devdocs.json b/api_docs/kbn_chart_expressions_common.devdocs.json index de54c17861fdd..a86e37814a6fa 100644 --- a/api_docs/kbn_chart_expressions_common.devdocs.json +++ b/api_docs/kbn_chart_expressions_common.devdocs.json @@ -236,6 +236,53 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.isChartSizeEvent", + "type": "Function", + "tags": [], + "label": "isChartSizeEvent", + "description": [], + "signature": [ + "(event: ", + { + "pluginId": "expressions", + "scope": "public", + "docId": "kibExpressionsPluginApi", + "section": "def-public.ExpressionRendererEvent", + "text": "ExpressionRendererEvent" + }, + ") => boolean" + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.isChartSizeEvent.$1", + "type": "Object", + "tags": [], + "label": "event", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "public", + "docId": "kibExpressionsPluginApi", + "section": "def-public.ExpressionRendererEvent", + "text": "ExpressionRendererEvent" + } + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/chart-expressions-common", "id": "def-common.isOnAggBasedEditor", @@ -283,9 +330,226 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.useSizeTransitionVeil", + "type": "Function", + "tags": [], + "label": "useSizeTransitionVeil", + "description": [ + "\nThis hook is used to show a veil over the chart while it is being resized\nin response to a change in the container dimensions.\n\nIt is only relevant if client dimensions are being requested based on chart configuration.\n\nThis whole feature is a nice-to-have. If it proves to be a source of bugs,\nwe can consider removing it and accepting the aesthetic drawback." + ], + "signature": [ + "(chartSizeSpec: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.ChartSizeSpec", + "text": "ChartSizeSpec" + }, + ", setChartSize: (d: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.ChartSizeSpec", + "text": "ChartSizeSpec" + }, + ") => void, shouldUseVeil: boolean) => { veil: JSX.Element; onResize: () => void; containerRef: React.RefObject; }" + ], + "path": "src/plugins/chart_expressions/common/chart_size_transition_veil.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.useSizeTransitionVeil.$1", + "type": "Object", + "tags": [], + "label": "chartSizeSpec", + "description": [], + "signature": [ + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.ChartSizeSpec", + "text": "ChartSizeSpec" + } + ], + "path": "src/plugins/chart_expressions/common/chart_size_transition_veil.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.useSizeTransitionVeil.$2", + "type": "Function", + "tags": [], + "label": "setChartSize", + "description": [], + "signature": [ + "(d: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.ChartSizeSpec", + "text": "ChartSizeSpec" + }, + ") => void" + ], + "path": "src/plugins/chart_expressions/common/chart_size_transition_veil.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.useSizeTransitionVeil.$3", + "type": "boolean", + "tags": [], + "label": "shouldUseVeil", + "description": [], + "signature": [ + "boolean" + ], + "path": "src/plugins/chart_expressions/common/chart_size_transition_veil.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.ChartSizeEvent", + "type": "Interface", + "tags": [], + "label": "ChartSizeEvent", + "description": [], + "signature": [ + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.ChartSizeEvent", + "text": "ChartSizeEvent" + }, + " extends ", + { + "pluginId": "expressions", + "scope": "public", + "docId": "kibExpressionsPluginApi", + "section": "def-public.ExpressionRendererEvent", + "text": "ExpressionRendererEvent" + } + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.ChartSizeEvent.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "\"chartSize\"" + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.ChartSizeEvent.data", + "type": "Object", + "tags": [], + "label": "data", + "description": [], + "signature": [ + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.ChartSizeSpec", + "text": "ChartSizeSpec" + } + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.ChartSizeSpec", + "type": "Interface", + "tags": [], + "label": "ChartSizeSpec", + "description": [], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.ChartSizeSpec.maxDimensions", + "type": "Object", + "tags": [], + "label": "maxDimensions", + "description": [], + "signature": [ + "ChartSizeDimensions | undefined" + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.ChartSizeSpec.minDimensions", + "type": "Object", + "tags": [], + "label": "minDimensions", + "description": [], + "signature": [ + "ChartSizeDimensions | undefined" + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/chart-expressions-common", + "id": "def-common.ChartSizeSpec.aspectRatio", + "type": "Object", + "tags": [], + "label": "aspectRatio", + "description": [], + "signature": [ + "{ x: number; y: number; } | undefined" + ], + "path": "src/plugins/chart_expressions/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false } ], - "interfaces": [], "enums": [], "misc": [ { diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index 8d6524fe65c66..b9e8c197aa1e0 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; @@ -21,13 +21,16 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 14 | 0 | 10 | 0 | +| 27 | 0 | 22 | 0 | ## Common ### Functions +### Interfaces + + ### Consts, variables and types diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 04d9a7654cf29..dc9e296c797db 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: 2024-01-12 +date: 2024-01-16 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 2180996c15311..cff33d875a1a9 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: 2024-01-12 +date: 2024-01-16 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 a3289278ada58..9661f1475396e 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: 2024-01-12 +date: 2024-01-16 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 828fef21fb371..54741be6d366f 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: 2024-01-12 +date: 2024-01-16 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 cd69b088037d7..d9d15e5436cd5 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index 69abf1ea3821d..d5b6a8325be14 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 2e9895942651d..d4739d0e60b31 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index 56aedaca25626..2aafaea584252 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 7fafaf11f95c0..6fb9aaeb0962f 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: 2024-01-12 +date: 2024-01-16 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 eb30a82a8194b..4c3b56bc29290 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: 2024-01-12 +date: 2024-01-16 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 2bac3a37eb9b4..f008f7a00dca0 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: 2024-01-12 +date: 2024-01-16 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 9d9b6b3cb7da0..107c189c99a89 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index 0372243d93a6b..3a2cf3bf1a926 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index 15a6d04a3a6e5..7ec9800b40fcf 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index b1d1e4a81cd0d..f4f1d562cb0d5 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index 9af30b1040c65..3a3fc1676a73a 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index 5c1f8b2206515..7712724a4260c 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 862ba6095f15e..c7618154f3781 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 675ca89c546e2..54d2f0027b7e9 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: 2024-01-12 +date: 2024-01-16 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 2ecfc03876254..07f7b854cfff3 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: 2024-01-12 +date: 2024-01-16 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 d8f5ed0a9a8a0..c8ade1dbe64d8 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: 2024-01-12 +date: 2024-01-16 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 f83e23c5d0faf..b26906e9466ba 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: 2024-01-12 +date: 2024-01-16 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 490b2e635e6d7..03b25ebdb8e4a 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: 2024-01-12 +date: 2024-01-16 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 0731afb7ca632..54b86737225e0 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: 2024-01-12 +date: 2024-01-16 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_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index a5130605371ca..8f6b636caffc7 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index 9e844a49ab368..bef2f0ebb3788 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index 8113c27e299f1..bd3af71518ae1 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index ed042ed13ec3a..25fe51a78c26a 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index 43c2c1a0d4347..3d40732e991af 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index 4d293ba8cee8c..42dc35ba9fe90 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index a654d22233eb7..e00bd975fb1cc 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 8eb72de8e30ad..113cbfd662a02 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: 2024-01-12 +date: 2024-01-16 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 ba014938b5dfb..7bf799d64c1f5 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: 2024-01-12 +date: 2024-01-16 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 bcbe0fdcb5d74..64944f87ac5ad 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: 2024-01-12 +date: 2024-01-16 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 04a88f1595721..eaf6623d93cd2 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: 2024-01-12 +date: 2024-01-16 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_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index 555cb353b9440..8893af4c4293b 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 75a0f589636c7..939355982090f 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: 2024-01-12 +date: 2024-01-16 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 14b0cf6319b75..7f64da3e71506 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: 2024-01-12 +date: 2024-01-16 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 393b45b39012f..cbb6e8eb43dc3 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: 2024-01-12 +date: 2024-01-16 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_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 5f1bc4e1077f6..2afaffe6d6c69 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index f54511165b26e..8abfd9d9b4900 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index a5c9f0d6178ed..6a21314e0687f 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: 2024-01-12 +date: 2024-01-16 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_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 0e8558c7cce26..5d6d04a4cb928 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index ea7069e264bcf..5b52234dfc68a 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index e05ad22ed04c7..dfcf1d1b0e620 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index dc9df06252620..40f725b627d43 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index b927b73a6ad0a..d43d4ffd10cd7 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index c7760e934688f..79aba402794f2 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index 38351d590cf29..ca01038a1d2a4 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index c8fd520184b3e..9205599531c7d 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: 2024-01-12 +date: 2024-01-16 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 86ec36379364c..bed9571157e3f 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: 2024-01-12 +date: 2024-01-16 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 23c109b4c90c2..98b5e5bffd96c 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: 2024-01-12 +date: 2024-01-16 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 572788f5ea890..36484078e6c7e 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: 2024-01-12 +date: 2024-01-16 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_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index 5097e34706168..1b2dacf8f1f04 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index c216d01c72753..77c511bca0efb 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 29ae331dcb676..2fddfd496b189 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index 5c87dbfa653d7..62375db8cf062 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: 2024-01-12 +date: 2024-01-16 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 70afb0ea71410..58c3c43ad4709 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: 2024-01-12 +date: 2024-01-16 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 0c7eef615b618..0bc6b1b5347db 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: 2024-01-12 +date: 2024-01-16 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 0fe1e777e7633..b6f024b0d3591 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: 2024-01-12 +date: 2024-01-16 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 5794cd7d42c14..1c899bf22de5d 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: 2024-01-12 +date: 2024-01-16 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 725a18fabf9a2..120ed38b2c5fc 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: 2024-01-12 +date: 2024-01-16 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 d6f2addbdf28d..431e5a5708247 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: 2024-01-12 +date: 2024-01-16 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 78f972f3cb88c..1eac5f268f4f4 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: 2024-01-12 +date: 2024-01-16 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 783a2ebe26324..51f57d352bb91 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: 2024-01-12 +date: 2024-01-16 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 05bdf5300fd7a..2da266f903f1b 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: 2024-01-12 +date: 2024-01-16 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 a8f42d496b237..ea61ea3753943 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: 2024-01-12 +date: 2024-01-16 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 218f083ed14c2..8fb792cb95dba 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: 2024-01-12 +date: 2024-01-16 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 98fcbf9d35712..5716fe953f8a5 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: 2024-01-12 +date: 2024-01-16 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 af53c71168b79..5f6e5d60618c6 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: 2024-01-12 +date: 2024-01-16 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 2b64c70db9401..23a20f2c10dc7 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: 2024-01-12 +date: 2024-01-16 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 15ed65a60c69a..b7986bc7003d4 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: 2024-01-12 +date: 2024-01-16 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 d6924a2f70708..12a14b4038d0a 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: 2024-01-12 +date: 2024-01-16 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 5ac460dbdbec9..8181838c76de1 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: 2024-01-12 +date: 2024-01-16 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 e6bebe12a80fc..4716941d989d3 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: 2024-01-12 +date: 2024-01-16 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 32dfbf117d671..0d0200fa8f841 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: 2024-01-12 +date: 2024-01-16 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 d1069b5494fcb..ad94fd7f81f9c 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: 2024-01-12 +date: 2024-01-16 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 f7ef230d46908..e5554ec744ef2 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: 2024-01-12 +date: 2024-01-16 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 8ff014ff70306..f552c137950e3 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: 2024-01-12 +date: 2024-01-16 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 345654e2c0d13..8df7eb2743288 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: 2024-01-12 +date: 2024-01-16 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 f2ab91a67a135..9497efaf6bbb5 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: 2024-01-12 +date: 2024-01-16 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_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index 44688cfa963a8..05bc7a3f2e0b4 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.devdocs.json b/api_docs/kbn_core_http_resources_server.devdocs.json index 1b3ef39af611e..806137b6d08a4 100644 --- a/api_docs/kbn_core_http_resources_server.devdocs.json +++ b/api_docs/kbn_core_http_resources_server.devdocs.json @@ -247,7 +247,7 @@ "tags": [], "label": "renderAnonymousCoreApp", "description": [ - "To respond with HTML page bootstrapping Kibana application without retrieving user-specific information." + "\nTo respond with HTML page bootstrapping Kibana application without retrieving user-specific information.\n**Note:**\n- Your client-side JavaScript bundle will only be loaded on an anonymous page if `plugin.enabledOnAnonymousPages` is enabled in your plugin's `kibana.jsonc` manifest file.\n- You will also need to register the route serving your anonymous app with the `coreSetup.http.anonymousPaths` service in your plugin's client-side `setup` method." ], "signature": [ "(options?: ", diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 97c7f5266c922..e7314232fdfae 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index e8789ef7463ba..26582b8135ef1 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index e292d06519807..b28fe3155892d 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_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 cd95ad0ef9284..3c4449dce170a 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: 2024-01-12 +date: 2024-01-16 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 572a52c7bc1dc..02b8788acccf5 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: 2024-01-12 +date: 2024-01-16 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.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index 524bee00a9781..8f3413bd88be7 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -7034,6 +7034,10 @@ "plugin": "visTypeTimelion", "path": "src/plugins/vis_types/timelion/server/routes/run.ts" }, + { + "plugin": "mockIdpPlugin", + "path": "packages/kbn-mock-idp-plugin/server/plugin.ts" + }, { "plugin": "@kbn/core-http-router-server-internal", "path": "packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_route.test.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index be6a50cf91162..daf45f9752c9b 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: 2024-01-12 +date: 2024-01-16 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 3e4474d73e423..4ff869de1a8fe 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: 2024-01-12 +date: 2024-01-16 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 932e235729c1b..17df1d4826e95 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: 2024-01-12 +date: 2024-01-16 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 9cf76afdd00e5..40b934b72ab85 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: 2024-01-12 +date: 2024-01-16 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 0a0740014809c..651ea4dc6b532 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: 2024-01-12 +date: 2024-01-16 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_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index eb3fd0ed246fd..ebd8633c294b1 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 24947107fbac0..5813ba8298a0c 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index db8dac5a980df..292793d9a9c32 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.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 b2e4cd1789bae..de0866466f605 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: 2024-01-12 +date: 2024-01-16 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 f1d9277241027..b56f4c11d0871 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: 2024-01-12 +date: 2024-01-16 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 f6c7f5cf4f118..95e6b6cc3d1d3 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: 2024-01-12 +date: 2024-01-16 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_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 59498a676c6f5..be55eaba1a289 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index d9eeb66288009..9e912597b9884 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 5ddb6761a8100..e0c2b0f78bd38 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index c5a3670a6a480..2e5a24b7313f0 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 151c4d43c6142..b41cc17484b49 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index f7741dfd17347..ae8bc043da26f 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index a6be08fc3be1b..723a236357234 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: 2024-01-12 +date: 2024-01-16 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 ccd7b70817a80..b56c9b16f6644 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: 2024-01-12 +date: 2024-01-16 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 9eec765ef00e7..b81c39f7640ee 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: 2024-01-12 +date: 2024-01-16 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 6ed953104fe25..9254c2d44f6a3 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: 2024-01-12 +date: 2024-01-16 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 fffef0ab08344..8f3e4dbd95ab9 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: 2024-01-12 +date: 2024-01-16 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 0dd5bd6634192..70cf88b75ef44 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: 2024-01-12 +date: 2024-01-16 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 ee25f20964540..b3ff0d8199485 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: 2024-01-12 +date: 2024-01-16 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 623e740829880..66e9207b46c3e 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: 2024-01-12 +date: 2024-01-16 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 81683acd70813..ca2d3f0f249bc 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: 2024-01-12 +date: 2024-01-16 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_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 27d7bda9796e7..0e5b61b5968a3 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: 2024-01-12 +date: 2024-01-16 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 5a0685b243671..cd0874e762bc3 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: 2024-01-12 +date: 2024-01-16 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 e9adb5576a649..449666461e899 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: 2024-01-12 +date: 2024-01-16 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 d2a18ec655cdb..86ad1376337a9 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: 2024-01-12 +date: 2024-01-16 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 2008bf0169687..6eb73d4b0b710 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: 2024-01-12 +date: 2024-01-16 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 03cd81425446f..c84bb456fce36 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: 2024-01-12 +date: 2024-01-16 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 934cf30279bee..8b1572c8741fd 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: 2024-01-12 +date: 2024-01-16 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 9a3e14b08b7c8..13b085cd8b6ba 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: 2024-01-12 +date: 2024-01-16 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 0ddba1fd85bc3..bb51bb1743749 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: 2024-01-12 +date: 2024-01-16 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_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index 8d733a8704655..518172f5f0252 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index 5a67ba679b3dd..2f87f8e785874 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index 81395a8e1ca64..2cc4c3552f94b 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 545f98d76207b..236c8a9dfe5ba 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 603ddecdd3102..a33a4f6f8b9e6 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 62c16a1223496..24755c1a87d96 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index dc41764319fe4..985b45591b6cd 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: 2024-01-12 +date: 2024-01-16 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 0d2b20c40b3f9..b01bb8a037463 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: 2024-01-12 +date: 2024-01-16 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_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 292126c6df292..addfd32a871c1 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 154d99e88e3f5..edec5c8354760 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index b4cd8f20e1be9..aa863d5d62218 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 5c3cab9ad8bd8..8c0e2847737c2 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.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 ffaa673bdbb1f..e2a1f0c02dfbf 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: 2024-01-12 +date: 2024-01-16 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 270b659d26e6a..3cecf90de0344 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: 2024-01-12 +date: 2024-01-16 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_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 27ae8f11488ca..0814e2c6fe891 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index fb7bb78bf9516..07b2c88c02dc7 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index c7efe180edd60..4162ad449f290 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index ead0ce20ac93e..24ab499d5fd93 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: 2024-01-12 +date: 2024-01-16 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 1c387fad5dc99..dbe1e32259ba4 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: 2024-01-12 +date: 2024-01-16 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 acf7672841b79..a0cca9ea1f4a6 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: 2024-01-12 +date: 2024-01-16 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 20e3a56976e7e..2d595e5e2d2e8 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: 2024-01-12 +date: 2024-01-16 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_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index ed0b35d7f5ef0..e05d16622252b 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index cd01d94ff98ff..8530527b2b9d4 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index a88050e58c503..2bcb4fbcd662c 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index a8dd2c23b04ca..73bef880b16c8 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 762fd7c8f47fd..5634a37239242 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: 2024-01-12 +date: 2024-01-16 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_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 36ebdb9380977..f83a4d5cbc4f0 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 388afe731225b..bb41c2ff623bd 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index dc413e83a00e9..ababb7449c59b 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 97e62513aba92..639ac8065542b 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index 1b6b67918fd99..06ea35e382682 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 3a16ddcce08aa..e79aa4dcee905 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index 729034e2f2981..bd8d2678f3544 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index 8f95c2c11c26c..edd5f0268b77d 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index 3ee9fbc34d629..cc2c9d90d2753 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: 2024-01-12 +date: 2024-01-16 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 c0a1716dd1ca6..52ae4e5caff1c 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: 2024-01-12 +date: 2024-01-16 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_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 39400a258129e..7946523def66e 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index ec0a47e033e75..7f9ed2396ba8b 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 26a52c0e7e78b..456e84d86b201 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 4b41cae5f27b1..4e2ca7fc29c10 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 5c1664f4764c0..1407ddb62da02 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: 2024-01-12 +date: 2024-01-16 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_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 01c7d441454bf..2af4b154ebd19 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: 2024-01-12 +date: 2024-01-16 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 c153a2be8df80..2063565c2fad0 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: 2024-01-12 +date: 2024-01-16 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 5134860537db6..f5141022a0b8c 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: 2024-01-12 +date: 2024-01-16 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 fa2c60d75161d..5ba6713235b48 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: 2024-01-12 +date: 2024-01-16 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 bc31640211396..49c0a0ecd3f4c 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: 2024-01-12 +date: 2024-01-16 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_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 00c413f42efd1..df47926fe87ab 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index d26d6e2b6ac55..1a70236d63fca 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index 7e38f4194bcf8..2598cbe434a7e 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index 11a8723dcdba8..f8c395ecebe53 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index 524f9862e3c99..009c7f6f4c495 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index 1ddd42b5b1b9e..4ca93d1148a3c 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index bacb6f2a9e4b3..ba791e3e0b00b 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_internal.mdx b/api_docs/kbn_core_user_settings_server_internal.mdx index 19e219c94f262..c427cacf7a131 100644 --- a/api_docs/kbn_core_user_settings_server_internal.mdx +++ b/api_docs/kbn_core_user_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-internal title: "@kbn/core-user-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-internal plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-internal'] --- import kbnCoreUserSettingsServerInternalObj from './kbn_core_user_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index bba7a6eeb2311..0ecd8df4e8f58 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 6d7260c3ce836..88d1074ab1eb8 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: 2024-01-12 +date: 2024-01-16 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 8a58efaea1033..8901317dc2f55 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index 811bc4d7d4cf0..44eaf0aa1c0cb 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 7d3e9f433107d..3ab1442889d32 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 7da624d13ed58..718291c230b1b 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index eceb01f77192d..4a31e9333d173 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index a68038e8a07a1..e01550c6ae64b 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index 0a10888287381..948c8673c7e8a 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index 9c48b4e59d04c..f4a62024811a8 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 797f1a82061a5..6c4226c5c2ed9 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index 704da8dfbac58..5d204bbfef835 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index 780c5d96bda97..8d06c25b23ab8 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 9b17e256a44d4..e69aaaa01fff2 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index a072d6629e5c0..4446f32ab16b6 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index c4b927e8a2465..b6e98c4116768 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index 9fda2a98313ae..bbee5dbf49951 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index d61c840b480e9..1555ad90ec8de 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 7e39641e6225e..2c4b28a48feb6 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: 2024-01-12 +date: 2024-01-16 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 81be34d5ab189..25031426624ec 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: 2024-01-12 +date: 2024-01-16 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 e8fa92f657ab2..640b7d56e4a15 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: 2024-01-12 +date: 2024-01-16 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 b88a6eebf00f4..a7155c8354c7d 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 2250e289e905c..842422e73665e 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 3bf8529a522ca..0048a0620b760 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: 2024-01-12 +date: 2024-01-16 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 abf1bad02d531..edc4d2d2f6f89 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index 860dfdd3c6321..6fbd68f212e3e 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index cd25b81c21da2..d9b857afd18c4 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs.mdx b/api_docs/kbn_ecs.mdx index 9aca2e6a2ecfd..9e8c0adf746f2 100644 --- a/api_docs/kbn_ecs.mdx +++ b/api_docs/kbn_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs title: "@kbn/ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs'] --- import kbnEcsObj from './kbn_ecs.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 9bba79712db71..437ab75018e3b 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index 8e2459910fa42..74bb6402575b4 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 6d5feb8171359..af86b22618154 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index dbd937e3a7088..9aa798875aaf0 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index fee0887e4b2b8..a3e3d57d78eb1 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index c6b8837576153..0f8bff3d96029 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: 2024-01-12 +date: 2024-01-16 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 b3f787d43aa84..61635cfc5e652 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: 2024-01-12 +date: 2024-01-16 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 6efe81ef27643..0c8b903f16d77 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 5a07942246e82..46d26d4b44b4e 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index dacf6e1048d8a..62750e076939c 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 8f8961b9f8e50..f24faabf61b28 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 6975c01521abc..c2b1fc3666d13 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index d5660d9fdd482..7a3dd342af76a 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 6f7b00aa3d90c..e9fe23c1eac86 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index e25b8b88120bf..1720fdc4aa01e 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 5b9a638a46ad2..b89c32f9af52e 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: 2024-01-12 +date: 2024-01-16 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_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 604799cd72b99..8e93d456b3ee8 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index 2a97a353311a7..46258a339d597 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 21123997e377d..f6e26bd9e838a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index bfe228a02eb30..5828fef0dab74 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index ec0b2f4de9699..351f6689673b3 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index b2d8cc6a1530f..2452e855755ed 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 3880d6f5b52a4..282dde58b8fad 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: 2024-01-12 +date: 2024-01-16 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 d69aed1a85793..02cf074c3fb0a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 5c958bb458f95..640a7edee0cf2 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 9907dff594f77..77554dc2cdc48 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: 2024-01-12 +date: 2024-01-16 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 e9fb01ed0cecc..6a9afb085b7db 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: 2024-01-12 +date: 2024-01-16 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 7bd9fa56245ba..5153f057570e9 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index c17ba7fffb622..ed044ff9d4291 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 7b866edab33d3..d9432bedfceb2 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index 785083821d848..4fd1bc796fc8d 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 1acb88dcfbc20..0bcbdd3049cd6 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: 2024-01-12 +date: 2024-01-16 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 583e493e7e4dc..41b5467390a0f 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: 2024-01-12 +date: 2024-01-16 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 1e997bcf518e3..b5d63f0935f3c 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index c0d594ad7e535..72116ac0c1f4a 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 0fe2189121448..86a404056e075 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 080d606855f5d..d367725961821 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index b92788deecd02..d6067a1b7ab26 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 8b6c9e389ca5d..e1873de3f6eaf 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index 0a2b9710daaaa..3cfc1fb71baee 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 87304af56f8f7..0c6e9fc45cd62 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: 2024-01-12 +date: 2024-01-16 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 d5c0d5e3f066e..e8d222cf5f2e2 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: 2024-01-12 +date: 2024-01-16 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 1717d084245c1..6355323af812d 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index 9582e8312be1b..774c5adbe22a6 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index fcf15306bdfba..c31cf1905dfc5 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index 45f6c9fe7eac8..3218c6992f30f 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index b112bd4898c3d..fe91a2aab8d8f 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index f89e6f8a95c23..857f67726737e 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index 0e89eb0582a07..4c96f9f06ad86 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index 27208bfe98c7f..6481cfc232e3b 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.devdocs.json b/api_docs/kbn_management_settings_ids.devdocs.json index dfb4567885ff4..26d5541422881 100644 --- a/api_docs/kbn_management_settings_ids.devdocs.json +++ b/api_docs/kbn_management_settings_ids.devdocs.json @@ -1192,6 +1192,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/management-settings-ids", + "id": "def-common.OBSERVABILITY_APM_ENABLE_TABLE_SEARCH_BAR", + "type": "string", + "tags": [], + "label": "OBSERVABILITY_APM_ENABLE_TABLE_SEARCH_BAR", + "description": [], + "signature": [ + "\"observability:apmEnableTableSearchBar\"" + ], + "path": "packages/kbn-management/settings/setting_ids/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/management-settings-ids", "id": "def-common.OBSERVABILITY_APM_LABS_BUTTON_ID", diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 9dcd387f2ffec..e593b7ac12c0b 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux @elastic/platform-deployment-management](https: | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 132 | 0 | 130 | 0 | +| 133 | 0 | 131 | 0 | ## Common diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index 91eb7f71b3497..2117bd7449833 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index dc7f86da567d7..44776f64768ac 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 7a4c6cded28d9..75fe25651c974 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 39f39719d7d42..b579a9c551abd 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 3ab8d261e1cb0..ab586e6c67609 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index d7a47a13affbb..e74a616a44a74 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 0de315ab2cc55..5a739b128c83a 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: 2024-01-12 +date: 2024-01-16 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_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index 663fb2c7ef425..b16664a213e99 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index d5b1c3d24bcc8..13c905d353de7 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index ca6d6e581dcfd..bde774c8b5784 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index c4f1d26dcbc32..766d7392c500b 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index b75541cee4806..abb25a85ed4ad 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 1ee1b5e13e926..821347f8cf10b 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index d757a697aa4d1..71f0badbf1fe9 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index 800c6667d9932..20b98254a61de 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.devdocs.json b/api_docs/kbn_ml_in_memory_table.devdocs.json index 4f21249865b51..6d72e5a158c23 100644 --- a/api_docs/kbn_ml_in_memory_table.devdocs.json +++ b/api_docs/kbn_ml_in_memory_table.devdocs.json @@ -29,7 +29,9 @@ "\nHook to help with managing the pagination and sorting for EuiInMemoryTable" ], "signature": [ - "(items: T[], initialSortField: string, initialSortDirection: \"asc\" | \"desc\") => { onTableChange: ({ page, sort }: ", + "(items: T[], initialSortField: string, initialSortDirection: \"asc\" | \"desc\", initialPagionation: Partial<", + "Pagination", + "> | undefined) => { onTableChange: ({ page, sort }: ", "Criteria", ") => void; pagination: ", "Pagination", @@ -91,6 +93,23 @@ "deprecated": false, "trackAdoption": false, "isRequired": true + }, + { + "parentPluginId": "@kbn/ml-in-memory-table", + "id": "def-common.useTableState.$4", + "type": "Object", + "tags": [], + "label": "initialPagionation", + "description": [], + "signature": [ + "Partial<", + "Pagination", + "> | undefined" + ], + "path": "x-pack/packages/ml/in_memory_table/hooks/use_table_state.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index ae3eab43e4b03..3fff58bba44a8 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 11 | 0 | 0 | 0 | +| 12 | 0 | 1 | 0 | ## Common diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index a025e0cec596c..11125e28021c0 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index aa1acdbca38d3..caf34c7643ef5 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: 2024-01-12 +date: 2024-01-16 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_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 267ceffe622a0..1ae4b7fa80e14 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 41dd9e700b903..28ddb3c8fe9fb 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index e9463195cb92c..e6e3f8ac7ce6f 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index 0b66b0d48bc57..3718d23cca592 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index f848452dc0730..c6e45c496663b 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 916215b3ca8b1..45741e00c7935 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index 91f0d4659f46d..6d02327c8a09f 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index fafc81c596177..153d4d07869da 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 04e313d291e99..0f596c4bd3a83 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 176ebf603320c..2547514695817 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index bcff01dc98d0a..6ec48444b5c2c 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 617cfcde51e51..3a8348ecccb04 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.devdocs.json b/api_docs/kbn_mock_idp_utils.devdocs.json new file mode 100644 index 0000000000000..991b274f3f7d5 --- /dev/null +++ b/api_docs/kbn_mock_idp_utils.devdocs.json @@ -0,0 +1,415 @@ +{ + "id": "@kbn/mock-idp-utils", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createMockIdpMetadata", + "type": "Function", + "tags": [], + "label": "createMockIdpMetadata", + "description": [ + "\nCreates XML metadata for our mock identity provider.\n\nThis can be saved to file and used to configure Elasticsearch SAML realm.\n" + ], + "signature": [ + "(kibanaUrl: string) => Promise" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createMockIdpMetadata.$1", + "type": "string", + "tags": [], + "label": "kibanaUrl", + "description": [ + "Fully qualified URL where Kibana is hosted (including base path)" + ], + "signature": [ + "string" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse", + "type": "Function", + "tags": [], + "label": "createSAMLResponse", + "description": [ + "\nCreates a SAML response that can be passed directly to the Kibana ACS endpoint to authenticate a user.\n" + ], + "signature": [ + "(options: { kibanaUrl: string; authnRequestId?: string | undefined; username: string; full_name?: string | undefined; email?: string | undefined; roles: string[]; }) => Promise" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse.$1.kibanaUrl", + "type": "string", + "tags": [], + "label": "kibanaUrl", + "description": [ + "Fully qualified URL where Kibana is hosted (including base path)" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse.$1.authnRequestId", + "type": "string", + "tags": [], + "label": "authnRequestId", + "description": [ + "ID from SAML authentication request" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse.$1.username", + "type": "string", + "tags": [], + "label": "username", + "description": [], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse.$1.full_name", + "type": "string", + "tags": [], + "label": "full_name", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse.$1.email", + "type": "string", + "tags": [], + "label": "email", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.createSAMLResponse.$1.roles", + "type": "Array", + "tags": [], + "label": "roles", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.ensureSAMLRoleMapping", + "type": "Function", + "tags": [], + "label": "ensureSAMLRoleMapping", + "description": [ + "\nCreates the role mapping required for developers to authenticate using SAML." + ], + "signature": [ + "(client: ", + "default", + ") => Promise" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.ensureSAMLRoleMapping.$1", + "type": "Object", + "tags": [], + "label": "client", + "description": [], + "signature": [ + "default" + ], + "path": "packages/kbn-mock-idp-utils/src/utils.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_ATTRIBUTE_EMAIL", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_EMAIL", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/email\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_ATTRIBUTE_NAME", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_NAME", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/name\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_ATTRIBUTE_PRINCIPAL", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_PRINCIPAL", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/principal\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_ATTRIBUTE_ROLES", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ATTRIBUTE_ROLES", + "description": [], + "signature": [ + "\"http://saml.elastic-cloud.com/attributes/roles\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_ENTITY_ID", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ENTITY_ID", + "description": [], + "signature": [ + "\"urn:mock-idp\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_LOGIN_PATH", + "type": "string", + "tags": [], + "label": "MOCK_IDP_LOGIN_PATH", + "description": [], + "signature": [ + "\"/mock_idp/login\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_LOGOUT_PATH", + "type": "string", + "tags": [], + "label": "MOCK_IDP_LOGOUT_PATH", + "description": [], + "signature": [ + "\"/mock_idp/logout\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_OBSERVABILITY_ROLE_NAMES", + "type": "Array", + "tags": [], + "label": "MOCK_IDP_OBSERVABILITY_ROLE_NAMES", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_REALM_NAME", + "type": "string", + "tags": [], + "label": "MOCK_IDP_REALM_NAME", + "description": [], + "signature": [ + "\"mock-idp\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_REALM_TYPE", + "type": "string", + "tags": [], + "label": "MOCK_IDP_REALM_TYPE", + "description": [], + "signature": [ + "\"saml\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_ROLE_MAPPING_NAME", + "type": "string", + "tags": [], + "label": "MOCK_IDP_ROLE_MAPPING_NAME", + "description": [], + "signature": [ + "\"mock-idp-mapping\"" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_SEARCH_ROLE_NAMES", + "type": "Array", + "tags": [], + "label": "MOCK_IDP_SEARCH_ROLE_NAMES", + "description": [ + "List of roles from `packages/kbn-es/src/serverless_resources/roles.yml`" + ], + "signature": [ + "string[]" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/mock-idp-utils", + "id": "def-common.MOCK_IDP_SECURITY_ROLE_NAMES", + "type": "Array", + "tags": [], + "label": "MOCK_IDP_SECURITY_ROLE_NAMES", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-mock-idp-utils/src/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx new file mode 100644 index 0000000000000..7b077dfe66714 --- /dev/null +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -0,0 +1,33 @@ +--- +#### +#### 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: kibKbnMockIdpUtilsPluginApi +slug: /kibana-dev-docs/api/kbn-mock-idp-utils +title: "@kbn/mock-idp-utils" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/mock-idp-utils plugin +date: 2024-01-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] +--- +import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; + + + +Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 25 | 0 | 18 | 0 | + +## Common + +### Functions + + +### Consts, variables and types + + diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index f81a5d7e43a70..7d192e8ffeb81 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index 4c64fb1913576..328ee38356dbe 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 14f3953eff336..a5980eaa0a80a 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 6b596670b8677..ffc62c14684aa 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index d249f2039538c..324adb788b92f 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index 2fe261471cb9c..513e9611a91a7 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index f79ac57563087..6c8c5a64487ec 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index dc556e489f774..c90503239435e 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: 2024-01-12 +date: 2024-01-16 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 eceac5c3ca50c..6597b17e7f796 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index ce552f779dafa..4a467ad810c8c 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index 70b6dbc0640ed..dbe4082fcd87f 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 3eb02e27ea088..a16995deb18b2 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: 2024-01-12 +date: 2024-01-16 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 c2afde9a7782d..7f34ea6fd5e04 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: 2024-01-12 +date: 2024-01-16 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 6d5d8665ded2d..913cddd71221d 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 368dc6d3e60c5..5fc9077dad899 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 3e9def467d482..dc8001b6da57b 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 9a48b79229e51..df1fb9a7a4dae 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index b9fd378d4ca3b..d03b8bf43fd76 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index d058fd68aef04..60b6ea7dc696c 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index 7d01523b4859b..3723231f1b60b 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index 4e8ccfcaeb09a..376409ca25c8e 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index 8e06f449fa7d4..d543c5bce5f91 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index 46c53bc9c19bf..47c2eb8a3fd3f 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index c2bb37413353a..720606161c8c3 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index 7af7dfa5dcc50..efd53288912c8 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index 5cd8898015dfe..acd2686b2f7b0 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 43bf0600c39ec..946cd1a97a27d 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index e395eeeeba7bf..44d73b8c1fda6 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.devdocs.json b/api_docs/kbn_reporting_export_types_csv.devdocs.json index 006a2c32b5760..d862fb9f9b953 100644 --- a/api_docs/kbn_reporting_export_types_csv.devdocs.json +++ b/api_docs/kbn_reporting_export_types_csv.devdocs.json @@ -168,7 +168,7 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -176,7 +176,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", { "pluginId": "@kbn/logging", "scope": "common", @@ -192,7 +192,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -200,7 +200,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" ], "path": "packages/kbn-reporting/export_types/csv/csv_searchsource.ts", "deprecated": false, @@ -538,7 +538,7 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -546,7 +546,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", { "pluginId": "@kbn/logging", "scope": "common", @@ -562,7 +562,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -570,7 +570,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" ], "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", "deprecated": false, @@ -886,7 +886,7 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -894,7 +894,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", { "pluginId": "@kbn/logging", "scope": "common", @@ -910,7 +910,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -918,7 +918,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" ], "path": "packages/kbn-reporting/export_types/csv/csv_v2.ts", "deprecated": false, diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 8d14082988190..3999771a4298b 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index fab413a61bdb0..0a4ce5bbb5068 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.devdocs.json b/api_docs/kbn_reporting_export_types_pdf.devdocs.json index 5a7a0d2414a5a..96359a7676d93 100644 --- a/api_docs/kbn_reporting_export_types_pdf.devdocs.json +++ b/api_docs/kbn_reporting_export_types_pdf.devdocs.json @@ -176,7 +176,7 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -184,7 +184,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", { "pluginId": "@kbn/logging", "scope": "common", @@ -200,7 +200,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -208,7 +208,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" ], "path": "packages/kbn-reporting/export_types/pdf/printable_pdf_v2.ts", "deprecated": false, @@ -578,7 +578,7 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -586,7 +586,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", { "pluginId": "@kbn/logging", "scope": "common", @@ -602,7 +602,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -610,7 +610,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" ], "path": "packages/kbn-reporting/export_types/pdf/printable_pdf.ts", "deprecated": false, diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index dbeb82983e65e..c2ff704ea50e2 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index 04682a2407960..24d0f9dcf94b2 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.devdocs.json b/api_docs/kbn_reporting_export_types_png.devdocs.json index 910b4e56d3265..1ea14e3f787d2 100644 --- a/api_docs/kbn_reporting_export_types_png.devdocs.json +++ b/api_docs/kbn_reporting_export_types_png.devdocs.json @@ -176,7 +176,7 @@ "section": "def-common.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -184,7 +184,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", { "pluginId": "@kbn/logging", "scope": "common", @@ -200,7 +200,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -208,7 +208,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" ], "path": "packages/kbn-reporting/export_types/png/png_v2.ts", "deprecated": false, diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index 9ba0b4763bbdd..7c7cd7d35fa94 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index 82fb5fd8d29bb..8a18e0f08598b 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.devdocs.json b/api_docs/kbn_reporting_mocks_server.devdocs.json index 55588a5151511..b1db2e710a66d 100644 --- a/api_docs/kbn_reporting_mocks_server.devdocs.json +++ b/api_docs/kbn_reporting_mocks_server.devdocs.json @@ -29,7 +29,7 @@ "signature": [ "(overrides?: ", "_DeepPartialObject", - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -37,7 +37,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>) => Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>) => Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -45,7 +45,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>" ], "path": "packages/kbn-reporting/mocks_server/index.ts", "deprecated": false, @@ -60,7 +60,7 @@ "description": [], "signature": [ "_DeepPartialObject", - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -68,7 +68,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>" ], "path": "packages/kbn-reporting/mocks_server/index.ts", "deprecated": false, diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index d01d1e4eb578e..6c40fa8adf126 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 9f67cca0a26cc..a07d07d6f61c0 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.devdocs.json b/api_docs/kbn_reporting_server.devdocs.json index 8cabd5e24af12..6e6f1bd1cb721 100644 --- a/api_docs/kbn_reporting_server.devdocs.json +++ b/api_docs/kbn_reporting_server.devdocs.json @@ -402,7 +402,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -410,7 +410,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>" ], "path": "packages/kbn-reporting/server/export_type.ts", "deprecated": false, @@ -453,7 +453,7 @@ "section": "def-common.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -461,7 +461,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>" ], "path": "packages/kbn-reporting/server/export_type.ts", "deprecated": false, @@ -935,7 +935,7 @@ "label": "getFullRedirectAppUrl", "description": [], "signature": [ - "(config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "(config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -943,7 +943,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, serverInfo: ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, serverInfo: ", "ReportingServerInfo", ", spaceId: string | undefined, forceNow: string | undefined) => string" ], @@ -959,7 +959,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -967,7 +967,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>" ], "path": "packages/kbn-reporting/server/get_full_redirect_app_url.ts", "deprecated": false, @@ -1487,7 +1487,7 @@ "label": "ReportingConfigType", "description": [], "signature": [ - "{ readonly encryptionKey?: string | undefined; readonly enabled: boolean; readonly capture: Readonly<{} & { maxAttempts: number; }>; readonly kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; readonly queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; readonly csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "{ readonly encryptionKey?: string | undefined; readonly enabled: boolean; readonly capture: Readonly<{} & { maxAttempts: number; }>; readonly roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; readonly kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; readonly queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; readonly csv: Readonly<{} & { scroll: Readonly<{} & { duration: string; size: number; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -1495,7 +1495,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; readonly roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; readonly poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; readonly export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; readonly statefulSettings: Readonly<{} & { enabled: boolean; }>; }" + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; readonly poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; readonly export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; readonly statefulSettings: Readonly<{} & { enabled: boolean; }>; }" ], "path": "packages/kbn-reporting/server/types.ts", "deprecated": false, diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index c57557b7cb8a9..6fadd760f1938 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 3370f87b4984a..6ef9af01f9a24 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 48ba4b559d6eb..73ea9ed474603 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 83143d5f8a798..497c266e7e492 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index b772415b62ba8..db1e7806d6c89 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 6ee90751af932..863a00da7e580 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index d238d68ce9001..a0bf6d93af6f8 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 7600979585abe..e6d5aaccdcee0 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 1ed2ae14fb498..a82ee73b97da3 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index f72d468bc8eca..837695f1d1c2c 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index 5e80f196b5a8e..101317585d439 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 5c2d570685a12..c45539c54f820 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index ad3acb581004d..bdd4c36e40184 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index 97981080de074..bb81ba4e2023b 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index aa75045998146..25f761fdb0a7b 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 839361be1a59a..637f2826552e1 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index d898011836cc8..8baef6b220ad6 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 4a1d462eb4e78..b6f90c48f143c 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index 157b2fba174cf..0dfd17f2cfef6 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 6160b6cf3e0f2..ee0eaf9c7d30d 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index 0d8b9710a96c1..1a06d4bf8fa77 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index e94323454fef1..4ac91cce6174b 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index c6bda1b83ad5b..da28cfffddb3d 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: 2024-01-12 +date: 2024-01-16 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_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index a1e97f47cadf8..ac77af1bcb0c4 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_grouping.mdx b/api_docs/kbn_securitysolution_grouping.mdx index 8c384f61bf22a..8a0c535e40d0b 100644 --- a/api_docs/kbn_securitysolution_grouping.mdx +++ b/api_docs/kbn_securitysolution_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-grouping title: "@kbn/securitysolution-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-grouping plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-grouping'] --- import kbnSecuritysolutionGroupingObj from './kbn_securitysolution_grouping.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 76544fad007ab..22762f35d235f 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: 2024-01-12 +date: 2024-01-16 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 ebad9ac513200..6772533df4163 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: 2024-01-12 +date: 2024-01-16 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 ae0358ccf1836..0c2daa6517d04 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: 2024-01-12 +date: 2024-01-16 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 f5bbee312fd02..30ac819771155 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: 2024-01-12 +date: 2024-01-16 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 3c94ee2ecc9ae..cfcbae417820b 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: 2024-01-12 +date: 2024-01-16 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 8962110de95e5..396d2665cee8f 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: 2024-01-12 +date: 2024-01-16 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 8b6c40633552e..87ee63945dd1b 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: 2024-01-12 +date: 2024-01-16 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 cd5a9254cd9c1..7ab52bb381bbb 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: 2024-01-12 +date: 2024-01-16 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 3e6e7883383a7..1889f065c9d58 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: 2024-01-12 +date: 2024-01-16 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 113463b13268f..43c4b3d933ffe 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: 2024-01-12 +date: 2024-01-16 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 b66773eb91257..7d525cf5b3d6c 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: 2024-01-12 +date: 2024-01-16 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 bc397b293ad15..2111733c7f861 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: 2024-01-12 +date: 2024-01-16 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 16b6062be5a8d..aeed93c8fefb6 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: 2024-01-12 +date: 2024-01-16 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 d33a615341d72..5858da39a3b95 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index ac9225ab74644..259eb5cda193d 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 51d08d188a571..6276f33bccb12 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 86f62bf421e6a..acd1c606df455 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index 38b6d2079088c..a509f94f7a99a 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 14dabb06711aa..d5be722a0c795 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index 43cf295a1b2e6..68e80a321166e 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 39a67f2eb04be..913e6cf1d07d0 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 332389d227df4..128a83059bf38 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 54659e6ec2928..96430b82d45e9 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.devdocs.json b/api_docs/kbn_shared_ux_button_toolbar.devdocs.json index 1e2e1a3777596..cbf27e1fbcb79 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.devdocs.json +++ b/api_docs/kbn_shared_ux_button_toolbar.devdocs.json @@ -78,7 +78,7 @@ "\nA group of buttons each performing an action, represented by an icon." ], "signature": [ - "({ buttons, legend, buttonSize }: ", + "({ buttons, legend, buttonSize, \"data-test-subj\": dataTestSubj, }: ", { "pluginId": "@kbn/shared-ux-button-toolbar", "scope": "common", @@ -97,7 +97,7 @@ "id": "def-common.IconButtonGroup.$1", "type": "Object", "tags": [], - "label": "{ buttons, legend, buttonSize = 'm' }", + "label": "{\n buttons,\n legend,\n buttonSize = 'm',\n 'data-test-subj': dataTestSubj,\n}", "description": [], "signature": [ { @@ -358,6 +358,54 @@ "path": "packages/shared-ux/button_toolbar/src/buttons/icon_button_group/icon_button_group.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/shared-ux-button-toolbar", + "id": "def-common.IconButton.isDisabled", + "type": "CompoundType", + "tags": [], + "label": "isDisabled", + "description": [ + "To disable the action" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/shared-ux/button_toolbar/src/buttons/icon_button_group/icon_button_group.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/shared-ux-button-toolbar", + "id": "def-common.IconButton.ariaexpanded", + "type": "CompoundType", + "tags": [], + "label": "'aria-expanded'", + "description": [ + "A11y for button" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/shared-ux/button_toolbar/src/buttons/icon_button_group/icon_button_group.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/shared-ux-button-toolbar", + "id": "def-common.IconButton.ariacontrols", + "type": "string", + "tags": [], + "label": "'aria-controls'", + "description": [ + "A11y for button" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/shared-ux/button_toolbar/src/buttons/icon_button_group/icon_button_group.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -426,6 +474,22 @@ "path": "packages/shared-ux/button_toolbar/src/buttons/icon_button_group/icon_button_group.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/shared-ux-button-toolbar", + "id": "def-common.Props.datatestsubj", + "type": "string", + "tags": [], + "label": "'data-test-subj'", + "description": [ + "Test subject for button group" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/shared-ux/button_toolbar/src/buttons/icon_button_group/icon_button_group.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -471,7 +535,7 @@ "label": "Props", "description": [], "signature": [ - "{ fullWidth?: boolean | undefined; 'aria-label'?: string | undefined; onClick?: React.MouseEventHandler | undefined; 'data-test-subj'?: string | undefined; isDisabled?: boolean | undefined; isLoading?: boolean | undefined; size?: \"m\" | \"s\" | undefined; as?: \"standard\" | undefined; fontWeight?: ToolbarButtonFontWeights | undefined; iconSide?: ", + "{ fullWidth?: boolean | undefined; 'aria-label'?: string | undefined; onBlur?: React.FocusEventHandler | undefined; onClick?: React.MouseEventHandler | undefined; 'data-test-subj'?: string | undefined; isDisabled?: boolean | undefined; isLoading?: boolean | undefined; size?: \"m\" | \"s\" | undefined; as?: \"standard\" | undefined; fontWeight?: ToolbarButtonFontWeights | undefined; iconSide?: ", "ButtonContentIconSide", "; groupPosition?: ButtonPositions | undefined; hasArrow?: boolean | undefined; }" ], diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index ccc362509693d..6a511afc5884e 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 26 | 0 | 8 | 0 | +| 30 | 0 | 8 | 0 | ## Common diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 4ec27f787f1df..afbb9a093725e 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: 2024-01-12 +date: 2024-01-16 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 7ddd18f59594f..1e7fcc2824575 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: 2024-01-12 +date: 2024-01-16 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_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 991ccbe4c01a3..4faa2cb1426ad 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 2689cf5d99562..078ad20536ad4 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 3a3a250857838..bcc2dc1c7c178 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index 1a0f793d9881c..0e1108a16e9b1 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 047ba786e7dea..fd6534b5d1b8d 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 028a46fef5ef1..2646632c6fd99 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index 4d7732790757c..dd63bdcf5124f 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 9fce08639fb56..52c1f39eda2e6 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 5fe5a79b54891..6931644afa4e0 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 5d03b56cd975a..31c8f64be4c4b 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 036339ec0283b..9993a1ddd789d 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.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 ce17fafe94732..5f85c44674b1f 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: 2024-01-12 +date: 2024-01-16 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_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index 92e076efeae45..4cae4743e0251 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 2d22aba071dcd..b539a5392fea3 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_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 36c4353ebcedb..dfd08881fd78e 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: 2024-01-12 +date: 2024-01-16 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 f779813d06448..28725b6891e10 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: 2024-01-12 +date: 2024-01-16 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 676f9f8740424..9332414f24a49 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: 2024-01-12 +date: 2024-01-16 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 87a1c1dfbc82a..51453742c80d1 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: 2024-01-12 +date: 2024-01-16 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 87e9e9cd63f56..12a9d365bfaf7 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: 2024-01-12 +date: 2024-01-16 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 bdf8febea3975..bbd4501efc62a 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: 2024-01-12 +date: 2024-01-16 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 1bb0e3ed66a72..c7ba640d1ec93 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: 2024-01-12 +date: 2024-01-16 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 118cc70aebff5..d5205eff918d2 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: 2024-01-12 +date: 2024-01-16 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 9fe4a982c02b9..bbffc266e9308 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: 2024-01-12 +date: 2024-01-16 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 a8ca3f1e41f6d..345e2856028c8 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: 2024-01-12 +date: 2024-01-16 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 da469c413328b..c9b2c1803ce2d 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: 2024-01-12 +date: 2024-01-16 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 19c3de45e1ecb..22a440c73e938 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: 2024-01-12 +date: 2024-01-16 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 9e704c3b5ce47..27fdbf063c8cf 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: 2024-01-12 +date: 2024-01-16 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_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index a6c5ac9b1f540..9b6d3380938ea 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 89ebb1de37fca..1276e6eaa34b4 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index 70cc8344158d6..6cde2047ee863 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 6388b049b43e2..63ee372b6297c 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 3cfb0d7642a13..5877795e1dcf8 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: 2024-01-12 +date: 2024-01-16 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 e0407ae0248a9..39dbfc2c538cb 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index a3ea7cb5edab2..83538d7689e16 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 147d85ec296d5..691291f4b21f2 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 67120ab321351..292497286f872 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: 2024-01-12 +date: 2024-01-16 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 7ff1106e3c733..06df3130ac4f4 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: 2024-01-12 +date: 2024-01-16 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 debabfce62f89..47f0d52f5eaa6 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: 2024-01-12 +date: 2024-01-16 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 70ef477585cb9..1c16f4766a205 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: 2024-01-12 +date: 2024-01-16 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 1e9529263b97e..0578a1af4f5d1 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index 859bef50ab0f9..661f84d3afe7a 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 66da9d33d75a4..8587cbfce3d70 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index de2d5d83edaa4..be2f1872e0c06 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index b213c4a6d3f44..d584d47f8e92a 100644 --- a/api_docs/kbn_text_based_editor.mdx +++ b/api_docs/kbn_text_based_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-text-based-editor title: "@kbn/text-based-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/text-based-editor plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index c83e2bcd9d282..c91b34cf03183 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 3956ab3dbdfb5..ee33131bea7c4 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index ec07710865491..bd74278992303 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index fc94f7268825a..1f95dd18c0c89 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: 2024-01-12 +date: 2024-01-16 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_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index ea9eaeb0f7f51..cf947dda613e4 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 772820246c445..bccd65ae034f0 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index e993dfb1c698d..433fa1d7a0a4e 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index 2907ddaef2778..00efa7ab17ac7 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index 983b39b53b0c8..0fdc9a34411ae 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.devdocs.json b/api_docs/kbn_unified_field_list.devdocs.json index da24a60d27f67..1d138e53c869f 100644 --- a/api_docs/kbn_unified_field_list.devdocs.json +++ b/api_docs/kbn_unified_field_list.devdocs.json @@ -5127,14 +5127,13 @@ "children": [ { "parentPluginId": "@kbn/unified-field-list", - "id": "def-common.UnifiedFieldListSidebarContainerApi.isSidebarCollapsed$", + "id": "def-common.UnifiedFieldListSidebarContainerApi.sidebarVisibility", "type": "Object", "tags": [], - "label": "isSidebarCollapsed$", + "label": "sidebarVisibility", "description": [], "signature": [ - "Observable", - "" + "SidebarVisibility" ], "path": "packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar_container.tsx", "deprecated": false, diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 5e594db9068f2..8279a5b968d82 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 291 | 0 | 267 | 9 | +| 291 | 0 | 267 | 10 | ## Common diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index 700564e4e8346..0cbdc049b4716 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index bdba2790ce6a8..9bcb1f277ef8a 100644 --- a/api_docs/kbn_url_state.mdx +++ b/api_docs/kbn_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-url-state title: "@kbn/url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/url-state plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/url-state'] --- import kbnUrlStateObj from './kbn_url_state.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 6178ce40fd00e..415dd95d39029 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 992d61cda37bc..75126105e39a4 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: 2024-01-12 +date: 2024-01-16 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 3126e0f096949..4302a69f1c375 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: 2024-01-12 +date: 2024-01-16 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 5c6e22894a444..af5057a7e4726 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: 2024-01-12 +date: 2024-01-16 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 81afa999e7475..c171fcf22c3cc 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 066979e285dc2..a6efb574da65b 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index 721012fec60b6..19b58ba064969 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index dc85f20a10d75..0a70ee3d99645 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index b218694074868..f480feeb6621a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 0dc1e1cda9907..527997dfd5c12 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 0721c4cd53c8c..cc0697604af71 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: 2024-01-12 +date: 2024-01-16 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 ac4d24e0b28ae..f448e22bc2faf 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: 2024-01-12 +date: 2024-01-16 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 4f3d7df572d06..2db5fb4ad16fb 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: 2024-01-12 +date: 2024-01-16 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 bb8b24c11ec3c..6e6aacb00f172 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: 2024-01-12 +date: 2024-01-16 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 8e67021264f0f..9b99764cf44af 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: 2024-01-12 +date: 2024-01-16 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 9a718b4ac79a2..9d49c301b81a8 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: 2024-01-12 +date: 2024-01-16 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 d40e937d06d2e..f38aaeae7cad1 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: 2024-01-12 +date: 2024-01-16 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 d8a3f9e857223..feb537b00defc 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 37a4319e2ff38..bdd3aad9ea793 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 4b2317fe6b7f5..843b3b81f56ac 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/log_explorer.mdx b/api_docs/log_explorer.mdx index af20b2cd42808..d63f69e02bcce 100644 --- a/api_docs/log_explorer.mdx +++ b/api_docs/log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logExplorer title: "logExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logExplorer plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logExplorer'] --- import logExplorerObj from './log_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 25282cfa1993b..52c11c5f382c1 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 6dc327024b8c4..117c8fc15e3db 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: 2024-01-12 +date: 2024-01-16 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 5920f41a9cf0b..7b0e0631f8806 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: 2024-01-12 +date: 2024-01-16 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 1b9ffc4992d42..fbdbd2b3b1e6a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index e54d1715fb09f..dc325a53d9759 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 6da1e4abe8448..18f2a4a9eeb2c 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.devdocs.json b/api_docs/mock_idp_plugin.devdocs.json index 9c7b5bd1558d8..dc9e8d3ea6460 100644 --- a/api_docs/mock_idp_plugin.devdocs.json +++ b/api_docs/mock_idp_plugin.devdocs.json @@ -13,367 +13,31 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [], - "objects": [] - }, - "common": { - "classes": [], - "functions": [ - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createMockIdpMetadata", - "type": "Function", - "tags": [], - "label": "createMockIdpMetadata", - "description": [ - "\nCreates XML metadata for our mock identity provider.\n\nThis can be saved to file and used to configure Elasticsearch SAML realm.\n" - ], - "signature": [ - "(kibanaUrl: string) => Promise" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createMockIdpMetadata.$1", - "type": "string", - "tags": [], - "label": "kibanaUrl", - "description": [ - "Fully qualified URL where Kibana is hosted (including base path)" - ], - "signature": [ - "string" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse", - "type": "Function", - "tags": [], - "label": "createSAMLResponse", - "description": [ - "\nCreates a SAML response that can be passed directly to the Kibana ACS endpoint to authenticate a user.\n" - ], - "signature": [ - "(options: { kibanaUrl: string; authnRequestId?: string | undefined; username: string; fullname?: string | undefined; email?: string | undefined; roles: string[]; }) => Promise" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse.$1", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse.$1.kibanaUrl", - "type": "string", - "tags": [], - "label": "kibanaUrl", - "description": [ - "Fully qualified URL where Kibana is hosted (including base path)" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse.$1.authnRequestId", - "type": "string", - "tags": [], - "label": "authnRequestId", - "description": [ - "ID from SAML authentication request" - ], - "signature": [ - "string | undefined" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse.$1.username", - "type": "string", - "tags": [], - "label": "username", - "description": [], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse.$1.fullname", - "type": "string", - "tags": [], - "label": "fullname", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse.$1.email", - "type": "string", - "tags": [], - "label": "email", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.createSAMLResponse.$1.roles", - "type": "Array", - "tags": [], - "label": "roles", - "description": [], - "signature": [ - "string[]" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.ensureSAMLRoleMapping", - "type": "Function", - "tags": [], - "label": "ensureSAMLRoleMapping", - "description": [ - "\nCreates the role mapping required for developers to authenticate using SAML." - ], - "signature": [ - "(client: ", - "default", - ") => Promise" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.ensureSAMLRoleMapping.$1", - "type": "Object", - "tags": [], - "label": "client", - "description": [], - "signature": [ - "default" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, + "misc": [ { "parentPluginId": "mockIdpPlugin", - "id": "def-common.parseSAMLAuthnRequest", - "type": "Function", + "id": "def-server.CreateSAMLResponseParams", + "type": "Type", "tags": [], - "label": "parseSAMLAuthnRequest", + "label": "CreateSAMLResponseParams", "description": [], "signature": [ - "(samlRequest: string) => Promise<{ AssertionConsumerServiceURL: string; Destination: string; ID: string; IssueInstant: string; }>" + "{ readonly email?: string | null | undefined; readonly full_name?: string | null | undefined; readonly username: string; readonly roles: string[]; }" ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", + "path": "packages/kbn-mock-idp-plugin/server/plugin.ts", "deprecated": false, "trackAdoption": false, - "children": [ - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.parseSAMLAuthnRequest.$1", - "type": "string", - "tags": [], - "label": "samlRequest", - "description": [], - "signature": [ - "string" - ], - "path": "packages/kbn-mock-idp-plugin/common/utils.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], "initialIsOpen": false } ], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], "interfaces": [], "enums": [], "misc": [ - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_ATTRIBUTE_EMAIL", - "type": "string", - "tags": [], - "label": "MOCK_IDP_ATTRIBUTE_EMAIL", - "description": [], - "signature": [ - "\"http://saml.elastic-cloud.com/attributes/email\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_ATTRIBUTE_NAME", - "type": "string", - "tags": [], - "label": "MOCK_IDP_ATTRIBUTE_NAME", - "description": [], - "signature": [ - "\"http://saml.elastic-cloud.com/attributes/name\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_ATTRIBUTE_PRINCIPAL", - "type": "string", - "tags": [], - "label": "MOCK_IDP_ATTRIBUTE_PRINCIPAL", - "description": [], - "signature": [ - "\"http://saml.elastic-cloud.com/attributes/principal\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_ATTRIBUTE_ROLES", - "type": "string", - "tags": [], - "label": "MOCK_IDP_ATTRIBUTE_ROLES", - "description": [], - "signature": [ - "\"http://saml.elastic-cloud.com/attributes/roles\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_ENTITY_ID", - "type": "string", - "tags": [], - "label": "MOCK_IDP_ENTITY_ID", - "description": [], - "signature": [ - "\"urn:mock-idp\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_LOGIN_PATH", - "type": "string", - "tags": [], - "label": "MOCK_IDP_LOGIN_PATH", - "description": [], - "signature": [ - "\"/mock_idp/login\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_LOGOUT_PATH", - "type": "string", - "tags": [], - "label": "MOCK_IDP_LOGOUT_PATH", - "description": [], - "signature": [ - "\"/mock_idp/logout\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_METADATA_PATH", - "type": "string", - "tags": [], - "label": "MOCK_IDP_METADATA_PATH", - "description": [], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_PLUGIN_PATH", - "type": "string", - "tags": [], - "label": "MOCK_IDP_PLUGIN_PATH", - "description": [], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "mockIdpPlugin", "id": "def-common.MOCK_IDP_REALM_NAME", @@ -384,22 +48,7 @@ "signature": [ "\"mock-idp\"" ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "mockIdpPlugin", - "id": "def-common.MOCK_IDP_ROLE_MAPPING_NAME", - "type": "string", - "tags": [], - "label": "MOCK_IDP_ROLE_MAPPING_NAME", - "description": [], - "signature": [ - "\"mock-idp-mapping\"" - ], - "path": "packages/kbn-mock-idp-plugin/common/constants.ts", + "path": "packages/kbn-mock-idp-utils/src/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index c8060d8cc8bc9..7a08b5fc30a78 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; @@ -21,12 +21,14 @@ Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 25 | 0 | 19 | 0 | +| 2 | 0 | 2 | 0 | -## Common +## Server + +### Consts, variables and types + -### Functions - +## Common ### Consts, variables and types diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 7394a19e0540d..ed455232b960a 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: 2024-01-12 +date: 2024-01-16 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 4cd30ee68e653..0ef4e0c867c25 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: 2024-01-12 +date: 2024-01-16 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 a3d1f34b5b58c..7ad757bf750bd 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: 2024-01-12 +date: 2024-01-16 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 89a4134ba1d52..810cbcddff38e 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index d6b4da5a49c5b..24e4d1a66c7ba 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 500a81a100cfa..0d87d50aed7cb 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index b2b384bfc1a42..d114321d3fac5 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -4247,6 +4247,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-public.apmEnableTableSearchBar", + "type": "string", + "tags": [], + "label": "apmEnableTableSearchBar", + "description": [], + "signature": [ + "\"observability:apmEnableTableSearchBar\"" + ], + "path": "x-pack/plugins/observability/common/ui_settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-public.apmServiceGroupMaxNumberOfServices", @@ -14393,6 +14408,118 @@ } ] }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar", + "type": "Object", + "tags": [], + "label": "[apmEnableTableSearchBar]", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar.category", + "type": "Array", + "tags": [], + "label": "category", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar.schema", + "type": "Object", + "tags": [], + "label": "schema", + "description": [], + "signature": [ + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, + "" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar.value", + "type": "boolean", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "false" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar.requiresPageReload", + "type": "boolean", + "tags": [], + "label": "requiresPageReload", + "description": [], + "signature": [ + "false" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.uiSettings.apmEnableTableSearchBar.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "\"boolean\"" + ], + "path": "x-pack/plugins/observability/server/ui_settings.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, { "parentPluginId": "observability", "id": "def-server.uiSettings.apmAWSLambdaPriceFactor", @@ -16795,6 +16922,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-common.apmEnableTableSearchBar", + "type": "string", + "tags": [], + "label": "apmEnableTableSearchBar", + "description": [], + "signature": [ + "\"observability:apmEnableTableSearchBar\"" + ], + "path": "x-pack/plugins/observability/common/ui_settings_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-common.apmLabsButton", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index ab70cc2906dbc..b8520a0515540 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 605 | 2 | 596 | 17 | +| 615 | 2 | 606 | 17 | ## Client diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index ef48e6602d959..e46bf9cabe768 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_log_explorer.mdx b/api_docs/observability_log_explorer.mdx index afe5c76bcfa0a..8fcdda5ec9a75 100644 --- a/api_docs/observability_log_explorer.mdx +++ b/api_docs/observability_log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogExplorer title: "observabilityLogExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogExplorer plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogExplorer'] --- import observabilityLogExplorerObj from './observability_log_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 12b3e631bdbf9..6771bd1bad073 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index f1796189645a6..6f31481743603 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 2c10e8de65d47..be093d0103c2a 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index 7328fd622ccff..5262f6c28d38f 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index af65d94b296f6..11987a95c7853 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: 2024-01-12 +date: 2024-01-16 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 | |--------------|----------|------------------------| -| 739 | 631 | 41 | +| 740 | 632 | 41 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 78770 | 240 | 67446 | 1700 | +| 78851 | 240 | 67518 | 1702 | ## Plugin Directory @@ -57,7 +57,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 268 | 0 | 249 | 1 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 109 | 0 | 106 | 11 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 54 | 0 | 51 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | 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. | 3188 | 31 | 2537 | 22 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | 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. | 3220 | 31 | 2569 | 23 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 35 | 0 | 25 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Reusable data view field editor across Kibana | 72 | 0 | 33 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data view management app | 2 | 0 | 2 | 0 | @@ -91,7 +91,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'shape' function and renderer to expressions | 148 | 0 | 146 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. | 6 | 0 | 6 | 2 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression XY plugin adds a `xy` renderer and function to the expression plugin. The renderer will display the `xy` chart. | 177 | 0 | 167 | 13 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2211 | 17 | 1752 | 5 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2219 | 17 | 1757 | 5 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 235 | 0 | 99 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Index pattern fields and ambiguous values formatters | 292 | 5 | 253 | 3 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 59 | 0 | 59 | 2 | @@ -133,14 +133,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 60 | 0 | 60 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | Exposes utilities for accessing metrics data | 104 | 8 | 104 | 7 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 151 | 3 | 65 | 95 | -| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 25 | 0 | 19 | 0 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 15 | 3 | 13 | 1 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 42 | 0 | 42 | 3 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 605 | 2 | 596 | 17 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 615 | 2 | 606 | 17 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 75 | 0 | 73 | 13 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin exposes and registers observability log consumption features. | 18 | 0 | 18 | 1 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 14 | 0 | 14 | 0 | @@ -237,7 +237,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 22 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 34 | 0 | 34 | 8 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 44 | 0 | 44 | 8 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 188 | 0 | 188 | 28 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 11 | 0 | 11 | 0 | | | [@elastic/kibana-qa](https://github.com/orgs/elastic/teams/kibana-qa) | - | 12 | 0 | 12 | 0 | @@ -246,7 +246,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 7 | 0 | 7 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 19 | 0 | 16 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 60 | 1 | 42 | 3 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 14 | 0 | 10 | 0 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 27 | 0 | 22 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 78 | 0 | 78 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 7 | 0 | 2 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 3 | 0 | 3 | 0 | @@ -501,7 +501,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 23 | 0 | 7 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 8 | 0 | 2 | 3 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 45 | 0 | 0 | 0 | -| | [@elastic/appex-sharedux @elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 132 | 0 | 130 | 0 | +| | [@elastic/appex-sharedux @elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 133 | 0 | 131 | 0 | | | [@elastic/appex-sharedux @elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 20 | 0 | 11 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 81 | 0 | 3 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 54 | 0 | 6 | 0 | @@ -517,7 +517,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 48 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 11 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 36 | 4 | 8 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 11 | 0 | 0 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 12 | 0 | 1 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 3 | 0 | 2 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 5 | 0 | 3 | 0 | @@ -532,6 +532,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 33 | 0 | 28 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 18 | 0 | 18 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 31 | 1 | 24 | 1 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 25 | 0 | 18 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 98 | 0 | 96 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 55 | 1 | 50 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 10 | 0 | 10 | 2 | @@ -616,7 +617,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 4 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 2 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 8 | 0 | 2 | 1 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 26 | 0 | 8 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 30 | 0 | 8 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 28 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 61 | 0 | 48 | 5 | @@ -672,7 +673,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 7 | 0 | 6 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 112 | 0 | 51 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 14 | 0 | 13 | 6 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 291 | 0 | 267 | 9 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 291 | 0 | 267 | 10 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 13 | 0 | 9 | 0 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 3 | 0 | 0 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 3 | 0 | 2 | 1 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 0fee518d74a42..c890ad8e3cf63 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 8e422c0c7bf7b..ddb631a1b9878 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index 3e55fdb73f3e1..9adb71e715107 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index a12dc42057c23..a1ec8508df633 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: 2024-01-12 +date: 2024-01-16 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 dff000d3bc534..03d0f2252c9ea 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: 2024-01-12 +date: 2024-01-16 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 39d154a295d54..ac5d5e91b75bd 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: 2024-01-12 +date: 2024-01-16 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 9c471793653a6..1fe6dbb13279c 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: 2024-01-12 +date: 2024-01-16 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 05d42f6fe1919..af372f38dac0c 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: 2024-01-12 +date: 2024-01-16 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 62cc7561ae29e..70f5207f1f2b3 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 6c22c8e274eb0..0885542ea71d9 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 71cc2b051c8f0..1acd8a227c6e6 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: 2024-01-12 +date: 2024-01-16 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 0bf2bef2543d8..16cd81cb24ea5 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: 2024-01-12 +date: 2024-01-16 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 86a29c1b83c5a..c283dde957504 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: 2024-01-12 +date: 2024-01-16 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 50fabff819a92..033fbd00937ac 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: 2024-01-12 +date: 2024-01-16 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 379ddcff4cbf3..57a2adbbff3b5 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: 2024-01-12 +date: 2024-01-16 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 32727ab7f6c88..87f40cdc501b3 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: 2024-01-12 +date: 2024-01-16 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 9668a17fac9a0..0f7f31d17a060 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index 01e4de0e19596..aa8a4abeccd8b 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -114,7 +114,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/plugin.tsx", "deprecated": false, @@ -568,7 +568,7 @@ "\nExperimental flag needed to enable the link" ], "signature": [ - "\"assistantModelEvaluation\" | \"assistantStreamingEnabled\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" + "\"assistantModelEvaluation\" | \"assistantStreamingEnabled\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newUserDetailsFlyoutManagedUser\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -648,7 +648,7 @@ "\nExperimental flag needed to disable the link. Opposite of experimentalKey" ], "signature": [ - "\"assistantModelEvaluation\" | \"assistantStreamingEnabled\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"alertsPreviewChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" + "\"assistantModelEvaluation\" | \"assistantStreamingEnabled\" | \"tGridEnabled\" | \"tGridEventRenderedViewEnabled\" | \"excludePoliciesInFilterEnabled\" | \"kubernetesEnabled\" | \"chartEmbeddablesEnabled\" | \"donutChartEmbeddablesEnabled\" | \"previewTelemetryUrlEnabled\" | \"insightsRelatedAlertsByProcessAncestry\" | \"extendedRuleExecutionLoggingEnabled\" | \"socTrendsEnabled\" | \"responseActionsEnabled\" | \"endpointResponseActionsEnabled\" | \"responseActionUploadEnabled\" | \"responseActionsSentinelOneV1Enabled\" | \"alertsPageChartsEnabled\" | \"alertTypeEnabled\" | \"expandableFlyoutInCreateRuleEnabled\" | \"alertsPageFiltersEnabled\" | \"newUserDetailsFlyout\" | \"newUserDetailsFlyoutManagedUser\" | \"newHostDetailsFlyout\" | \"riskScoringPersistence\" | \"riskScoringRoutesEnabled\" | \"esqlRulesDisabled\" | \"protectionUpdatesEnabled\" | \"disableTimelineSaveTour\" | \"riskEnginePrivilegesRouteEnabled\" | \"entityAnalyticsAssetCriticalityEnabled\" | \"sentinelOneDataInAnalyzerEnabled\" | \"sentinelOneManualHostActionsEnabled\" | \"jsonPrebuiltRulesDiffingEnabled\" | \"timelineEsqlTabDisabled\" | undefined" ], "path": "x-pack/plugins/security_solution/public/common/links/types.ts", "deprecated": false, @@ -1913,7 +1913,7 @@ "label": "experimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -3018,7 +3018,7 @@ "\nThe security solution generic experimental features" ], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", "deprecated": false, @@ -3194,7 +3194,7 @@ "label": "ExperimentalFeatures", "description": [], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, @@ -3243,7 +3243,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly alertsPreviewChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" + "{ readonly tGridEnabled: boolean; readonly tGridEventRenderedViewEnabled: boolean; readonly excludePoliciesInFilterEnabled: boolean; readonly kubernetesEnabled: boolean; readonly chartEmbeddablesEnabled: boolean; readonly donutChartEmbeddablesEnabled: boolean; readonly previewTelemetryUrlEnabled: boolean; readonly insightsRelatedAlertsByProcessAncestry: boolean; readonly extendedRuleExecutionLoggingEnabled: boolean; readonly assistantStreamingEnabled: boolean; readonly socTrendsEnabled: boolean; readonly responseActionsEnabled: boolean; readonly endpointResponseActionsEnabled: boolean; readonly responseActionUploadEnabled: boolean; readonly responseActionsSentinelOneV1Enabled: boolean; readonly alertsPageChartsEnabled: boolean; readonly alertTypeEnabled: boolean; readonly expandableFlyoutInCreateRuleEnabled: boolean; readonly alertsPageFiltersEnabled: boolean; readonly assistantModelEvaluation: boolean; readonly newUserDetailsFlyout: boolean; readonly newUserDetailsFlyoutManagedUser: boolean; readonly newHostDetailsFlyout: boolean; readonly riskScoringPersistence: boolean; readonly riskScoringRoutesEnabled: boolean; readonly esqlRulesDisabled: boolean; readonly protectionUpdatesEnabled: boolean; readonly disableTimelineSaveTour: boolean; readonly riskEnginePrivilegesRouteEnabled: boolean; readonly entityAnalyticsAssetCriticalityEnabled: boolean; readonly sentinelOneDataInAnalyzerEnabled: boolean; readonly sentinelOneManualHostActionsEnabled: boolean; readonly jsonPrebuiltRulesDiffingEnabled: boolean; readonly timelineEsqlTabDisabled: boolean; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 22a7824b9add9..bf137d734a014 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index de5b317673823..6e6e5d8ad57ba 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index 8945b2a4340e6..973ae77528bda 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index bc73cba5a1285..b5d8130b22376 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index 1d8f57df4f049..310e9bb0b101a 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index d2d2e0588ee05..2eb484e9faf83 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 75d96e68c81fb..20c881bd38101 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: 2024-01-12 +date: 2024-01-16 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 0aa73c31b32bd..abefa1da21aa9 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: 2024-01-12 +date: 2024-01-16 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 ce6a02bc66bc2..7aaaf810b0fd3 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: 2024-01-12 +date: 2024-01-16 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 bc49ee935ab3a..f3b0e95a6c9d8 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: 2024-01-12 +date: 2024-01-16 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 ff9d62bbf9fe9..df50a30360d67 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index 38dd22f49d003..40efd539d3491 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 1a84a7ce85210..9a21be1960883 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: 2024-01-12 +date: 2024-01-16 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 b839867565cb7..23ac47e1f021e 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: 2024-01-12 +date: 2024-01-16 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 d85a64002598f..f19ee99f8459f 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: 2024-01-12 +date: 2024-01-16 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 fc8b31cffcc54..5c2eddc799fea 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: 2024-01-12 +date: 2024-01-16 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 8aab62350b3f3..f2cb169f302f2 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index 6c9be5a594c3e..fd7f6654c4adb 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 56ccf5f65539f..9c53778382f93 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index f599c20f96cbc..27e097bc61c7c 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: 2024-01-12 +date: 2024-01-16 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 5a4c83b5dd44b..844bafafd1aa2 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: 2024-01-12 +date: 2024-01-16 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 1b78b948e9faa..d723c422fbe06 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: 2024-01-12 +date: 2024-01-16 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 784d4b70da1c9..78d58cba5c4c6 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: 2024-01-12 +date: 2024-01-16 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 e6586885832c8..1d7baa3745e16 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index 7dfcfcd089019..447cdf99988ca 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.devdocs.json b/api_docs/unified_histogram.devdocs.json index 23dd7f92c4067..1b35d04fb831e 100644 --- a/api_docs/unified_histogram.devdocs.json +++ b/api_docs/unified_histogram.devdocs.json @@ -468,7 +468,7 @@ }, " | undefined; isChartLoading?: boolean | undefined; } & Pick<", "UnifiedHistogramLayoutProps", - ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"container\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\"> & ", + ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"container\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"renderCustomChartToggleActions\" | \"onFilter\" | \"withDefaultActions\"> & ", { "pluginId": "@kbn/shared-ux-utility", "scope": "common", @@ -1236,7 +1236,7 @@ }, " | undefined; isChartLoading?: boolean | undefined; } & Pick<", "UnifiedHistogramLayoutProps", - ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"container\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\">" + ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"container\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"renderCustomChartToggleActions\" | \"onFilter\" | \"withDefaultActions\">" ], "path": "src/plugins/unified_histogram/public/container/container.tsx", "deprecated": false, diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index ba73130534c3a..b9166917e32a5 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index b4086a5751d5e..22845b8d66197 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: 2024-01-12 +date: 2024-01-16 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 8f30ff6a4bd61..e803d6bb209ad 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 04dfebc633e2b..26ab7917cd879 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 82315df8f79cb..2b93ed71a1578 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: 2024-01-12 +date: 2024-01-16 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 983ee8fe7e0bf..7aa36df387b3c 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: 2024-01-12 +date: 2024-01-16 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 a82fbe25bd9b4..0b9b4f7cc3b21 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: 2024-01-12 +date: 2024-01-16 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 ca51dda826dab..b9d3137a29817 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: 2024-01-12 +date: 2024-01-16 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 3260bd8ca20c3..c37d13e4c6c58 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: 2024-01-12 +date: 2024-01-16 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 1fe5bff2321d6..4900e6fd37351 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: 2024-01-12 +date: 2024-01-16 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 fde80ef28eca4..47d658e2553b8 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: 2024-01-12 +date: 2024-01-16 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 9838078bf9c29..382aa1fb53c9f 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: 2024-01-12 +date: 2024-01-16 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 55987a87e6e05..3d9c6c44565ce 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: 2024-01-12 +date: 2024-01-16 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 ae3b2921b12a3..453e5685cdd27 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: 2024-01-12 +date: 2024-01-16 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 e4feece76c6f4..a760a43b9aaf5 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: 2024-01-12 +date: 2024-01-16 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 135bc755d662f..ad87d73ec3e14 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: 2024-01-12 +date: 2024-01-16 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 e5b416241666b..b69aa9902ced5 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 01bf0299a91ba..baa870f59a587 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: 2024-01-12 +date: 2024-01-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/docs/management/maintenance-windows/images/create-maintenance-window-filter.png b/docs/management/maintenance-windows/images/create-maintenance-window-filter.png new file mode 100644 index 0000000000000..23877293e426f Binary files /dev/null and b/docs/management/maintenance-windows/images/create-maintenance-window-filter.png differ diff --git a/docs/management/maintenance-windows/images/create-maintenance-window.png b/docs/management/maintenance-windows/images/create-maintenance-window.png index c6953d4e48693..b48c52ae9448d 100644 Binary files a/docs/management/maintenance-windows/images/create-maintenance-window.png and b/docs/management/maintenance-windows/images/create-maintenance-window.png differ diff --git a/docs/management/maintenance-windows/maintenance-windows.asciidoc b/docs/management/maintenance-windows/maintenance-windows.asciidoc index 9f7ffbae80edd..4bbdfb745022b 100644 --- a/docs/management/maintenance-windows/maintenance-windows.asciidoc +++ b/docs/management/maintenance-windows/maintenance-windows.asciidoc @@ -25,7 +25,7 @@ When the alert recovers, there are no notifications--even if the recovery occurs To use maintenance windows, you must have the appropriate {subscriptions}[subscription] and {kib} feature privileges. - To have full access to maintenance windows, you must have `All` privileges for the *Management > Maintenance Windows* feature. -- To have view-only access to maintenance windows, you must have `Read` privileges for the **Management > Maintenance Windows* feature. +- To have view-only access to maintenance windows, you must have `Read` privileges for the *Management > Maintenance Windows* feature. For more details, refer to <>. @@ -46,6 +46,18 @@ By default, maintenance windows affect all categories of rules. The category-specific maintenance window options alter this behavior. For the definitive list of rule types in each category, refer to the <>. +If you turn on *Filter alerts*, you can use KQL to filter the alerts affected by the maintenance window: + +[role="screenshot"] +image::images/create-maintenance-window-filter.png[The Create Maintenance Window user interface in {kib} with alert filters turned on] +// NOTE: This is an autogenerated screenshot. Do not edit it directly. + +[NOTE] +==== +* You can select only a single category when you turn on filters. +* Some rules are not affected by maintenance window filters because their alerts do not contain requisite data. In particular, <>, <>, {ml-docs}/ml-configuring-alerts.html[{anomaly-jobs} health], and {ref}/transform-alerts.html[transform health] rules are not affected by the filters. +==== + A maintenance window can have any one of the following statuses: - `Upcoming`: It will run at the scheduled date and time. diff --git a/docs/user/dashboard/create-panels-with-editors.asciidoc b/docs/user/dashboard/create-panels-with-editors.asciidoc index 37fd6f7c07d8d..d0cf77ef8a469 100644 --- a/docs/user/dashboard/create-panels-with-editors.asciidoc +++ b/docs/user/dashboard/create-panels-with-editors.asciidoc @@ -386,6 +386,12 @@ Bucket aggregations group, or bucket, documents based on the aggregation type. T | ✓ | ✓ +| IP prefix +| Use filters +| Use filters +| ✓ +| ✓ + | IP range | Use filters | Use filters diff --git a/fleet_packages.json b/fleet_packages.json index 1d70d88ee783f..fac968262d64b 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -24,7 +24,7 @@ [ { "name": "apm", - "version": "8.13.0-preview-1705022233", + "version": "8.13.0-preview-1705349439", "forceAlignStackVersion": true, "allowSyncToPrerelease": true }, diff --git a/package.json b/package.json index bfb63e64ffd9e..8755f072d7b57 100644 --- a/package.json +++ b/package.json @@ -889,7 +889,7 @@ "archiver": "^5.3.1", "async": "^3.2.3", "aws4": "^1.12.0", - "axios": "^1.6.5", + "axios": "^1.6.3", "base64-js": "^1.3.1", "bitmap-sdf": "^1.0.3", "blurhash": "^2.0.1", diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.isolated.test.mocks.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.isolated.test.mocks.ts new file mode 100644 index 0000000000000..be92b3fc91ef1 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.isolated.test.mocks.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const getSavedObjectFromSourceMock = jest.fn(); +export const rawDocExistsInNamespaceMock = jest.fn(); + +jest.doMock('./utils', () => { + const actual = jest.requireActual('./utils'); + return { + ...actual, + getSavedObjectFromSource: getSavedObjectFromSourceMock, + rawDocExistsInNamespace: rawDocExistsInNamespaceMock, + }; +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.isolated.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.isolated.test.ts new file mode 100644 index 0000000000000..f76747fdfab8c --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.isolated.test.ts @@ -0,0 +1,124 @@ +/* + * 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 { + getSavedObjectFromSourceMock, + rawDocExistsInNamespaceMock, +} from './bulk_get.isolated.test.mocks'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { SavedObject, CheckAuthorizationResult } from '@kbn/core-saved-objects-server'; +import { apiContextMock, ApiExecutionContextMock } from '../../mocks'; +import { performBulkGet } from './bulk_get'; + +interface ObjectInfo { + id: string; + type: string; + attributes: Record; +} + +const mgetResultToSavedObject = (hit: estypes.GetGetResult): SavedObject => { + const type = hit._source.type; + return { + type, + id: hit._id, + references: [], + attributes: hit._source[type], + }; +}; + +const createMgetResult = (object: ObjectInfo): estypes.GetGetResult => { + return { + _index: '.kibana', + found: true, + _id: object.id, + _source: { + type: object.type, + [object.type]: object.attributes, + }, + }; +}; + +const createMgetResponse = (objects: ObjectInfo[]): estypes.MgetResponse => { + return { + docs: objects.map(createMgetResult), + }; +}; + +describe('performBulkGet', () => { + let apiContext: ApiExecutionContextMock; + + beforeEach(() => { + apiContext = apiContextMock.create({ + allowedTypes: ['type'], + }); + + apiContext.helpers.common.getCurrentNamespace.mockReturnValue('default'); + apiContext.extensions.spacesExtension.getSearchableNamespaces.mockResolvedValue(['default']); + + getSavedObjectFromSourceMock.mockReset(); + rawDocExistsInNamespaceMock.mockReset().mockResolvedValue(true); + }); + + it('calls migrationHelper.migrateAndDecryptStorageDocument with the correct parameters', async () => { + const type = 'type'; + + apiContext.client.mget.mockResponse( + createMgetResponse([ + { + type, + id: 'id1', + attributes: { foo: '1' }, + }, + { + type, + id: 'id2', + attributes: { foo: '2' }, + }, + ]) + ); + + getSavedObjectFromSourceMock.mockImplementation((_registry, _type, _id, doc) => + mgetResultToSavedObject(doc) + ); + + const checkResult: CheckAuthorizationResult = { + status: 'fully_authorized', + typeMap: new Map(), + }; + apiContext.extensions.securityExtension.authorizeBulkGet.mockResolvedValue(checkResult); + + await performBulkGet( + { + objects: [ + { + type, + id: 'id1', + }, + { + type, + id: 'id2', + }, + ], + options: {}, + }, + apiContext + ); + + const results = getSavedObjectFromSourceMock.mock.results; + + expect(apiContext.helpers.migration.migrateAndDecryptStorageDocument).toHaveBeenCalledTimes( + results.length + ); + results.forEach((result) => { + expect(apiContext.helpers.migration.migrateAndDecryptStorageDocument).toHaveBeenCalledWith({ + document: result.value, + typeMap: checkResult.typeMap, + }); + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts index 3a135d4b73ce8..76d07d8e8f705 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts @@ -46,20 +46,11 @@ type ExpectedBulkGetResult = Either< export const performBulkGet = async ( { objects, options }: PerformBulkGetParams, - { - helpers, - allowedTypes, - client, - migrator, - serializer, - registry, - extensions = {}, - }: ApiExecutionContext + { helpers, allowedTypes, client, serializer, registry, extensions = {} }: ApiExecutionContext ): Promise> => { const { common: commonHelper, validation: validationHelper, - encryption: encryptionHelper, migration: migrationHelper, } = helpers; const { securityExtension, spacesExtension } = extensions; @@ -162,61 +153,67 @@ export const performBulkGet = async ( } const authObjects: AuthorizeBulkGetObject[] = []; - const result = { - saved_objects: expectedBulkGetResults.map((expectedResult) => { - if (isLeft(expectedResult)) { - const { type, id } = expectedResult.value; - authObjects.push({ type, id, existingNamespaces: [], error: true }); - return expectedResult.value as any; - } + const documents = expectedBulkGetResults.map>((expectedResult) => { + if (isLeft(expectedResult)) { + const { type, id } = expectedResult.value; + authObjects.push({ type, id, existingNamespaces: [], error: true }); + return expectedResult.value as any; + } - const { - type, - id, - // set to default namespaces value for `rawDocExistsInNamespaces` check below - namespaces = [SavedObjectsUtils.namespaceIdToString(namespace)], - esRequestIndex, - } = expectedResult.value; + const { + type, + id, + // set to default namespaces value for `rawDocExistsInNamespaces` check below + namespaces = [SavedObjectsUtils.namespaceIdToString(namespace)], + esRequestIndex, + } = expectedResult.value; + + const doc = bulkGetResponse?.body.docs[esRequestIndex]; - const doc = bulkGetResponse?.body.docs[esRequestIndex]; + // @ts-expect-error MultiGetHit._source is optional + const docNotFound = !doc?.found || !rawDocExistsInNamespaces(registry, doc, namespaces); + authObjects.push({ + type, + id, + objectNamespaces: namespaces, // @ts-expect-error MultiGetHit._source is optional - const docNotFound = !doc?.found || !rawDocExistsInNamespaces(registry, doc, namespaces); + existingNamespaces: doc?._source?.namespaces ?? [], + error: docNotFound, + }); - authObjects.push({ - type, + if (docNotFound) { + return { id, - objectNamespaces: namespaces, - // @ts-expect-error MultiGetHit._source is optional - existingNamespaces: doc?._source?.namespaces ?? [], - error: docNotFound, - }); - - if (docNotFound) { - return { - id, - type, - error: errorContent(SavedObjectsErrorHelpers.createGenericNotFoundError(type, id)), - } as any as SavedObject; - } - - // @ts-expect-error MultiGetHit._source is optional - const document = getSavedObjectFromSource(registry, type, id, doc, { - migrationVersionCompatibility, - }); - const migrated = migrationHelper.migrateStorageDocument(document); + type, + error: errorContent(SavedObjectsErrorHelpers.createGenericNotFoundError(type, id)), + } as any as SavedObject; + } - return migrated; - }), - }; + // @ts-expect-error MultiGetHit._source is optional + return getSavedObjectFromSource(registry, type, id, doc, { + migrationVersionCompatibility, + }); + }); const authorizationResult = await securityExtension?.authorizeBulkGet({ namespace, objects: authObjects, }); - return encryptionHelper.optionallyDecryptAndRedactBulkResult( - result, - authorizationResult?.typeMap - ); + const results: Array> = []; + for (const doc of documents) { + results.push( + doc.error + ? doc + : await migrationHelper.migrateAndDecryptStorageDocument({ + document: doc, + typeMap: authorizationResult?.typeMap, + }) + ); + } + + return { + saved_objects: results, + }; }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.test.ts index a71f8e27ccb98..77545f73f6bfa 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.test.ts @@ -114,7 +114,10 @@ describe('#bulkResolve', () => { ], }); expect(mockInternalBulkResolve).toHaveBeenCalledTimes(1); - expect(mockInternalBulkResolve).toHaveBeenCalledWith(expect.objectContaining({ objects })); + expect(mockInternalBulkResolve).toHaveBeenCalledWith( + expect.objectContaining({ objects }), + expect.any(Object) + ); }); it('throws when internalBulkResolve throws', async () => { diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.ts index a18b69ec29bf6..40d0931808e9c 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_resolve.ts @@ -27,33 +27,19 @@ export const performBulkResolve = async ( { objects, options }: PerformCreateParams, apiExecutionContext: ApiExecutionContext ): Promise> => { - const { - registry, - helpers, - allowedTypes, - client, - migrator, - serializer, - extensions = {}, - } = apiExecutionContext; - const { common: commonHelper } = helpers; - const { securityExtension, encryptionExtension } = extensions; + const { common: commonHelper } = apiExecutionContext.helpers; const namespace = commonHelper.getCurrentNamespace(options.namespace); - const { resolved_objects: bulkResults } = await internalBulkResolve({ - registry, - allowedTypes, - client, - migrator, - serializer, - getIndexForType: commonHelper.getIndexForType.bind(commonHelper), - incrementCounterInternal: (type, id, counterFields, opts = {}) => - incrementCounterInternal({ type, id, counterFields, options: opts }, apiExecutionContext), - encryptionExtension, - securityExtension, - objects, - options: { ...options, namespace }, - }); + const { resolved_objects: bulkResults } = await internalBulkResolve( + { + objects, + options: { ...options, namespace }, + incrementCounterInternal: (type, id, counterFields, opts = {}) => + incrementCounterInternal({ type, id, counterFields, options: opts }, apiExecutionContext), + }, + apiExecutionContext + ); + const resolvedObjects = bulkResults.map>((result) => { // extract payloads from saved object errors if (isBulkResolveError(result)) { diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.isolated.test.mocks.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.isolated.test.mocks.ts new file mode 100644 index 0000000000000..ec5154bcd38c1 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.isolated.test.mocks.ts @@ -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. + */ + +export const isSupportedEsServerMock = jest.fn(); + +jest.doMock('@kbn/core-elasticsearch-server-internal', () => { + const actual = jest.requireActual('@kbn/core-elasticsearch-server-internal'); + return { + ...actual, + isSupportedEsServer: isSupportedEsServerMock, + }; +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.isolated.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.isolated.test.ts new file mode 100644 index 0000000000000..b2a30d24a7bee --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.isolated.test.ts @@ -0,0 +1,113 @@ +/* + * 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 { isSupportedEsServerMock } from './find.isolated.test.mocks'; +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { SavedObject, AuthorizationTypeMap } from '@kbn/core-saved-objects-server'; +import { apiContextMock, ApiExecutionContextMock } from '../../mocks'; +import { performFind } from './find'; + +interface ObjectInfo { + id: string; + type: string; + attributes: Record; +} + +const hitToSavedObject = (hit: estypes.SearchHit): SavedObject => { + const type = hit._source.type; + return { + type, + id: hit._id, + references: [], + attributes: hit._source[type], + }; +}; + +const createHit = ({ type, id, attributes }: ObjectInfo): estypes.SearchHit => { + return { + _index: '.kibana', + _id: id, + _score: 1, + _seq_no: 1, + _primary_term: 1, + _source: { + type, + references: [], + [type]: attributes, + }, + }; +}; + +const createSuccessSearchResponse = (objects: ObjectInfo[]): estypes.SearchResponse => { + return { + took: 1, + timed_out: false, + _shards: {} as any, + hits: { + total: objects.length, + hits: objects.map(createHit), + }, + }; +}; + +describe('performFind', () => { + let apiContext: ApiExecutionContextMock; + + beforeEach(() => { + apiContext = apiContextMock.create({ + allowedTypes: ['type'], + }); + + isSupportedEsServerMock.mockReturnValue(true); + + apiContext.helpers.serializer.rawToSavedObject.mockImplementation(hitToSavedObject as any); + apiContext.extensions.spacesExtension.getSearchableNamespaces.mockResolvedValue(['default']); + }); + + it('calls migrationHelper.migrateAndDecryptStorageDocument with the correct parameters', async () => { + const type = 'type'; + + apiContext.client.search.mockResponse( + createSuccessSearchResponse([ + { + type, + id: 'id1', + attributes: { foo: '1' }, + }, + { + type, + id: 'id2', + attributes: { foo: '2' }, + }, + ]) + ); + + const authzTypeMap: AuthorizationTypeMap = new Map(); + apiContext.extensions.securityExtension.getFindRedactTypeMap.mockResolvedValue(authzTypeMap); + + await performFind( + { + options: { type }, + internalOptions: { + disableExtensions: false, + }, + }, + apiContext + ); + + expect(apiContext.helpers.migration.migrateAndDecryptStorageDocument).toHaveBeenCalledTimes(2); + + const results = apiContext.helpers.serializer.rawToSavedObject.mock.results; + results.forEach((result) => { + expect(apiContext.helpers.migration.migrateAndDecryptStorageDocument).toHaveBeenCalledWith({ + document: result.value, + typeMap: authzTypeMap, + }); + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.test.ts index 6a16b71b1d9af..9e6f03d2beac8 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.test.ts @@ -266,6 +266,7 @@ describe('find', () => { ...mockTimestampFields, version: mockVersion, score: doc._score, + sort: doc.sort, attributes: doc._source![doc._source!.type], references: [], namespaces: doc._source!.type === NAMESPACE_AGNOSTIC_TYPE ? undefined : ['default'], @@ -296,6 +297,7 @@ describe('find', () => { ...mockTimestampFields, version: mockVersion, score: doc._score, + sort: doc.sort, attributes: doc._source![doc._source!.type], references: [], namespaces: doc._source!.type === NAMESPACE_AGNOSTIC_TYPE ? undefined : [namespace], diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts index 3346e6552646a..62b5ccb82d68d 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts @@ -13,8 +13,8 @@ import { SavedObjectsErrorHelpers, type SavedObjectsRawDoc, CheckAuthorizationResult, - type SavedObject, SavedObjectsRawDocSource, + GetFindRedactTypeMapParams, } from '@kbn/core-saved-objects-server'; import { DEFAULT_NAMESPACE_STRING, @@ -49,13 +49,11 @@ export const performFind = async ( allowedTypes: rawAllowedTypes, mappings, client, - migrator, extensions = {}, }: ApiExecutionContext ): Promise> => { const { common: commonHelper, - encryption: encryptionHelper, serializer: serializerHelper, migration: migrationHelper, } = helpers; @@ -230,31 +228,52 @@ export const performFind = async ( return SavedObjectsUtils.createEmptyFindResponse(options); } - let result: SavedObjectsFindResponse; + // if extensions are enabled, we need to build an updated authorization type map + // to pass on to the redact method + const redactTypeMapParams: GetFindRedactTypeMapParams | undefined = disableExtensions + ? undefined + : { + previouslyCheckedNamespaces: spacesToAuthorize, + objects: [], + }; + const savedObjects: SavedObjectsFindResult[] = []; + + body.hits.hits.forEach((hit: estypes.SearchHit) => { + const obj = serializerHelper.rawToSavedObject(hit as SavedObjectsRawDoc, { + migrationVersionCompatibility, + }); + + if (redactTypeMapParams) { + redactTypeMapParams.objects.push({ + type: obj.type, + id: obj.id, + existingNamespaces: obj.namespaces ?? [], + }); + } + + savedObjects.push({ + ...obj, + score: hit._score!, + sort: hit.sort, + }); + }); + + const redactTypeMap = redactTypeMapParams + ? await securityExtension?.getFindRedactTypeMap(redactTypeMapParams) + : undefined; + + const migratedDocuments: Array> = []; try { - result = { - ...(body.aggregations ? { aggregations: body.aggregations as unknown as A } : {}), - page, - per_page: perPage, - total: body.hits.total, - saved_objects: body.hits.hits.map( - (hit: estypes.SearchHit): SavedObjectsFindResult => { - let savedObject = serializerHelper.rawToSavedObject(hit as SavedObjectsRawDoc, { - migrationVersionCompatibility, + for (const savedObject of savedObjects) { + const { sort, score, ...rawObject } = savedObject; + const migrated = disableExtensions + ? migrationHelper.migrateStorageDocument(rawObject) + : await migrationHelper.migrateAndDecryptStorageDocument({ + document: rawObject, + typeMap: redactTypeMap, }); - // can't migrate a document with partial attributes - if (!fields) { - savedObject = migrationHelper.migrateStorageDocument(savedObject) as SavedObject; - } - return { - ...savedObject, - score: hit._score!, - sort: hit.sort, - }; - } - ), - pit_id: body.pit_id, - } as typeof result; + migratedDocuments.push({ ...migrated, sort, score } as SavedObjectsFindResult); + } } catch (error) { throw SavedObjectsErrorHelpers.decorateGeneralError( error, @@ -262,25 +281,14 @@ export const performFind = async ( ); } - if (disableExtensions) { - return result; - } - - // Now that we have a full set of results with all existing namespaces for each object, - // we need an updated authorization type map to pass on to the redact method - const redactTypeMap = await securityExtension?.getFindRedactTypeMap({ - previouslyCheckedNamespaces: spacesToAuthorize, - objects: result.saved_objects.map((obj) => { - return { - type: obj.type, - id: obj.id, - existingNamespaces: obj.namespaces ?? [], - }; - }), - }); + const result: SavedObjectsFindResponse = { + ...(body.aggregations ? { aggregations: body.aggregations as unknown as A } : {}), + page, + per_page: perPage, + total: body.hits.total as number, + saved_objects: migratedDocuments, + pit_id: body.pit_id, + }; - return encryptionHelper.optionallyDecryptAndRedactBulkResult( - result, - redactTypeMap ?? authorizationResult?.typeMap // If the redact type map is valid, use that one; otherwise, fall back to the authorization check - ); + return result; }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.isolated.test.mocks.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.isolated.test.mocks.ts new file mode 100644 index 0000000000000..e4a205e888132 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.isolated.test.mocks.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const getSavedObjectFromSourceMock = jest.fn(); +export const isFoundGetResponseMock = jest.fn(); +export const rawDocExistsInNamespaceMock = jest.fn(); + +jest.doMock('./utils', () => { + const actual = jest.requireActual('./utils'); + return { + ...actual, + isFoundGetResponse: isFoundGetResponseMock, + getSavedObjectFromSource: getSavedObjectFromSourceMock, + rawDocExistsInNamespace: rawDocExistsInNamespaceMock, + }; +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.isolated.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.isolated.test.ts new file mode 100644 index 0000000000000..b07f573594fec --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.isolated.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + getSavedObjectFromSourceMock, + isFoundGetResponseMock, + rawDocExistsInNamespaceMock, +} from './get.isolated.test.mocks'; +import { SavedObject, CheckAuthorizationResult } from '@kbn/core-saved-objects-server'; +import { apiContextMock, ApiExecutionContextMock } from '../../mocks'; +import { performGet } from './get'; + +const createSavedObject = (id = 'foo'): SavedObject => { + return { + id, + type: 'bar', + attributes: {}, + references: [], + }; +}; + +describe('performGet', () => { + let apiContext: ApiExecutionContextMock; + + beforeEach(() => { + apiContext = apiContextMock.create({ + allowedTypes: ['type'], + }); + + getSavedObjectFromSourceMock.mockReset(); + isFoundGetResponseMock.mockReset().mockReturnValue(true); + rawDocExistsInNamespaceMock.mockReset().mockResolvedValue(true); + + apiContext.client.get.mockResponse({ _index: '.kibana', found: true, _id: '_id' }); + }); + + it('calls migrationHelper.migrateAndDecryptStorageDocument with the correct parameters', async () => { + const savedObject = createSavedObject(); + getSavedObjectFromSourceMock.mockReturnValue(savedObject); + + const checkResult: CheckAuthorizationResult = { + status: 'fully_authorized', + typeMap: new Map(), + }; + apiContext.extensions.securityExtension!.authorizeGet.mockResolvedValue(checkResult); + + const type = 'type'; + const id = 'id'; + + await performGet({ type, id, options: {} }, apiContext); + + expect(apiContext.helpers.migration.migrateAndDecryptStorageDocument).toHaveBeenCalledTimes(1); + expect(apiContext.helpers.migration.migrateAndDecryptStorageDocument).toHaveBeenCalledWith({ + document: savedObject, + typeMap: checkResult.typeMap, + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts index 215036f29583c..602498c3f4293 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts @@ -24,21 +24,9 @@ export interface PerformGetParams { export const performGet = async ( { type, id, options }: PerformGetParams, - { - registry, - helpers, - allowedTypes, - client, - migrator, - serializer, - extensions = {}, - }: ApiExecutionContext + { registry, helpers, allowedTypes, client, serializer, extensions = {} }: ApiExecutionContext ): Promise> => { - const { - common: commonHelper, - encryption: encryptionHelper, - migration: migrationHelper, - } = helpers; + const { common: commonHelper, migration: migrationHelper } = helpers; const { securityExtension } = extensions; const namespace = commonHelper.getCurrentNamespace(options.namespace); @@ -84,18 +72,8 @@ export const performGet = async ( migrationVersionCompatibility, }); - let migrated: SavedObject; - try { - migrated = migrationHelper.migrateStorageDocument(document) as SavedObject; - } catch (error) { - throw SavedObjectsErrorHelpers.decorateGeneralError( - error, - 'Failed to migrate document to the latest version.' - ); - } - - return encryptionHelper.optionallyDecryptAndRedactSingleResult( - migrated, - authorizationResult?.typeMap - ); + return await migrationHelper.migrateAndDecryptStorageDocument({ + document, + typeMap: authorizationResult?.typeMap, + }); }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.test.ts new file mode 100644 index 0000000000000..d252f2f2b38e5 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.test.ts @@ -0,0 +1,158 @@ +/* + * 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 { SavedObject, AuthorizationTypeMap } from '@kbn/core-saved-objects-server'; +import { + createMigratorMock, + createDocumentMigratorMock, + createEncryptionHelperMock, +} from '../../../mocks'; +import { MigrationHelper } from './migration'; + +const createSavedObject = (id = 'foo'): SavedObject => { + return { + id, + type: 'bar', + attributes: {}, + references: [], + }; +}; + +const createTypeMap = (): AuthorizationTypeMap => { + return new Map(); +}; + +describe('MigrationHelper', () => { + let documentMigrator: ReturnType; + let migrator: ReturnType; + let encryptionHelper: ReturnType; + + let migrationHelper: MigrationHelper; + + beforeEach(() => { + documentMigrator = createDocumentMigratorMock(); + migrator = createMigratorMock(); + migrator.getDocumentMigrator.mockReturnValue(documentMigrator); + encryptionHelper = createEncryptionHelperMock(); + + migrator.migrateDocument.mockImplementation((doc: unknown) => doc as any); + encryptionHelper.optionallyDecryptAndRedactSingleResult.mockImplementation( + (doc: unknown) => doc as any + ); + + migrationHelper = new MigrationHelper({ + encryptionHelper, + migrator, + }); + }); + + describe('migrateAndDecryptStorageDocument', () => { + it('calls documentMigrator.isDowngradeRequired with the correct parameters', async () => { + const doc = createSavedObject(); + + await migrationHelper.migrateAndDecryptStorageDocument({ + document: doc, + typeMap: undefined, + }); + + expect(documentMigrator.isDowngradeRequired).toHaveBeenCalledTimes(1); + expect(documentMigrator.isDowngradeRequired).toHaveBeenCalledWith(doc); + }); + + it('calls migrator.migrateDocument with the correct parameters', async () => { + const doc = createSavedObject(); + + await migrationHelper.migrateAndDecryptStorageDocument({ + document: doc, + typeMap: undefined, + }); + + expect(migrator.migrateDocument).toHaveBeenCalledTimes(1); + expect(migrator.migrateDocument).toHaveBeenCalledWith(doc, { allowDowngrade: true }); + }); + + it('calls encryptionHelper.optionallyDecryptAndRedactSingleResult with the correct parameters', async () => { + const doc = createSavedObject(); + const typeMap = createTypeMap(); + const originalAttributes = { unknown: true }; + + await migrationHelper.migrateAndDecryptStorageDocument({ + document: doc, + typeMap, + originalAttributes, + }); + + expect(encryptionHelper.optionallyDecryptAndRedactSingleResult).toHaveBeenCalledTimes(1); + expect(encryptionHelper.optionallyDecryptAndRedactSingleResult).toHaveBeenCalledWith( + doc, + typeMap, + originalAttributes + ); + }); + + it('performs the calls in the correct order when isDowngradeRequired returns false', async () => { + documentMigrator.isDowngradeRequired.mockReturnValue(false); + + const doc = createSavedObject(); + const typeMap = createTypeMap(); + const originalAttributes = { unknown: true }; + + const migratedDoc = createSavedObject('another_id'); + migrator.migrateDocument.mockReturnValue(migratedDoc); + + await migrationHelper.migrateAndDecryptStorageDocument({ + document: doc, + typeMap, + originalAttributes, + }); + + expect(migrator.migrateDocument).toHaveBeenCalledTimes(1); + expect(encryptionHelper.optionallyDecryptAndRedactSingleResult).toHaveBeenCalledTimes(1); + + const migrateCallOrder = migrator.migrateDocument.mock.invocationCallOrder[0]; + const encryptionCallOrder = + encryptionHelper.optionallyDecryptAndRedactSingleResult.mock.invocationCallOrder[0]; + + expect(migrateCallOrder).toBeLessThan(encryptionCallOrder); + + expect(encryptionHelper.optionallyDecryptAndRedactSingleResult).toHaveBeenCalledWith( + migratedDoc, + typeMap, + originalAttributes + ); + }); + + it('performs the calls in the correct order when isDowngradeRequired returns true', async () => { + documentMigrator.isDowngradeRequired.mockReturnValue(true); + + const doc = createSavedObject(); + const typeMap = createTypeMap(); + const originalAttributes = { unknown: true }; + + const decryptedDoc = createSavedObject('another_id'); + encryptionHelper.optionallyDecryptAndRedactSingleResult.mockReturnValue(decryptedDoc as any); + + await migrationHelper.migrateAndDecryptStorageDocument({ + document: doc, + typeMap, + originalAttributes, + }); + + expect(migrator.migrateDocument).toHaveBeenCalledTimes(1); + expect(encryptionHelper.optionallyDecryptAndRedactSingleResult).toHaveBeenCalledTimes(1); + + const migrateCallOrder = migrator.migrateDocument.mock.invocationCallOrder[0]; + const encryptionCallOrder = + encryptionHelper.optionallyDecryptAndRedactSingleResult.mock.invocationCallOrder[0]; + + expect(encryptionCallOrder).toBeLessThan(migrateCallOrder); + + expect(migrator.migrateDocument).toHaveBeenCalledWith(decryptedDoc, { allowDowngrade: true }); + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.ts index c7ae86b101984..2530d60ad6608 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.ts @@ -7,8 +7,14 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import type { SavedObjectUnsanitizedDoc } from '@kbn/core-saved-objects-server'; +import { + SavedObjectsErrorHelpers, + type SavedObjectUnsanitizedDoc, + type AuthorizationTypeMap, + type SavedObject, +} from '@kbn/core-saved-objects-server'; import type { IKibanaMigrator } from '@kbn/core-saved-objects-base-server-internal'; +import type { IEncryptionHelper } from './encryption'; export type IMigrationHelper = PublicMethodsOf; @@ -17,9 +23,17 @@ export type IMigrationHelper = PublicMethodsOf; */ export class MigrationHelper { private migrator: IKibanaMigrator; + private encryptionHelper: IEncryptionHelper; - constructor({ migrator }: { migrator: IKibanaMigrator }) { + constructor({ + migrator, + encryptionHelper, + }: { + migrator: IKibanaMigrator; + encryptionHelper: IEncryptionHelper; + }) { this.migrator = migrator; + this.encryptionHelper = encryptionHelper; } /** @@ -39,4 +53,41 @@ export class MigrationHelper { migrateStorageDocument(document: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc { return this.migrator.migrateDocument(document, { allowDowngrade: true }); } + + async migrateAndDecryptStorageDocument({ + document, + typeMap, + originalAttributes, + }: { + document: SavedObjectUnsanitizedDoc | SavedObject; + typeMap: AuthorizationTypeMap | undefined; + originalAttributes?: T; + }): Promise> { + const downgrade = this.migrator.getDocumentMigrator().isDowngradeRequired(document); + + const migrate = (doc: SavedObjectUnsanitizedDoc | SavedObject) => { + try { + return this.migrator.migrateDocument(doc, { allowDowngrade: true }) as SavedObject; + } catch (error) { + throw SavedObjectsErrorHelpers.decorateGeneralError( + error, + 'Failed to migrate document to the latest version.' + ); + } + }; + + const decrypt = (doc: SavedObjectUnsanitizedDoc | SavedObject) => { + return this.encryptionHelper.optionallyDecryptAndRedactSingleResult( + doc as SavedObject, + typeMap, + originalAttributes + ); + }; + + if (downgrade) { + return migrate(await decrypt(document)); + } else { + return await decrypt(migrate(document)); + } + } } diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts index 6abb1b6acf55f..0997e9d1328ff 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts @@ -30,7 +30,7 @@ export interface PerformIncrementCounterInternalParams { export const incrementCounterInternal = async ( { type, id, counterFields, options }: PerformIncrementCounterInternalParams, - { registry, helpers, client, serializer, migrator }: ApiExecutionContext + { registry, helpers, client, serializer }: ApiExecutionContext ): Promise> => { const { common: commonHelper, preflight: preflightHelper, migration: migrationHelper } = helpers; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts index d1fb50a1bc08a..b195423f46f5d 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts @@ -26,12 +26,9 @@ import { typeRegistryMock } from '@kbn/core-saved-objects-base-server-mocks'; import { internalBulkResolve, type InternalBulkResolveParams } from './internal_bulk_resolve'; import { normalizeNamespace } from '../utils'; import { - type ISavedObjectsEncryptionExtension, type ISavedObjectsSecurityExtension, - type ISavedObjectTypeRegistry, type SavedObject, SavedObjectsErrorHelpers, - type SavedObjectUnsanitizedDoc, } from '@kbn/core-saved-objects-server'; import { enforceError, @@ -39,7 +36,7 @@ import { setupAuthorizeAndRedactInternalBulkResolveSuccess, } from '../../../test_helpers/repository.test.common'; import { savedObjectsExtensionsMock } from '../../../mocks/saved_objects_extensions.mock'; -import { kibanaMigratorMock } from '../../../mocks'; +import { apiContextMock, type ApiExecutionContextMock } from '../../../mocks'; const VERSION_PROPS = { _seq_no: 1, _primary_term: 1 }; const OBJ_TYPE = 'obj-type'; @@ -59,35 +56,38 @@ beforeEach(() => { describe('internalBulkResolve', () => { let client: ReturnType; - let migrator: ReturnType; - let serializer: SavedObjectsSerializer; let incrementCounterInternal: jest.Mock; - let registry: jest.Mocked; + let serializer: SavedObjectsSerializer; + let apiContext: ApiExecutionContextMock; + + beforeEach(() => { + apiContext = apiContextMock.create({ allowedTypes: [OBJ_TYPE, ENCRYPTED_TYPE] }); + + apiContext.helpers.common.getIndexForType.mockImplementation( + (type: string) => `index-for-${type}` + ); + + apiContext.helpers.migration.migrateAndDecryptStorageDocument.mockImplementation( + ({ document }) => Promise.resolve(document as SavedObject) + ); + + apiContext.extensions = {} as unknown as typeof apiContext.extensions; + + client = apiContext.client; + + const registry = typeRegistryMock.create(); + serializer = new SavedObjectsSerializer(registry); + apiContext.serializer = serializer as unknown as typeof apiContext.serializer; + }); /** Sets up the type registry, saved objects client, etc. and return the full parameters object to be passed to `internalBulkResolve` */ function setup( objects: SavedObjectsBulkResolveObject[], - options: SavedObjectsBaseOptions = {}, - extensions?: { - encryptionExt?: ISavedObjectsEncryptionExtension; - securityExt?: ISavedObjectsSecurityExtension; - } + options: SavedObjectsBaseOptions = {} ): InternalBulkResolveParams { - registry = typeRegistryMock.create(); - client = elasticsearchClientMock.createElasticsearchClient(); - migrator = kibanaMigratorMock.create(); - serializer = new SavedObjectsSerializer(registry); incrementCounterInternal = jest.fn().mockRejectedValue(new Error('increment error')); // mock error to implicitly test that it is caught and swallowed return { - registry, - allowedTypes: [OBJ_TYPE, ENCRYPTED_TYPE], - migrator, - client, - serializer, - getIndexForType: (type: string) => `index-for-${type}`, incrementCounterInternal, - encryptionExtension: extensions?.encryptionExt, - securityExtension: extensions?.securityExt, objects, options, }; @@ -242,7 +242,7 @@ describe('internalBulkResolve', () => { ); mockIsNotFoundFromUnsupportedServer.mockReturnValue(true); - await expect(() => internalBulkResolve(params)).rejects.toThrow( + await expect(() => internalBulkResolve(params, apiContext)).rejects.toThrow( SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError() ); expect(client.bulk).toHaveBeenCalledTimes(1); @@ -252,7 +252,7 @@ describe('internalBulkResolve', () => { it('returns an empty array if no object args are passed in', async () => { const params = setup([], { namespace }); - const result = await internalBulkResolve(params); + const result = await internalBulkResolve(params, apiContext); expect(client.bulk).not.toHaveBeenCalled(); expect(client.mget).not.toHaveBeenCalled(); expect(result.resolved_objects).toEqual([]); @@ -262,7 +262,7 @@ describe('internalBulkResolve', () => { const objects = [{ type: UNSUPPORTED_TYPE, id: '1' }]; const params = setup(objects, { namespace }); - const result = await internalBulkResolve(params); + const result = await internalBulkResolve(params, apiContext); expect(client.bulk).not.toHaveBeenCalled(); expect(client.mget).not.toHaveBeenCalled(); expect(result.resolved_objects).toEqual([expectUnsupportedTypeError({ id: '1' })]); @@ -289,7 +289,7 @@ describe('internalBulkResolve', () => { ); mockRawDocExistsInNamespace.mockReturnValue(false); // for objs 3 and 3-newId - const result = await internalBulkResolve(params); + const result = await internalBulkResolve(params, apiContext); expectBulkArgs(expectedNamespaceString, ['1', '2', '3']); expectMgetArgs(namespace, ['1', '2', '2-newId', '3', '3-newId']); expect(mockRawDocExistsInNamespace).toHaveBeenCalledTimes(2); // for objs 3 and 3-newId @@ -311,7 +311,7 @@ describe('internalBulkResolve', () => { // does not attempt to fetch obj 1-newId, because that alias is disabled ); - const result = await internalBulkResolve(params); + const result = await internalBulkResolve(params, apiContext); expectBulkArgs(expectedNamespaceString, ['1']); expectMgetArgs(namespace, ['1']); expect(result.resolved_objects).toEqual([ @@ -352,7 +352,7 @@ describe('internalBulkResolve', () => { { found: true } // fetch obj 7-newId ); - const result = await internalBulkResolve(params); + const result = await internalBulkResolve(params, apiContext); const bulkIds = ['2', '3', '4', '5', '6', '7']; expectBulkArgs(expectedNamespaceString, bulkIds); const mgetIds = ['2', '3', '4', '4-newId', '5', '5-newId', '6', '6-newId', '7', '7-newId']; @@ -368,7 +368,7 @@ describe('internalBulkResolve', () => { ]); }); - it('migrates the resolved objects', async () => { + it('migrates and decrypts the resolved objects', async () => { const objects = [ { type: OBJ_TYPE, id: '1' }, { type: OBJ_TYPE, id: '2' }, @@ -376,81 +376,28 @@ describe('internalBulkResolve', () => { const params = setup(objects, { namespace }); mockBulkResults({ found: false }, { found: false }); mockMgetResults({ found: true }, { found: true }); - migrator.migrateDocument.mockImplementation( - (doc) => `migrated-${doc}` as unknown as SavedObjectUnsanitizedDoc + const migrationHelper = apiContext.helpers.migration; + migrationHelper.migrateAndDecryptStorageDocument.mockImplementation(({ document }) => + Promise.resolve(`migrated-${document}` as unknown as SavedObject) ); - await expect(internalBulkResolve(params)).resolves.toHaveProperty('resolved_objects', [ - expect.objectContaining({ saved_object: 'migrated-mock-obj-for-1' }), - expect.objectContaining({ saved_object: 'migrated-mock-obj-for-2' }), - ]); - - expect(migrator.migrateDocument).toHaveBeenCalledTimes(2); - expect(migrator.migrateDocument).nthCalledWith( - 1, - 'mock-obj-for-1', - expect.objectContaining({ allowDowngrade: expect.any(Boolean) }) + await expect(internalBulkResolve(params, apiContext)).resolves.toHaveProperty( + 'resolved_objects', + [ + expect.objectContaining({ saved_object: 'migrated-mock-obj-for-1' }), + expect.objectContaining({ saved_object: 'migrated-mock-obj-for-2' }), + ] ); - expect(migrator.migrateDocument).nthCalledWith(2, 'mock-obj-for-2', { - allowDowngrade: expect.any(Boolean), - }); - }); - }); - - describe('with encryption extension', () => { - const namespace = 'foo'; - - const attributes = { - attrNotSoSecret: '*not-so-secret*', - attrOne: 'one', - attrSecret: '*secret*', - attrThree: 'three', - title: 'Testing', - }; - beforeEach(() => { - mockGetSavedObjectFromSource.mockImplementation((_registry, type, id) => { - return { - id, - type, - namespaces: [namespace], - attributes, - references: [], - } as SavedObject; + expect(migrationHelper.migrateAndDecryptStorageDocument).toHaveBeenCalledTimes(2); + expect(migrationHelper.migrateAndDecryptStorageDocument).nthCalledWith(1, { + document: 'mock-obj-for-1', + typeMap: undefined, + }); + expect(migrationHelper.migrateAndDecryptStorageDocument).nthCalledWith(2, { + document: 'mock-obj-for-2', + typeMap: undefined, }); - }); - - it('only attempts to decrypt and strip attributes for types that are encryptable', async () => { - const objects = [ - { type: OBJ_TYPE, id: '11' }, // non encryptable type - { type: ENCRYPTED_TYPE, id: '12' }, // encryptable type - ]; - const mockEncryptionExt = savedObjectsExtensionsMock.createEncryptionExtension(); - const params = setup(objects, { namespace }, { encryptionExt: mockEncryptionExt }); - mockBulkResults( - // No alias matches - { found: false }, - { found: false } - ); - mockMgetResults( - // exact matches - { found: true }, - { found: true } - ); - - mockEncryptionExt.isEncryptableType.mockReturnValueOnce(false); - mockEncryptionExt.isEncryptableType.mockReturnValueOnce(true); - - await internalBulkResolve(params); - - expect(mockEncryptionExt.isEncryptableType).toBeCalledTimes(2); - expect(mockEncryptionExt.isEncryptableType).toBeCalledWith(OBJ_TYPE); - expect(mockEncryptionExt.isEncryptableType).toBeCalledWith(ENCRYPTED_TYPE); - - expect(mockEncryptionExt.decryptOrStripResponseAttributes).toBeCalledTimes(1); - expect(mockEncryptionExt.decryptOrStripResponseAttributes).toBeCalledWith( - expect.objectContaining({ type: ENCRYPTED_TYPE, id: '12', attributes }) - ); }); }); @@ -487,7 +434,8 @@ describe('internalBulkResolve', () => { }); mockSecurityExt = savedObjectsExtensionsMock.createSecurityExtension(); - params = setup(objects, { namespace }, { securityExt: mockSecurityExt }); + apiContext.extensions.securityExtension = mockSecurityExt; + params = setup(objects, { namespace }); mockBulkResults( // No alias matches @@ -503,14 +451,14 @@ describe('internalBulkResolve', () => { test(`propagates decorated error when unauthorized`, async () => { setupAuthorizeAndRedactInternalBulkResolveFailure(mockSecurityExt); - await expect(internalBulkResolve(params)).rejects.toThrow(enforceError); + await expect(internalBulkResolve(params, apiContext)).rejects.toThrow(enforceError); expect(mockSecurityExt.authorizeAndRedactInternalBulkResolve).toHaveBeenCalledTimes(1); }); test(`returns result when successful`, async () => { setupAuthorizeAndRedactInternalBulkResolveSuccess(mockSecurityExt); - const result = await internalBulkResolve(params); + const result = await internalBulkResolve(params, apiContext); expect(mockSecurityExt.authorizeAndRedactInternalBulkResolve).toHaveBeenCalledTimes(1); const bulkIds = objects.map((obj) => obj.id); @@ -524,7 +472,7 @@ describe('internalBulkResolve', () => { test(`returns empty array when no objects are provided`, async () => { setupAuthorizeAndRedactInternalBulkResolveSuccess(mockSecurityExt); - const result = await internalBulkResolve({ ...params, objects: [] }); + const result = await internalBulkResolve({ ...params, objects: [] }, apiContext); expect(result).toEqual({ resolved_objects: [] }); expect(mockSecurityExt.authorizeAndRedactInternalBulkResolve).not.toHaveBeenCalled(); }); @@ -536,7 +484,7 @@ describe('internalBulkResolve', () => { test(`in the default space`, async () => { await expect( - internalBulkResolve({ ...params, options: { namespace: 'default' } }) + internalBulkResolve({ ...params, options: { namespace: 'default' } }, apiContext) ).rejects.toThrow(enforceError); expect(mockSecurityExt.authorizeAndRedactInternalBulkResolve).toHaveBeenCalledTimes(1); @@ -547,7 +495,7 @@ describe('internalBulkResolve', () => { }); test(`in a non-default space`, async () => { - await expect(internalBulkResolve(params)).rejects.toThrow(enforceError); + await expect(internalBulkResolve(params, apiContext)).rejects.toThrow(enforceError); expect(mockSecurityExt.authorizeAndRedactInternalBulkResolve).toHaveBeenCalledTimes(1); const { namespace: actualNamespace, objects: actualObjects } = diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts index 53cb04453555c..ef2afc5b8a95f 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts @@ -17,9 +17,6 @@ import type { SavedObjectsIncrementCounterOptions, } from '@kbn/core-saved-objects-api-server'; import { - type ISavedObjectsEncryptionExtension, - type ISavedObjectsSecurityExtension, - type ISavedObjectTypeRegistry, type SavedObjectsRawDocSource, type SavedObject, type BulkResolveError, @@ -27,7 +24,6 @@ import { SavedObjectsErrorHelpers, } from '@kbn/core-saved-objects-server'; import { - type IKibanaMigrator, LEGACY_URL_ALIAS_TYPE, type LegacyUrlAlias, } from '@kbn/core-saved-objects-base-server-internal'; @@ -49,6 +45,7 @@ import { left, right, } from '../utils'; +import type { ApiExecutionContext } from '../types'; import type { RepositoryEsClient } from '../../repository_es_client'; const MAX_CONCURRENT_RESOLVE = 10; @@ -59,22 +56,14 @@ const MAX_CONCURRENT_RESOLVE = 10; * @internal */ export interface InternalBulkResolveParams { - registry: ISavedObjectTypeRegistry; - migrator: IKibanaMigrator; - allowedTypes: string[]; - client: RepositoryEsClient; - serializer: ISavedObjectsSerializer; - getIndexForType: (type: string) => string; + objects: SavedObjectsBulkResolveObject[]; + options?: SavedObjectsResolveOptions; incrementCounterInternal: ( type: string, id: string, counterFields: Array, options?: SavedObjectsIncrementCounterOptions ) => Promise>; - encryptionExtension: ISavedObjectsEncryptionExtension | undefined; - securityExtension: ISavedObjectsSecurityExtension | undefined; - objects: SavedObjectsBulkResolveObject[]; - options?: SavedObjectsResolveOptions; } /** @@ -96,21 +85,14 @@ export function isBulkResolveError( type AliasInfo = Pick; export async function internalBulkResolve( - params: InternalBulkResolveParams + params: InternalBulkResolveParams, + apiExecutionContext: ApiExecutionContext ): Promise> { - const { - registry, - migrator, - allowedTypes, - client, - serializer, - getIndexForType, - incrementCounterInternal, - encryptionExtension, - securityExtension, - objects, - options = {}, - } = params; + const { incrementCounterInternal, objects, options = {} } = params; + + const { registry, allowedTypes, client, serializer } = apiExecutionContext; + const { common: commonHelper, migration: migrationHelper } = apiExecutionContext.helpers; + const { securityExtension } = apiExecutionContext.extensions; if (objects.length === 0) { return { resolved_objects: [] }; @@ -126,14 +108,14 @@ export async function internalBulkResolve( validObjects, client, serializer, - getIndexForType, + commonHelper.getIndexForType.bind(commonHelper), namespace ); const docsToBulkGet: Array<{ _id: string; _index: string }> = []; const aliasInfoArray: Array = []; validObjects.forEach(({ value: { type, id } }, i) => { - const objectIndex = getIndexForType(type); + const objectIndex = commonHelper.getIndexForType(type); docsToBulkGet.push({ // attempt to find an exact match for the given ID _id: serializer.generateRawId(namespace, type, id), @@ -182,17 +164,15 @@ export async function internalBulkResolve( objectId: string, doc: MgetResponseItem ) { - // Encryption // @ts-expect-error MultiGetHit._source is optional const object = getSavedObjectFromSource(registry, objectType, objectId, doc, { migrationVersionCompatibility, }); - const migrated = migrator.migrateDocument(object, { allowDowngrade: true }) as SavedObject; - - if (!encryptionExtension?.isEncryptableType(migrated.type)) { - return migrated; - } - return encryptionExtension.decryptOrStripResponseAttributes(migrated); + // migrate and decrypt document + return await migrationHelper.migrateAndDecryptStorageDocument({ + document: object, + typeMap: undefined, + }); } // map function for pMap below @@ -275,9 +255,11 @@ export async function internalBulkResolve( { refresh: false } ).catch(() => {}); // if the call fails for some reason, intentionally swallow the error - if (!securityExtension) return { resolved_objects: resolvedObjects }; + if (!securityExtension) { + return { resolved_objects: resolvedObjects }; + } - const redactedObjects = await securityExtension?.authorizeAndRedactInternalBulkResolve({ + const redactedObjects = await securityExtension.authorizeAndRedactInternalBulkResolve({ namespace, objects: resolvedObjects, }); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.test.ts index 25acc55cc77c2..957dd69af06ee 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.test.ts @@ -86,7 +86,8 @@ describe('SavedObjectsRepository', () => { await expect(repository.resolve('obj-type', 'obj-id')).resolves.toEqual(expectedResult); expect(mockInternalBulkResolve).toHaveBeenCalledTimes(1); expect(mockInternalBulkResolve).toHaveBeenCalledWith( - expect.objectContaining({ objects: [{ type: 'obj-type', id: 'obj-id' }] }) + expect.objectContaining({ objects: [{ type: 'obj-type', id: 'obj-id' }] }), + expect.any(Object) ); }); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.ts index 50de472546344..6e940dac047bb 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/resolve.ts @@ -24,35 +24,21 @@ export const performResolve = async ( { type, id, options }: PerformCreateParams, apiExecutionContext: ApiExecutionContext ): Promise> => { - const { - registry, - helpers, - allowedTypes, - client, - migrator, - serializer, - extensions = {}, - } = apiExecutionContext; - const { common: commonHelper } = helpers; - const { securityExtension, encryptionExtension } = extensions; + const { common: commonHelper } = apiExecutionContext.helpers; const namespace = commonHelper.getCurrentNamespace(options.namespace); - const { resolved_objects: bulkResults } = await internalBulkResolve({ - registry, - allowedTypes, - client, - migrator, - serializer, - getIndexForType: commonHelper.getIndexForType.bind(commonHelper), - incrementCounterInternal: (t, i, counterFields, opts = {}) => - incrementCounterInternal( - { type: t, id: i, counterFields, options: opts }, - apiExecutionContext - ), - encryptionExtension, - securityExtension, - objects: [{ type, id }], - options: { ...options, namespace }, - }); + const { resolved_objects: bulkResults } = await internalBulkResolve( + { + objects: [{ type, id }], + options: { ...options, namespace }, + incrementCounterInternal: (t, i, counterFields, opts = {}) => + incrementCounterInternal( + { type: t, id: i, counterFields, options: opts }, + apiExecutionContext + ), + }, + apiExecutionContext + ); + const [result] = bulkResults; if (isBulkResolveError(result)) { throw result.error; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts index 82a7d2930f8d5..ec5fe1d4b25de 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts @@ -518,7 +518,8 @@ describe('SavedObjectsRepository Spaces Extension', () => { ? currentSpace.expectedNamespace : undefined, }, - }) + }), + expect.any(Object) ); }); }); @@ -764,7 +765,8 @@ describe('SavedObjectsRepository Spaces Extension', () => { ? `${currentSpace.expectedNamespace}` : undefined, }, - }) + }), + expect.any(Object) ); }); }); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/create_helpers.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/create_helpers.ts index 17a17be122916..087f3690886b1 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/create_helpers.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/create_helpers.ts @@ -78,6 +78,7 @@ export const createRepositoryHelpers = ({ }); const migrationHelper = new MigrationHelper({ migrator, + encryptionHelper, }); const helpers: RepositoryHelpers = { diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_context.mock.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_context.mock.ts index 3b4da315868fa..22caaaa56a714 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_context.mock.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_context.mock.ts @@ -28,7 +28,11 @@ export type ApiExecutionContextMock = Pick { +const createApiExecutionContextMock = ({ + allowedTypes = ['foo', 'bar'], +}: { + allowedTypes?: string[]; +} = {}): ApiExecutionContextMock => { return { registry: new SavedObjectTypeRegistry(), helpers: apiHelperMocks.create(), @@ -37,7 +41,7 @@ const createApiExecutionContextMock = (): ApiExecutionContextMock => { serializer: serializerMock.create(), migrator: createMigratorMock(), logger: loggerMock.create(), - allowedTypes: ['foo', 'bar'], + allowedTypes, mappings: { properties: { mockMappings: { type: 'text' } } }, }; }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts index e50cc4d1036eb..d284bddd5c060 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { SavedObject } from '@kbn/core-saved-objects-server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import type { CommonHelper, @@ -22,10 +23,14 @@ const createMigrationHelperMock = (): MigrationHelperMock => { const mock: MigrationHelperMock = { migrateInputDocument: jest.fn(), migrateStorageDocument: jest.fn(), + migrateAndDecryptStorageDocument: jest.fn(), }; mock.migrateInputDocument.mockImplementation((doc) => doc); mock.migrateStorageDocument.mockImplementation((doc) => doc); + mock.migrateAndDecryptStorageDocument.mockImplementation(({ document }) => + Promise.resolve(document as SavedObject) + ); return mock; }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/helpers.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/helpers.ts new file mode 100644 index 0000000000000..5d05cd65b9e27 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/helpers.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { IEncryptionHelper } from '../lib/apis/helpers/encryption'; + +export type IEncryptionHelperMock = jest.Mocked; + +export const createEncryptionHelperMock = (): IEncryptionHelperMock => { + const mock: IEncryptionHelperMock = { + optionallyEncryptAttributes: jest.fn(), + optionallyDecryptAndRedactSingleResult: jest.fn(), + optionallyDecryptAndRedactBulkResult: jest.fn(), + }; + + return mock; +}; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/index.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/index.ts index 22569e9437895..852e7a2f9dd52 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/index.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/index.ts @@ -19,3 +19,5 @@ export { type PreflightCheckHelperMock, } from './api_helpers.mocks'; export { apiContextMock, type ApiExecutionContextMock } from './api_context.mock'; +export { createDocumentMigratorMock, createMigratorMock } from './migrator.mock'; +export { createEncryptionHelperMock } from './helpers'; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/kibana_migrator.mock.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/kibana_migrator.mock.ts index e2c7107ca380c..a896f0934901d 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/kibana_migrator.mock.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/kibana_migrator.mock.ts @@ -8,6 +8,7 @@ import type { SavedObjectsType } from '@kbn/core-saved-objects-server'; import type { IKibanaMigrator } from '@kbn/core-saved-objects-base-server-internal'; +import { createDocumentMigratorMock } from './migrator.mock'; // mock duplicated from `@kbn/core/saved-objects-migration-server-mocks` to avoid cyclic dependencies @@ -39,6 +40,7 @@ const createMigratorMock = ( migrateDocument: jest.fn(), prepareMigrations: jest.fn(), getStatus$: jest.fn(), + getDocumentMigrator: jest.fn().mockReturnValue(createDocumentMigratorMock()), }; // mockMigrator.getActiveMappings.mockReturnValue(buildActiveMappings(mergeTypes(types))); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/migrator.mock.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/migrator.mock.ts index 94f221e7cfbc8..898259312628a 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/migrator.mock.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/migrator.mock.ts @@ -6,7 +6,10 @@ * Side Public License, v 1. */ -import type { IKibanaMigrator } from '@kbn/core-saved-objects-base-server-internal'; +import type { + IKibanaMigrator, + IDocumentMigrator, +} from '@kbn/core-saved-objects-base-server-internal'; export type KibanaMigratorMock = jest.Mocked; @@ -18,5 +21,16 @@ export const createMigratorMock = (kibanaVersion: string = '8.0.0'): KibanaMigra getStatus$: jest.fn(), getActiveMappings: jest.fn(), migrateDocument: jest.fn(), + getDocumentMigrator: jest.fn().mockReturnValue(createDocumentMigratorMock()), + }; +}; + +export type DocumentMigratorMock = jest.Mocked; + +export const createDocumentMigratorMock = (): DocumentMigratorMock => { + return { + migrate: jest.fn().mockImplementation((doc: unknown) => doc), + migrateAndConvert: jest.fn().mockImplementation((doc: unknown) => doc), + isDowngradeRequired: jest.fn().mockReturnValue(false), }; }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/saved_objects_extensions.mock.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/saved_objects_extensions.mock.ts index 6f7fb8299291e..3d9c3f91efa09 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/saved_objects_extensions.mock.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/saved_objects_extensions.mock.ts @@ -10,7 +10,6 @@ import type { ISavedObjectsEncryptionExtension, ISavedObjectsSecurityExtension, ISavedObjectsSpacesExtension, - SavedObjectsExtensions, } from '@kbn/core-saved-objects-server'; const createEncryptionExtension = (): jest.Mocked => ({ @@ -47,7 +46,7 @@ const createSpacesExtension = (): jest.Mocked => ( getSearchableNamespaces: jest.fn(), }); -const create = (): jest.Mocked => ({ +const create = () => ({ encryptionExtension: createEncryptionExtension(), securityExtension: createSecurityExtension(), spacesExtension: createSpacesExtension(), diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts index 2a3535f19207c..6eef9105198bf 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/index.ts @@ -41,6 +41,9 @@ export type { MigrationResult, MigrationStatus, MigrateDocumentOptions, + IDocumentMigrator, + DocumentMigrateOptions, + IsDowngradeRequiredOptions, } from './src/migration'; export { parseObjectKey, diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/document_migrator.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/document_migrator.ts new file mode 100644 index 0000000000000..bdbd78e717520 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/document_migrator.ts @@ -0,0 +1,67 @@ +/* + * 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 { SavedObjectUnsanitizedDoc } from '@kbn/core-saved-objects-server'; + +/** + * Manages transformations of individual documents. + */ +export interface IDocumentMigrator { + /** + * Migrates a document to its latest version. + */ + migrate( + doc: SavedObjectUnsanitizedDoc, + options?: DocumentMigrateOptions + ): SavedObjectUnsanitizedDoc; + + /** + * Migrates a document to the latest version and applies type conversions if applicable. + * Also returns any additional document(s) that may have been created during the transformation process. + * + * @remark This only be used by the savedObject migration during upgrade. For all other scenarios, + * {@link IDocumentMigrator#migrate} should be used instead. + */ + migrateAndConvert(doc: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc[]; + + /** + * Returns true if the provided document has a higher version that the `targetTypeVersion` + * (defaulting to the last known version), false otherwise. + */ + isDowngradeRequired( + doc: SavedObjectUnsanitizedDoc, + options?: IsDowngradeRequiredOptions + ): boolean; +} + +/** + * Options for {@link IDocumentMigrator.migrate} + */ +export interface DocumentMigrateOptions { + /** + * Defines whether it is allowed to convert documents from an higher version or not. + * - If `true`, documents from higher versions will go though the downgrade pipeline. + * - If `false`, an error will be thrown when trying to process a document with an higher type version. + * Defaults to `false`. + */ + allowDowngrade?: boolean; + /** + * If specified, will migrate to the given version instead of the latest known version. + */ + targetTypeVersion?: string; +} + +/** + * Options for {@link IDocumentMigrator.isDowngradeRequired} + */ +export interface IsDowngradeRequiredOptions { + /** + * If specified, will migrate to the given version instead of the latest known version. + */ + targetTypeVersion?: string; +} diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/index.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/index.ts index aa54e37f0d91a..0c4c87a3d3fbb 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/index.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/index.ts @@ -13,3 +13,8 @@ export type { MigrationResult, MigrateDocumentOptions, } from './kibana_migrator'; +export type { + IDocumentMigrator, + DocumentMigrateOptions, + IsDowngradeRequiredOptions, +} from './document_migrator'; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/kibana_migrator.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/kibana_migrator.ts index 18a03a7fcbf54..723d5724024fc 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/kibana_migrator.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/migration/kibana_migrator.ts @@ -9,6 +9,7 @@ import { Observable } from 'rxjs'; import type { SavedObjectUnsanitizedDoc } from '@kbn/core-saved-objects-server'; import type { IndexMapping } from '../mappings'; +import type { IDocumentMigrator } from './document_migrator'; /** @internal */ export interface IKibanaMigrator { @@ -53,6 +54,11 @@ export interface IKibanaMigrator { doc: SavedObjectUnsanitizedDoc, options?: MigrateDocumentOptions ): SavedObjectUnsanitizedDoc; + + /** + * Returns the document migrator bound to this kibana migrator. + */ + getDocumentMigrator(): IDocumentMigrator; } /** diff --git a/packages/core/saved-objects/core-saved-objects-base-server-mocks/index.ts b/packages/core/saved-objects/core-saved-objects-base-server-mocks/index.ts index 9700eb0f0f3cb..51ad9cfa5e4d5 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-mocks/index.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-mocks/index.ts @@ -8,3 +8,4 @@ export { typeRegistryMock } from './src/saved_objects_type_registry.mock'; export { serializerMock } from './src/serializer.mock'; +export { createDocumentMigratorMock } from './src/document_migrator.mock'; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-mocks/src/document_migrator.mock.ts b/packages/core/saved-objects/core-saved-objects-base-server-mocks/src/document_migrator.mock.ts new file mode 100644 index 0000000000000..e293fb30b2284 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-base-server-mocks/src/document_migrator.mock.ts @@ -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 type { IDocumentMigrator } from '@kbn/core-saved-objects-base-server-internal'; + +export const createDocumentMigratorMock = (): jest.Mocked => { + return { + migrate: jest.fn().mockImplementation((doc: unknown) => doc), + migrateAndConvert: jest.fn().mockImplementation((doc: unknown) => doc), + isDowngradeRequired: jest.fn().mockReturnValue(false), + }; +}; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/migrate_raw_docs.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/migrate_raw_docs.ts index 26e843ad99412..0b30ea2b0fe2d 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/migrate_raw_docs.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/migrate_raw_docs.ts @@ -17,10 +17,10 @@ import type { SavedObjectUnsanitizedDoc, ISavedObjectsSerializer, } from '@kbn/core-saved-objects-server'; -import type { VersionedTransformer } from '../document_migrator'; +import type { IDocumentMigrator } from '@kbn/core-saved-objects-base-server-internal'; import { TransformSavedObjectDocumentError } from '.'; -type MigrateAndConvertFn = VersionedTransformer['migrateAndConvert']; +type MigrateAndConvertFn = IDocumentMigrator['migrateAndConvert']; export interface DocumentsTransformFailed { readonly type: string; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/document_migrator.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/document_migrator.ts index 540f8e39b4671..d2dff051a5f53 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/document_migrator.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/document_migrator.ts @@ -13,6 +13,11 @@ import type { SavedObjectUnsanitizedDoc, ISavedObjectTypeRegistry, } from '@kbn/core-saved-objects-server'; +import type { + IDocumentMigrator, + DocumentMigrateOptions, + IsDowngradeRequiredOptions, +} from '@kbn/core-saved-objects-base-server-internal'; import type { ActiveMigrations } from './types'; import { maxVersion } from './pipelines/utils'; import { buildActiveMigrations } from './build_active_migrations'; @@ -20,23 +25,6 @@ import { DocumentUpgradePipeline, DocumentDowngradePipeline } from './pipelines' import { downgradeRequired } from './utils'; import { TransformType } from './types'; -/** - * Options for {@link VersionedTransformer.migrate} - */ -export interface DocumentMigrateOptions { - /** - * Defines whether it is allowed to convert documents from an higher version or not. - * - If `true`, documents from higher versions will go though the downgrade pipeline. - * - If `false`, an error will be thrown when trying to process a document with an higher type version. - * Defaults to `false`. - */ - allowDowngrade?: boolean; - /** - * If specified, will migrate to the given version instead of the latest known version. - */ - targetTypeVersion?: string; -} - interface TransformOptions { convertNamespaceTypes?: boolean; allowDowngrade?: boolean; @@ -65,31 +53,9 @@ interface MigrationVersionParams { } /** - * Manages transformations of individual documents. + * A concrete implementation of the {@link IDocumentMigrator} interface. */ -export interface VersionedTransformer { - /** - * Migrates a document to its latest version. - */ - migrate( - doc: SavedObjectUnsanitizedDoc, - options?: DocumentMigrateOptions - ): SavedObjectUnsanitizedDoc; - - /** - * Migrates a document to the latest version and applies type conversions if applicable. - * Also returns any additional document(s) that may have been created during the transformation process. - * - * @remark This only be used by the savedObject migration during upgrade. For all other scenarios, - * {@link VersionedTransformer#migrate} should be used instead. - */ - migrateAndConvert(doc: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc[]; -} - -/** - * A concrete implementation of the {@link VersionedTransformer} interface. - */ -export class DocumentMigrator implements VersionedTransformer { +export class DocumentMigrator implements IDocumentMigrator { private options: DocumentMigratorOptions; private migrations?: ActiveMigrations; @@ -175,6 +141,21 @@ export class DocumentMigrator implements VersionedTransformer { return [document, ...additionalDocs]; } + /** + * Returns true if the provided document has a higher version that the `targetTypeVersion` + * (defaulting to the last known version), false otherwise. + */ + public isDowngradeRequired( + doc: SavedObjectUnsanitizedDoc, + { targetTypeVersion }: IsDowngradeRequiredOptions = {} + ): boolean { + if (!this.migrations) { + throw new Error('Migrations are not ready. Make sure prepareMigrations is called first.'); + } + const typeMigrations = this.migrations[doc.type]; + return downgradeRequired(doc, typeMigrations?.latestVersion ?? {}, targetTypeVersion); + } + private transform( doc: SavedObjectUnsanitizedDoc, { diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/index.ts index f34053388d764..daaffc617f611 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/document_migrator/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { DocumentMigrator, type VersionedTransformer } from './document_migrator'; +export { DocumentMigrator } from './document_migrator'; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.ts index c06461da8fb43..a07d810ee75ab 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.ts @@ -119,6 +119,10 @@ export class KibanaMigrator implements IKibanaMigrator { this.esCapabilities = esCapabilities; } + public getDocumentMigrator() { + return this.documentMigrator; + } + public runMigrations({ rerun = false }: { rerun?: boolean } = {}): Promise { if (this.migrationResult === undefined || rerun) { // Reruns are only used by CI / EsArchiver. Publishing status updates on reruns results in slowing down CI diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/context/types.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/context/types.ts index 3515d8a01a5a0..060bd0ebdde51 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/context/types.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/context/types.ts @@ -18,9 +18,9 @@ import type { import type { VirtualVersionMap, SavedObjectsMigrationConfigType, + IDocumentMigrator, } from '@kbn/core-saved-objects-base-server-internal'; import type { DocLinks } from '@kbn/doc-links'; -import { VersionedTransformer } from '../../document_migrator'; /** * The set of static, precomputed values and services used by the ZDT migration @@ -45,7 +45,7 @@ export interface MigratorContext { /** SO serializer to use for migration */ readonly serializer: ISavedObjectsSerializer; /** The doc migrator to use */ - readonly documentMigrator: VersionedTransformer; + readonly documentMigrator: IDocumentMigrator; /** The SO type registry to use for the migration */ readonly typeRegistry: ISavedObjectTypeRegistry; /** List of types that are no longer registered */ diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/migrate_index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/migrate_index.ts index 1ee07de5e0395..d2d9c699566d3 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/migrate_index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/migrate_index.ts @@ -10,9 +10,10 @@ import type { ElasticsearchClient, ElasticsearchCapabilities, } from '@kbn/core-elasticsearch-server'; -import { - type SavedObjectsMigrationConfigType, - type MigrationResult, +import type { + SavedObjectsMigrationConfigType, + MigrationResult, + IDocumentMigrator, } from '@kbn/core-saved-objects-base-server-internal'; import type { ISavedObjectTypeRegistry, @@ -22,7 +23,6 @@ import type { Logger } from '@kbn/logging'; import type { DocLinksServiceStart } from '@kbn/core-doc-links-server'; import { NodeRoles } from '@kbn/core-node-server'; import { migrationStateActionMachine } from './migration_state_action_machine'; -import type { VersionedTransformer } from '../document_migrator'; import { createContext } from './context'; import { next } from './next'; import { model } from './model'; @@ -37,7 +37,7 @@ export interface MigrateIndexOptions { /** Logger to use for migration output */ logger: Logger; /** The document migrator to use to convert the document */ - documentMigrator: VersionedTransformer; + documentMigrator: IDocumentMigrator; /** The migration config to use for the migration */ migrationConfig: SavedObjectsMigrationConfigType; /** docLinks contract to use to link to documentation */ diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/run_zdt_migration.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/run_zdt_migration.ts index e8309f8d4d539..cb9d1656707c7 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/run_zdt_migration.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/run_zdt_migration.ts @@ -17,11 +17,11 @@ import type { ISavedObjectTypeRegistry, ISavedObjectsSerializer, } from '@kbn/core-saved-objects-server'; -import { - type SavedObjectsMigrationConfigType, - type MigrationResult, +import type { + SavedObjectsMigrationConfigType, + MigrationResult, + IDocumentMigrator, } from '@kbn/core-saved-objects-base-server-internal'; -import type { VersionedTransformer } from '../document_migrator'; import { buildMigratorConfigs } from './utils'; import { migrateIndex } from './migrate_index'; @@ -35,7 +35,7 @@ export interface RunZeroDowntimeMigrationOpts { /** Logger to use for migration output */ logger: Logger; /** The document migrator to use to convert the document */ - documentMigrator: VersionedTransformer; + documentMigrator: IDocumentMigrator; /** The migration config to use for the migration */ migrationConfig: SavedObjectsMigrationConfigType; /** docLinks contract to use to link to documentation */ diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/document_migrator.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/document_migrator.ts index 3dbe48ab2d4e9..dba89f2aacb1b 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/document_migrator.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/document_migrator.ts @@ -6,11 +6,12 @@ * Side Public License, v 1. */ -import type { VersionedTransformer } from '../../document_migrator'; +import type { IDocumentMigrator } from '@kbn/core-saved-objects-base-server-internal'; -export const createDocumentMigrator = (): jest.Mocked => { +export const createDocumentMigrator = (): jest.Mocked => { return { migrate: jest.fn().mockImplementation((doc: unknown) => doc), migrateAndConvert: jest.fn().mockImplementation((doc: unknown) => [doc]), + isDowngradeRequired: jest.fn().mockReturnValue(false), }; }; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/transform_raw_docs.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/transform_raw_docs.ts index 1af1cee9d3b84..11df2574f1e94 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/transform_raw_docs.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/transform_raw_docs.ts @@ -7,13 +7,13 @@ */ import type { ISavedObjectsSerializer, SavedObjectsRawDoc } from '@kbn/core-saved-objects-server'; -import { VersionedTransformer } from '../../document_migrator'; +import type { IDocumentMigrator } from '@kbn/core-saved-objects-base-server-internal'; import { TransformRawDocs } from '../../types'; import { migrateRawDocsSafely } from '../../core/migrate_raw_docs'; export interface CreateDocumentTransformFnOpts { serializer: ISavedObjectsSerializer; - documentMigrator: VersionedTransformer; + documentMigrator: IDocumentMigrator; } export const createDocumentTransformFn = ({ diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-mocks/src/kibana_migrator.mock.ts b/packages/core/saved-objects/core-saved-objects-migration-server-mocks/src/kibana_migrator.mock.ts index a0d7ac83fe74a..7801f71503931 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-mocks/src/kibana_migrator.mock.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-mocks/src/kibana_migrator.mock.ts @@ -16,6 +16,7 @@ import { buildActiveMappings, buildTypesMappings, } from '@kbn/core-saved-objects-migration-server-internal'; +import { createDocumentMigratorMock } from '@kbn/core-saved-objects-base-server-mocks'; const defaultSavedObjectTypes: SavedObjectsType[] = [ { @@ -58,10 +59,13 @@ const createMigrator = ( ], }) ), + getDocumentMigrator: jest.fn(), }; mockMigrator.getActiveMappings.mockReturnValue(buildActiveMappings(buildTypesMappings(types))); mockMigrator.migrateDocument.mockImplementation((doc) => doc); + mockMigrator.getDocumentMigrator.mockReturnValue(createDocumentMigratorMock()); + return mockMigrator; }; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-mocks/tsconfig.json b/packages/core/saved-objects/core-saved-objects-migration-server-mocks/tsconfig.json index b228481a3207a..8d075d0a9e0b3 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-mocks/tsconfig.json +++ b/packages/core/saved-objects/core-saved-objects-migration-server-mocks/tsconfig.json @@ -13,7 +13,8 @@ "kbn_references": [ "@kbn/core-saved-objects-server", "@kbn/core-saved-objects-base-server-internal", - "@kbn/core-saved-objects-migration-server-internal" + "@kbn/core-saved-objects-migration-server-internal", + "@kbn/core-saved-objects-base-server-mocks" ], "exclude": [ "target/**/*", diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/container.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/container.ts index 2df8aa2d71ea3..2f1cb1b7c27e9 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/container.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/container.ts @@ -15,6 +15,7 @@ interface ContainerDocument extends Fields { 'container.id': string; 'kubernetes.pod.uid': string; 'kubernetes.node.name': string; + 'metricset.name'?: string; } export class Container extends Entity { diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts index 8da22d5b140d7..db2fb3dd3d735 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts @@ -13,14 +13,79 @@ import { Serializable } from '../serializable'; import { pod } from './pod'; interface HostDocument extends Fields { + 'agent.id': string; 'host.hostname': string; + 'host.name': string; + 'metricset.name'?: string; } class Host extends Entity { - metrics() { + cpu() { return new HostMetrics({ ...this.fields, - 'system.cpu.total.norm.pct': 46, + 'system.cpu.total.norm.pct': 0.094, + 'system.cpu.user.pct': 0.805, + 'system.cpu.system.pct': 0.704, + 'system.cpu.cores': 16, + 'metricset.period': 10000, + 'metricset.name': 'cpu', + }); + } + + memory() { + return new HostMetrics({ + ...this.fields, + 'system.memory.actual.free': 44704067584, + 'system.memory.actual.used.bytes': 24015409152, + 'system.memory.actual.used.pct': 0.35, + 'system.memory.total': 68719476736, + 'system.memory.used.bytes': 39964708864, + 'system.memory.used.pct': 0.582, + 'metricset.period': 10000, + 'metricset.name': 'memory', + }); + } + + network() { + return new HostMetrics({ + ...this.fields, + 'host.network.ingress.bytes': 2871285, + 'host.network.egress.bytes': 2904987, + 'metricset.period': 10000, + 'metricset.name': 'network', + }); + } + + load() { + return new HostMetrics({ + ...this.fields, + 'system.load': { + 1: 3, + cores: 16, + }, + 'metricset.period': 10000, + 'metricset.name': 'load', + }); + } + + filesystem() { + return new HostMetrics({ + ...this.fields, + 'system.filesystem.used.pct': 12.23, + 'metricset.period': 10000, + 'metricset.name': 'filesystem', + }); + } + + diskio() { + return new HostMetrics({ + ...this.fields, + 'system.diskio.read.count': 3538413, + 'system.diskio.write.count': 4694333, + 'system.diskio.read.bytes': 33147297792, + 'system.diskio.write.bytes': 48595652608, + 'metricset.period': 10000, + 'metricset.name': 'diskio', }); } @@ -39,13 +104,35 @@ class Host extends Entity { } export interface HostMetricsDocument extends HostDocument { - 'system.cpu.total.norm.pct': number; + 'agent.id': string; + 'metricset.period'?: number; + 'metricset.name'?: string; + 'system.cpu.total.norm.pct'?: number; + 'system.cpu.user.pct'?: number; + 'system.cpu.system.pct'?: number; + 'system.cpu.cores'?: number; + 'system.diskio.read.count'?: number; + 'system.diskio.write.count'?: number; + 'system.diskio.read.bytes'?: number; + 'system.diskio.write.bytes'?: number; + 'system.filesystem.used.pct'?: number; + 'system.memory.actual.used.pct'?: number; + 'system.memory.total'?: number; + 'system.memory.actual.used.bytes'?: number; + 'system.memory.actual.free'?: number; + 'system.memory.used.bytes'?: number; + 'system.memory.used.pct'?: number; + 'system.load'?: { 1: number; cores: number }; + 'host.network.ingress.bytes'?: number; + 'host.network.egress.bytes'?: number; } class HostMetrics extends Serializable {} export function host(name: string): Host { return new Host({ + 'agent.id': 'synthtrace', 'host.hostname': name, + 'host.name': name, }); } diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts index 4876fd7291f53..618db5a69b77a 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts @@ -15,6 +15,7 @@ import { container } from './container'; interface PodDocument extends Fields { 'kubernetes.pod.uid': string; 'kubernetes.node.name': string; + 'metricset.name'?: string; } export class Pod extends Entity { diff --git a/packages/kbn-apm-synthtrace/index.ts b/packages/kbn-apm-synthtrace/index.ts index 880b97cac2a8f..378d7f610539d 100644 --- a/packages/kbn-apm-synthtrace/index.ts +++ b/packages/kbn-apm-synthtrace/index.ts @@ -12,6 +12,7 @@ export { ApmSynthtraceEsClient } from './src/lib/apm/client/apm_synthtrace_es_cl export { ApmSynthtraceKibanaClient } from './src/lib/apm/client/apm_synthtrace_kibana_client'; export { InfraSynthtraceEsClient } from './src/lib/infra/infra_synthtrace_es_client'; +export { InfraSynthtraceKibanaClient } from './src/lib/infra/infra_synthtrace_kibana_client'; export { AssetsSynthtraceEsClient } from './src/lib/assets/assets_synthtrace_es_client'; 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 3304fc7bd3c9c..13b4ee07aad24 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 @@ -9,6 +9,7 @@ import fetch from 'node-fetch'; import pRetry from 'p-retry'; import { Logger } from '../../utils/create_logger'; +import { kibanaHeaders } from '../../shared/client_headers'; export class ApmSynthtraceKibanaClient { private readonly logger: Logger; @@ -44,13 +45,31 @@ export class ApmSynthtraceKibanaClient { this.logger.debug(`Installing APM package ${packageVersion}`); const url = `${this.target}/api/fleet/epm/packages/apm/${packageVersion}`; - const response = await pRetry(() => { - return fetch(url, { - method: 'POST', - headers: kibanaHeaders(), - body: '{"force":true}', - }); - }); + const response = await pRetry( + async () => { + const res = await fetch(url, { + method: 'POST', + headers: kibanaHeaders(), + body: '{"force":true}', + }); + + if (res.status >= 400) { + const errorJson = await res.json(); + throw new Error( + `APM package installation returned ${res.status} status code\nError: ${errorJson}` + ); + } + return res; + }, + { + retries: 5, + onFailedAttempt: (error) => { + this.logger.debug( + `APM package installation failure. ${error.retriesLeft >= 1 ? 'Retrying' : 'Aborting'}` + ); + }, + } + ); const responseJson = await response.json(); @@ -63,12 +82,3 @@ export class ApmSynthtraceKibanaClient { this.logger.info(`Installed APM package ${packageVersion}`); } } - -function kibanaHeaders() { - return { - Accept: 'application/json', - 'Content-Type': 'application/json', - 'kbn-xsrf': 'kibana', - 'elastic-api-version': '2023-10-31', - }; -} diff --git a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts index 897d813ae6718..031c40c9ccf19 100644 --- a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts +++ b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts @@ -46,8 +46,20 @@ function getRoutingTransform() { return new Transform({ objectMode: true, transform(document: ESDocumentWithOperation, encoding, callback) { - if ('host.hostname' in document) { + const metricset = document['metricset.name']; + + if (metricset === 'cpu') { document._index = 'metrics-system.cpu-default'; + } else if (metricset === 'memory') { + document._index = 'metrics-system.memory-default'; + } else if (metricset === 'network') { + document._index = 'metrics-system.network-default'; + } else if (metricset === 'load') { + document._index = 'metrics-system.load-default'; + } else if (metricset === 'filesystem') { + document._index = 'metrics-system.filesystem-default'; + } else if (metricset === 'diskio') { + document._index = 'metrics-system.diskio-default'; } else if ('container.id' in document) { document._index = 'metrics-kubernetes.container-default'; } else if ('kubernetes.pod.uid' in document) { diff --git a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts new file mode 100644 index 0000000000000..c1ac555276a66 --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { join } from 'path'; +import fetch from 'node-fetch'; +import pRetry from 'p-retry'; +import { Logger } from '../utils/create_logger'; +import { kibanaHeaders } from '../shared/client_headers'; + +export class InfraSynthtraceKibanaClient { + private readonly logger: Logger; + private target: string; + + constructor(options: { logger: Logger; target: string; username: string; password: string }) { + this.logger = options.logger; + const url = new URL(options.target); + url.username = options.username; + url.password = options.password; + this.target = url.toString(); + } + + async fetchLatestSystemPackageVersion() { + const fleetPackageApiUrl = join(this.target, '/api/fleet/epm/packages/system?prerelease=true'); + this.logger.debug(`Fetching latest System package version from ${fleetPackageApiUrl}`); + const response = await fetch(fleetPackageApiUrl, { + method: 'GET', + headers: kibanaHeaders(), + }); + + const responseJson = await response.json(); + + if (response.status !== 200) { + throw new Error( + `Failed to fetch latest System package version, received HTTP ${response.status} and message: ${responseJson.message}` + ); + } + + const { latestVersion } = responseJson.item; + + return latestVersion as string; + } + + async installSystemPackage(packageVersion: string) { + this.logger.debug(`Installing System package ${packageVersion}`); + + const url = join(this.target, `/api/fleet/epm/packages/system/${packageVersion}`); + const response = await pRetry(() => { + return fetch(url, { + method: 'POST', + headers: kibanaHeaders(), + body: '{"force":true}', + }); + }); + + const responseJson = await response.json(); + + if (!responseJson.items) { + throw new Error( + `Failed to install System package version ${packageVersion}, received HTTP ${response.status} and message: ${responseJson.message} for url ${url}` + ); + } + + this.logger.info(`Installed System package ${packageVersion}`); + } +} diff --git a/packages/kbn-apm-synthtrace/src/lib/shared/client_headers.ts b/packages/kbn-apm-synthtrace/src/lib/shared/client_headers.ts new file mode 100644 index 0000000000000..c6a5a80d6ad7f --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/lib/shared/client_headers.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export function kibanaHeaders() { + return { + Accept: 'application/json', + 'Content-Type': 'application/json', + 'kbn-xsrf': 'kibana', + 'elastic-api-version': '2023-10-31', + }; +} diff --git a/packages/kbn-apm-synthtrace/src/scenarios/service_summary_field_version_dependent.ts b/packages/kbn-apm-synthtrace/src/scenarios/service_summary_field_version_dependent.ts new file mode 100644 index 0000000000000..37999bff114c2 --- /dev/null +++ b/packages/kbn-apm-synthtrace/src/scenarios/service_summary_field_version_dependent.ts @@ -0,0 +1,71 @@ +/* + * 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 { ApmFields, apm } from '@kbn/apm-synthtrace-client'; +import { random } from 'lodash'; +import { pipeline, Readable } from 'stream'; +import semver from 'semver'; +import { Scenario } from '../cli/scenario'; +import { + addObserverVersionTransform, + deleteSummaryFieldTransform, +} from '../lib/utils/transform_helpers'; +import { withClient } from '../lib/utils/with_client'; + +const scenario: Scenario = async ({ logger, versionOverride }) => { + const version = versionOverride as string; + const isLegacy = versionOverride && semver.lt(version, '8.7.0'); + return { + bootstrap: async ({ apmEsClient }) => { + if (isLegacy) { + apmEsClient.pipeline((base: Readable) => { + const defaultPipeline = apmEsClient.getDefaultPipeline()( + base + ) as unknown as NodeJS.ReadableStream; + + return pipeline( + defaultPipeline, + addObserverVersionTransform(version), + deleteSummaryFieldTransform(), + (err) => { + if (err) { + logger.error(err); + } + } + ); + }); + } + }, + generate: ({ range, clients: { apmEsClient } }) => { + const successfulTimestamps = range.ratePerMinute(6); + const instance = apm + .service({ + name: `java${isLegacy ? '-legacy' : ''}`, + environment: 'production', + agentName: 'java', + }) + .instance(`instance`); + + return withClient( + apmEsClient, + successfulTimestamps.generator((timestamp) => { + const randomHigh = random(1000, 4000); + const randomLow = random(100, randomHigh / 5); + const duration = random(randomLow, randomHigh); + return instance + .transaction({ transactionName: 'GET /order/{id}' }) + .timestamp(timestamp) + .duration(duration) + .success(); + }) + ); + }, + }; +}; + +export default scenario; diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index ff7dde5649b25..a18c9337d79d5 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -52,7 +52,7 @@ pageLoadAssetSize: expressionLegacyMetricVis: 23121 expressionMetric: 22238 expressionMetricVis: 23121 - expressionPartitionVis: 28000 + expressionPartitionVis: 29000 expressionRepeatImage: 22341 expressionRevealImage: 25675 expressions: 140958 diff --git a/src/dev/performance/run_performance_cli.ts b/src/dev/performance/run_performance_cli.ts index 3c5807e1c208b..687a6460d5a3d 100644 --- a/src/dev/performance/run_performance_cli.ts +++ b/src/dev/performance/run_performance_cli.ts @@ -11,7 +11,6 @@ import { run } from '@kbn/dev-cli-runner'; import { REPO_ROOT } from '@kbn/repo-info'; import fs from 'fs'; import path from 'path'; -import { JOURNEY_APM_CONFIG } from '@kbn/journeys'; const JOURNEY_BASE_PATH = 'x-pack/performance/journeys'; @@ -108,20 +107,21 @@ run( 'scripts/es', 'snapshot', '--license=trial', - ...(JOURNEY_APM_CONFIG.active - ? [ - '-E', - 'tracing.apm.enabled=true', - '-E', - 'tracing.apm.agent.transaction_sample_rate=1.0', - '-E', - `tracing.apm.agent.server_url=${JOURNEY_APM_CONFIG.serverUrl}`, - '-E', - `tracing.apm.agent.secret_token=${JOURNEY_APM_CONFIG.secretToken}`, - '-E', - `tracing.apm.agent.environment=${JOURNEY_APM_CONFIG.environment}`, - ] - : []), + // Temporarily disabling APM + // ...(JOURNEY_APM_CONFIG.active + // ? [ + // '-E', + // 'tracing.apm.enabled=true', + // '-E', + // 'tracing.apm.agent.transaction_sample_rate=1.0', + // '-E', + // `tracing.apm.agent.server_url=${JOURNEY_APM_CONFIG.serverUrl}`, + // '-E', + // `tracing.apm.agent.secret_token=${JOURNEY_APM_CONFIG.secretToken}`, + // '-E', + // `tracing.apm.agent.environment=${JOURNEY_APM_CONFIG.environment}`, + // ] + // : []), ], cwd: REPO_ROOT, wait: /kbn\/es setup complete/, diff --git a/src/dev/tsconfig.json b/src/dev/tsconfig.json index 806af4b68384f..a3ebcf6dda1ba 100644 --- a/src/dev/tsconfig.json +++ b/src/dev/tsconfig.json @@ -39,7 +39,6 @@ "@kbn/get-repo-files", "@kbn/import-locator", "@kbn/config-schema", - "@kbn/journeys", "@kbn/core-test-helpers-so-type-serializer", "@kbn/core-test-helpers-kbn-server", ] diff --git a/src/plugins/chart_expressions/common/chart_size_transition_veil.tsx b/src/plugins/chart_expressions/common/chart_size_transition_veil.tsx new file mode 100644 index 0000000000000..8a0c11f363f9c --- /dev/null +++ b/src/plugins/chart_expressions/common/chart_size_transition_veil.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 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, { useEffect } from 'react'; +import { useCallback, useRef, useState } from 'react'; +import fastIsEqual from 'fast-deep-equal'; +import { useResizeObserver } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; +import type { ChartSizeSpec } from './types'; + +/** + * This hook is used to show a veil over the chart while it is being resized + * in response to a change in the container dimensions. + * + * It is only relevant if client dimensions are being requested based on chart configuration. + * + * This whole feature is a nice-to-have. If it proves to be a source of bugs, + * we can consider removing it and accepting the aesthetic drawback. + */ +export function useSizeTransitionVeil( + chartSizeSpec: ChartSizeSpec, + setChartSize: (d: ChartSizeSpec) => void, + // should be retrieved from handlers.shouldUseSizeTransitionVeil function + shouldUseVeil: boolean +) { + const containerRef = useRef(null); + const containerSize = useResizeObserver(containerRef.current); + const currentContainerSize = useRef<{ width: number; height: number }>(containerSize); + + // This useEffect hook is here to make up for the fact that the initial container size + // is not correctly reported by the useResizeObserver hook (see https://github.com/elastic/eui/issues/7458). + useEffect(() => { + currentContainerSize.current = { + width: containerRef.current?.clientWidth ?? 0, + height: containerRef.current?.clientHeight ?? 0, + }; + }, []); + + const [showVeil, setShowVeil] = useState(false); + const currentChartSizeSpec = useRef(); + const specJustChanged = useRef(false); + + useEffect(() => { + if (!fastIsEqual(containerSize, currentContainerSize.current) && specJustChanged.current) { + // If the container size has changed, we need to show the veil to hide the chart since it + // be rendered based on the previous container size before being updated to the current size. + // + // 1. we show the veil + // 2. the charts library will render the chart based on the previous container dimensions + // 3. the charts library will resize the chart to the updated container dimensions + // 4. we hide the veil + setShowVeil(true); + currentContainerSize.current = containerSize; + } + }, [setShowVeil, containerSize]); + + useEffect(() => { + if (!fastIsEqual(chartSizeSpec, currentChartSizeSpec.current)) { + setChartSize(chartSizeSpec); + currentChartSizeSpec.current = chartSizeSpec; + specJustChanged.current = true; + + setTimeout(() => { + specJustChanged.current = false; + }, 500); + } + }, [chartSizeSpec, setChartSize]); + + const onResize = useCallback(() => { + setShowVeil(false); + }, []); + + return { + veil: ( +
+ ), + onResize, + containerRef, + }; +} diff --git a/src/plugins/chart_expressions/common/index.ts b/src/plugins/chart_expressions/common/index.ts index acc3b4d8c88cd..93b5d83710bb2 100644 --- a/src/plugins/chart_expressions/common/index.ts +++ b/src/plugins/chart_expressions/common/index.ts @@ -12,5 +12,7 @@ export { getOverridesFor, isOnAggBasedEditor, } from './utils'; -export type { Simplify, MakeOverridesSerializable } from './types'; +export type { Simplify, MakeOverridesSerializable, ChartSizeSpec, ChartSizeEvent } from './types'; +export { isChartSizeEvent } from './types'; export { getColorCategories } from './color_categories'; +export { useSizeTransitionVeil } from './chart_size_transition_veil'; diff --git a/src/plugins/chart_expressions/common/tsconfig.json b/src/plugins/chart_expressions/common/tsconfig.json index 7ac76523fcb6c..37a3b2f5bf607 100644 --- a/src/plugins/chart_expressions/common/tsconfig.json +++ b/src/plugins/chart_expressions/common/tsconfig.json @@ -4,11 +4,13 @@ "outDir": "target/types", "types": [ "jest", - "node" + "node", + "@emotion/react/types/css-prop", ] }, "include": [ "**/*.ts", + "**/*.tsx", ], "exclude": [ "target/**/*" @@ -17,5 +19,6 @@ "@kbn/core-execution-context-common", "@kbn/expressions-plugin", "@kbn/data-plugin", + "@kbn/ui-theme", ] } diff --git a/src/plugins/chart_expressions/common/types.ts b/src/plugins/chart_expressions/common/types.ts index acdd5909f1aec..6413a8f644efc 100644 --- a/src/plugins/chart_expressions/common/types.ts +++ b/src/plugins/chart_expressions/common/types.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import type { ExpressionRendererEvent } from '@kbn/expressions-plugin/public'; import React from 'react'; export type Simplify = { [KeyType in keyof T]: T[KeyType] } & {}; @@ -26,3 +27,27 @@ export type MakeOverridesSerializable = { ? MakeOverridesSerializable : NonNullable; }; + +export interface ChartSizeEvent extends ExpressionRendererEvent { + name: 'chartSize'; + data: ChartSizeSpec; +} + +export type ChartSizeUnit = 'pixels' | 'percentage'; + +interface ChartSizeDimensions { + x?: { value: number; unit: ChartSizeUnit }; + y?: { value: number; unit: ChartSizeUnit }; +} + +export interface ChartSizeSpec { + // if maxDimensions are provided, the aspect ratio will be computed from them + maxDimensions?: ChartSizeDimensions; + minDimensions?: ChartSizeDimensions; + aspectRatio?: { x: number; y: number }; +} + +export function isChartSizeEvent(event: ExpressionRendererEvent): event is ChartSizeEvent { + const expectedName: ChartSizeEvent['name'] = 'chartSize'; + return event.name === expectedName; +} diff --git a/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts b/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts index 1cdb5b464f3f5..5bda3a872da00 100644 --- a/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts +++ b/src/plugins/chart_expressions/expression_gauge/common/types/expression_renderers.ts @@ -11,6 +11,7 @@ import type { PersistedState } from '@kbn/visualizations-plugin/public'; import type { ChartsPluginSetup } from '@kbn/charts-plugin/public'; import type { IFieldFormat, SerializedFieldFormat } from '@kbn/field-formats-plugin/common'; import type { AllowedSettingsOverrides, AllowedChartOverrides } from '@kbn/charts-plugin/common'; +import type { ChartSizeSpec } from '@kbn/chart-expressions-common'; import type { AllowedGaugeOverrides, GaugeExpressionProps } from './expression_functions'; export type FormatFactory = (mapping?: SerializedFieldFormat) => IFieldFormat; @@ -22,4 +23,6 @@ export type GaugeRenderProps = GaugeExpressionProps & { renderComplete: () => void; uiState: PersistedState; overrides?: AllowedGaugeOverrides & AllowedSettingsOverrides & AllowedChartOverrides; + shouldUseVeil: boolean; + setChartSize: (d: ChartSizeSpec) => void; }; diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap b/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap index f797f9ba344e0..30735f360e32c 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_gauge/public/components/__snapshots__/gauge_component.test.tsx.snap @@ -536,6 +536,7 @@ exports[`GaugeComponent renders the chart 1`] = ` /> } onRenderChange={[Function]} + onResize={[Function]} theme={ Array [ Object { diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx index da8985d0427af..29163b414d82b 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx @@ -102,6 +102,8 @@ describe('GaugeComponent', function () { paletteService: await paletteThemeService.getPalettes(), uiState, renderComplete: jest.fn(), + setChartSize: jest.fn(), + shouldUseVeil: false, }; }); diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx index 6565673cea0da..a5a71ffc25c34 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx @@ -12,7 +12,11 @@ import type { PaletteOutput } from '@kbn/coloring'; import { FieldFormat } from '@kbn/field-formats-plugin/common'; import type { CustomPaletteState } from '@kbn/charts-plugin/public'; import { EmptyPlaceholder } from '@kbn/charts-plugin/public'; -import { getOverridesFor } from '@kbn/chart-expressions-common'; +import { + type ChartSizeSpec, + getOverridesFor, + useSizeTransitionVeil, +} from '@kbn/chart-expressions-common'; import { isVisDimension } from '@kbn/visualizations-plugin/common/utils'; import { i18n } from '@kbn/i18n'; import { @@ -178,6 +182,8 @@ export const GaugeComponent: FC = memo( chartsThemeService, renderComplete, overrides, + shouldUseVeil, + setChartSize, }) => { const { shape: gaugeType, @@ -253,6 +259,26 @@ export const GaugeComponent: FC = memo( [renderComplete] ); + const chartSizeSpec: ChartSizeSpec = { + maxDimensions: { + ...(gaugeType === GaugeShapes.HORIZONTAL_BULLET + ? { + x: { value: 600, unit: 'pixels' }, + y: { value: 300, unit: 'pixels' }, + } + : { + y: { value: 600, unit: 'pixels' }, + x: { value: 300, unit: 'pixels' }, + }), + }, + }; + + const { veil, onResize, containerRef } = useSizeTransitionVeil( + chartSizeSpec, + setChartSize, + shouldUseVeil + ); + const table = data; const accessors = getAccessorsFromArgs(args, table.columns); @@ -359,7 +385,8 @@ export const GaugeComponent: FC = memo( : {}; return ( -
+
+ {veil} } @@ -369,6 +396,7 @@ export const GaugeComponent: FC = memo( ariaLabel={args.ariaLabel} ariaUseDefaultSummary={!args.ariaLabel} onRenderChange={onRenderChange} + onResize={onResize} locale={i18n.getLocale()} {...getOverridesFor(overrides, 'settings')} /> diff --git a/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx b/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx index f86d6f2bff508..9759ceca52725 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/expression_renderers/gauge_renderer.tsx @@ -13,7 +13,11 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common/expression_renderers'; import { StartServicesGetter } from '@kbn/kibana-utils-plugin/public'; import { METRIC_TYPE } from '@kbn/analytics'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { ExpressionGaugePluginStart } from '../plugin'; import { EXPRESSION_GAUGE_NAME, GaugeExpressionProps, GaugeShapes } from '../../common'; import { getFormatService, getPaletteService } from '../services'; @@ -66,16 +70,27 @@ export const gaugeRenderer: ( handlers.done(); }; + const setChartSize = (chartSizeSpec: ChartSizeEvent['data']) => { + const event: ChartSizeEvent = { + name: 'chartSize', + data: chartSizeSpec, + }; + + handlers.event(event); + }; + const { GaugeComponent } = await import('../components/gauge_component'); render(
diff --git a/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx b/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx index 1d324ad63be55..029a2782f70ac 100644 --- a/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx +++ b/src/plugins/chart_expressions/expression_heatmap/public/expression_renderers/heatmap_renderer.tsx @@ -14,7 +14,11 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common/expression_renderers'; import { StartServicesGetter } from '@kbn/kibana-utils-plugin/public'; import { METRIC_TYPE } from '@kbn/analytics'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { I18nProvider } from '@kbn/i18n-react'; import { MultiFilterEvent } from '../../common/types'; import { ExpressionHeatmapPluginStart } from '../plugin'; @@ -78,6 +82,18 @@ export const heatmapRenderer: ( handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + const timeZone = getTimeZone(getUISettings()); const { HeatmapComponent } = await import('../components/heatmap_component'); const { isInteractive } = handlers; diff --git a/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx b/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx index 310f8e0ee54f4..be9164101202e 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx @@ -21,7 +21,11 @@ import { import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils'; import { Datatable } from '@kbn/expressions-plugin/common'; import { StartServicesGetter } from '@kbn/kibana-utils-plugin/public'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { ExpressionLegacyMetricPluginStart } from '../plugin'; import { EXPRESSION_METRIC_NAME, MetricVisRenderConfig, VisParams } from '../../common'; @@ -92,6 +96,18 @@ export const getMetricVisRenderer: ( handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + render( ; +} as Pick; describe('MetricVisComponent', function () { afterEach(() => { @@ -239,7 +238,7 @@ describe('MetricVisComponent', function () { expect(visConfig).toMatchInlineSnapshot(` Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": [Function], "subtitle": undefined, @@ -299,7 +298,7 @@ describe('MetricVisComponent', function () { expect(configWithPrefix).toMatchInlineSnapshot(` Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": secondary prefix number-13.6328125 @@ -348,7 +347,7 @@ describe('MetricVisComponent', function () { expect(configWithProgress).toMatchInlineSnapshot(` Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 28.984375, "extra": , "icon": [Function], @@ -425,7 +424,7 @@ describe('MetricVisComponent', function () { expect(visConfig).toMatchInlineSnapshot(` Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -434,7 +433,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -443,7 +442,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -452,7 +451,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -461,7 +460,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -590,7 +589,7 @@ describe('MetricVisComponent', function () { Array [ Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -599,7 +598,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -608,7 +607,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -617,7 +616,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -626,7 +625,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -637,7 +636,7 @@ describe('MetricVisComponent', function () { ], Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "extra": , "icon": undefined, "subtitle": "Median products.base_price", @@ -678,7 +677,7 @@ describe('MetricVisComponent', function () { Array [ Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 28.984375, "extra": , "icon": undefined, @@ -689,7 +688,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 28.984375, "extra": , "icon": undefined, @@ -700,7 +699,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 25.984375, "extra": , "icon": undefined, @@ -711,7 +710,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 25.784375, "extra": , "icon": undefined, @@ -722,7 +721,7 @@ describe('MetricVisComponent', function () { "valueFormatter": [Function], }, Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 25.348011363636363, "extra": , "icon": undefined, @@ -735,7 +734,7 @@ describe('MetricVisComponent', function () { ], Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "domainMax": 24.984375, "extra": , "icon": undefined, @@ -849,124 +848,60 @@ describe('MetricVisComponent', function () { }); }); - describe('rendering with no data', () => {}); - it('should constrain dimensions in edit mode', () => { - const getContainerStyles = (editMode: boolean, multipleTiles: boolean) => - ( - shallow( - - ) - .find('div') - .at(0) - .props() as HtmlAttributes & { css: { styles: string } } - ).css.styles; - - expect(getContainerStyles(false, false)).toMatchInlineSnapshot(` - " - height: 100%; - width: 100%; - max-height: 100%; - max-width: 100%; - overflow-y: auto; - scrollbar-width: thin; - - &::-webkit-scrollbar { - inline-size: 16px; - block-size: 16px; - } - - &::-webkit-scrollbar-thumb { - background-color: rgba(105,112,125,0.5); - background-clip: content-box; - border-radius: 16px; - border: calc(8px * 0.75) solid transparent; - } - - &::-webkit-scrollbar-corner, - &::-webkit-scrollbar-track { - background-color: transparent; - } - - scrollbar-color: rgba(105,112,125,0.5) transparent; - - " - `); - - expect(getContainerStyles(true, false)).toMatchInlineSnapshot(` - " - height: 300px; - width: 300px; - max-height: 100%; - max-width: 100%; - overflow-y: auto; - scrollbar-width: thin; - - &::-webkit-scrollbar { - inline-size: 16px; - block-size: 16px; - } + const getDimensionsRequest = (multipleTiles: boolean) => { + const fireEvent = jest.fn(); + const wrapper = shallow( + + ); - &::-webkit-scrollbar-thumb { - background-color: rgba(105,112,125,0.5); - background-clip: content-box; - border-radius: 16px; - border: calc(8px * 0.75) solid transparent; - } + wrapper.find(Settings).props().onWillRender!(); - &::-webkit-scrollbar-corner, - &::-webkit-scrollbar-track { - background-color: transparent; - } + return fireEvent.mock.calls[0][0].data; + }; - scrollbar-color: rgba(105,112,125,0.5) transparent; - - " + expect(getDimensionsRequest(false)).toMatchInlineSnapshot(` + Object { + "maxDimensions": Object { + "x": Object { + "unit": "pixels", + "value": 300, + }, + "y": Object { + "unit": "pixels", + "value": 300, + }, + }, + } `); - expect(getContainerStyles(true, true)).toMatchInlineSnapshot(` - " - height: 400px; - width: 1000px; - max-height: 100%; - max-width: 100%; - overflow-y: auto; - scrollbar-width: thin; - - &::-webkit-scrollbar { - inline-size: 16px; - block-size: 16px; - } - - &::-webkit-scrollbar-thumb { - background-color: rgba(105,112,125,0.5); - background-clip: content-box; - border-radius: 16px; - border: calc(8px * 0.75) solid transparent; - } - - &::-webkit-scrollbar-corner, - &::-webkit-scrollbar-track { - background-color: transparent; - } - - scrollbar-color: rgba(105,112,125,0.5) transparent; - - " + expect(getDimensionsRequest(true)).toMatchInlineSnapshot(` + Object { + "maxDimensions": Object { + "x": Object { + "unit": "pixels", + "value": 1000, + }, + "y": Object { + "unit": "pixels", + "value": 400, + }, + }, + } `); }); @@ -1308,7 +1243,7 @@ describe('MetricVisComponent', function () { const [[datum]] = component.find(Metric).props().data!; - expect(datum!.color).toBe(euiThemeVars.euiColorLightestShade); + expect(datum!.color).toBe(euiThemeVars.euiColorEmptyShade); expect(mockGetColorForValue).not.toHaveBeenCalled(); }); }); diff --git a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx index ba3ef124d7ed2..fb1383ce98d48 100644 --- a/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/components/metric_vis.tsx @@ -29,7 +29,6 @@ import type { DatatableColumn, DatatableRow, IInterpreterRenderHandlers, - RenderMode, } from '@kbn/expressions-plugin/common'; import { CustomPaletteState } from '@kbn/charts-plugin/public'; import { @@ -41,13 +40,13 @@ import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; import { useResizeObserver, useEuiScrollBar, EuiIcon } from '@elastic/eui'; import { AllowedChartOverrides, AllowedSettingsOverrides } from '@kbn/charts-plugin/common'; -import { getOverridesFor } from '@kbn/chart-expressions-common'; +import { type ChartSizeEvent, getOverridesFor } from '@kbn/chart-expressions-common'; import { DEFAULT_TRENDLINE_NAME } from '../../common/constants'; import { VisParams } from '../../common'; import { getPaletteService, getThemeService, getFormatService } from '../services'; import { getDataBoundsForPalette } from '../utils'; -export const defaultColor = euiThemeVars.euiColorLightestShade; +export const defaultColor = euiThemeVars.euiColorEmptyShade; function enhanceFieldFormat(serializedFieldFormat: SerializedFieldFormat | undefined) { const formatId = serializedFieldFormat?.id || 'number'; @@ -140,7 +139,6 @@ export interface MetricVisComponentProps { config: Pick; renderComplete: IInterpreterRenderHandlers['done']; fireEvent: IInterpreterRenderHandlers['event']; - renderMode: RenderMode; filterable: boolean; overrides?: AllowedSettingsOverrides & AllowedChartOverrides; } @@ -150,10 +148,11 @@ export const MetricVis = ({ config, renderComplete, fireEvent, - renderMode, filterable, overrides, }: MetricVisComponentProps) => { + const grid = useRef([[]]); + const onRenderChange = useCallback( (isRendered) => { if (isRendered) { @@ -163,6 +162,20 @@ export const MetricVis = ({ [renderComplete] ); + const onWillRender = useCallback(() => { + const maxTileSideLength = grid.current.length * grid.current[0].length > 1 ? 200 : 300; + const event: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + y: { value: grid.current.length * maxTileSideLength, unit: 'pixels' }, + x: { value: grid.current[0]?.length * maxTileSideLength, unit: 'pixels' }, + }, + }, + }; + fireEvent(event); + }, [fireEvent, grid]); + const [scrollChildHeight, setScrollChildHeight] = useState('100%'); const scrollContainerRef = useRef(null); const scrollDimensions = useResizeObserver(scrollContainerRef.current); @@ -289,28 +302,19 @@ export const MetricVis = ({ 'settings' ) as Partial; - const grid: MetricSpec['data'] = []; + const newGrid: MetricSpec['data'] = []; for (let i = 0; i < metricConfigs.length; i += maxCols) { - grid.push(metricConfigs.slice(i, i + maxCols)); + newGrid.push(metricConfigs.slice(i, i + maxCols)); } - let pixelHeight; - let pixelWidth; - if (renderMode === 'edit') { - // In the editor, we constrain the maximum size of the tiles for aesthetic reasons - const maxTileSideLength = metricConfigs.flat().length > 1 ? 200 : 300; - pixelHeight = grid.length * maxTileSideLength; - pixelWidth = grid[0]?.length * maxTileSideLength; - } + grid.current = newGrid; return (
{ const colRef = breakdownByColumn ?? primaryMetricColumn; - const rowLength = grid[0].length; + const rowLength = grid.current[0].length; events.forEach((event) => { if (isMetricElementEvent(event)) { const colIdx = data.columns.findIndex((col) => col === colRef); @@ -360,7 +365,7 @@ export const MetricVis = ({ } {...settingsOverrides} /> - +
diff --git a/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx index 9841e65d5ed20..4ba6076e032fa 100644 --- a/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_metric/public/expression_renderers/metric_vis_renderer.tsx @@ -101,7 +101,6 @@ export const getMetricVisRenderer = ( config={visConfig} renderComplete={renderComplete} fireEvent={handlers.event} - renderMode={handlers.getRenderMode()} filterable={filterable} overrides={overrides} /> diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx index 2379096796639..ac8a053f37ebd 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx @@ -22,6 +22,7 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { METRIC_TYPE } from '@kbn/analytics'; import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils'; import { + type ChartSizeEvent, extractContainerType, extractVisualizationType, isOnAggBasedEditor, @@ -116,6 +117,18 @@ export const getPartitionVisRenderer: ( const hasOpenedOnAggBasedEditor = isOnAggBasedEditor(handlers.getExecutionContext()); + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + render( diff --git a/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx index 101c40b6b384d..8dd3d7eb09358 100644 --- a/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx +++ b/src/plugins/chart_expressions/expression_tagcloud/public/expression_renderers/tagcloud_renderer.tsx @@ -15,7 +15,11 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { VisualizationContainer } from '@kbn/visualizations-plugin/public'; import { ExpressionRenderDefinition } from '@kbn/expressions-plugin/common/expression_renderers'; import { METRIC_TYPE } from '@kbn/analytics'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + type ChartSizeEvent, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import { ExpressionTagcloudRendererDependencies } from '../plugin'; import { TagcloudRendererConfig } from '../../common/types'; @@ -66,6 +70,18 @@ export const tagcloudRenderer: ( handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + const palettesRegistry = await plugins.charts.palettes.getPalettes(); let isDarkMode = false; plugins.charts.theme.darkModeEnabled$ diff --git a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap index 267833cba170d..a2f62afd3aee6 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap +++ b/src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap @@ -300,6 +300,18 @@ exports[`XYChart component it renders area 1`] = ` } } > +
+
+
+
+
+
+
+
+
+
{ eventAnnotationService: eventAnnotationServiceMock, renderComplete: jest.fn(), timeFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', + setChartSize: jest.fn(), + shouldUseVeil: false, }; }); diff --git a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx index 4eb52c67f20bd..7e4c5a5c6b974 100644 --- a/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/components/xy_chart.tsx @@ -52,7 +52,11 @@ import { LegendSizeToPixels, } from '@kbn/visualizations-plugin/common/constants'; import { PersistedState } from '@kbn/visualizations-plugin/public'; -import { getOverridesFor } from '@kbn/chart-expressions-common'; +import { + useSizeTransitionVeil, + getOverridesFor, + ChartSizeSpec, +} from '@kbn/chart-expressions-common'; import type { FilterEvent, BrushEvent, @@ -144,8 +148,11 @@ export type XYChartRenderProps = Omit & { syncCursor: boolean; eventAnnotationService: EventAnnotationServiceType; renderComplete: () => void; + shouldUseVeil: boolean; uiState?: PersistedState; timeFormat: string; + setChartSize: (chartSizeSpec: ChartSizeSpec) => void; + shouldShowLegendAction?: (actionId: string) => boolean; }; function nonNullable(v: T): v is NonNullable { @@ -199,12 +206,16 @@ export function XYChart({ onClickMultiValue, layerCellValueActions, onSelectRange, + setChartSize, interactive = true, syncColors, syncTooltips, syncCursor, + shouldUseVeil, + useLegacyTimeAxis, renderComplete, + uiState, timeFormat, overrides, @@ -293,6 +304,34 @@ export function XYChart({ ); const dataLayers: CommonXYDataLayerConfig[] = filteredLayers.filter(isDataLayer); + + const isTimeViz = isTimeChart(dataLayers); + + const chartSizeSpec: ChartSizeSpec = + isTimeViz && !isHorizontalChart(dataLayers) + ? { + aspectRatio: { + x: 16, + y: 9, + }, + minDimensions: { + y: { value: 300, unit: 'pixels' }, + x: { value: 100, unit: 'percentage' }, + }, + } + : { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }; + + const { veil, onResize, containerRef } = useSizeTransitionVeil( + chartSizeSpec, + setChartSize, + shouldUseVeil + ); + const formattedDatatables = useMemo( () => getFormattedTablesByLayers(dataLayers, formatFactory, splitColumnAccessor, splitRowAccessor), @@ -371,8 +410,6 @@ export function XYChart({ (layer) => isDataLayer(layer) && layer.splitAccessors && layer.splitAccessors.length ); - const isTimeViz = isTimeChart(dataLayers); - const defaultXScaleType = isTimeViz ? XScaleTypes.TIME : XScaleTypes.ORDINAL; const isHistogramViz = dataLayers.every((l) => l.isHistogram); @@ -711,7 +748,8 @@ export function XYChart({ ); return ( -
+
+ {veil} {showLegend !== undefined && uiState && ( } onRenderChange={onRenderChange} + onResize={onResize} onPointerUpdate={syncCursor ? handleCursorUpdate : undefined} externalPointerEvents={{ tooltip: { visible: syncTooltips, placement: Placement.Right }, diff --git a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx index c2561191deb9a..2d88ed53ac3f0 100644 --- a/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx +++ b/src/plugins/chart_expressions/expression_xy/public/expression_renderers/xy_chart_renderer.tsx @@ -26,7 +26,12 @@ import { FormatFactory } from '@kbn/field-formats-plugin/common'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; import { getColumnByAccessor } from '@kbn/visualizations-plugin/common/utils'; -import { extractContainerType, extractVisualizationType } from '@kbn/chart-expressions-common'; +import { + type ChartSizeEvent, + type ChartSizeSpec, + extractContainerType, + extractVisualizationType, +} from '@kbn/chart-expressions-common'; import type { getDataLayers } from '../helpers'; import { LayerTypes, SeriesTypes } from '../../common/constants'; @@ -215,6 +220,10 @@ export const getXyChartRenderer = ({ const onClickMultiValue = (data: MultiFilterEvent['data']) => { handlers.event({ name: 'multiFilter', data }); }; + const setChartSize = (data: ChartSizeSpec) => { + const event: ChartSizeEvent = { name: 'chartSize', data }; + handlers.event(event); + }; const layerCellValueActions = await getLayerCellValueActions( getDataLayers(config.args.layers), @@ -275,8 +284,10 @@ export const getXyChartRenderer = ({ syncColors={config.syncColors} syncTooltips={config.syncTooltips} syncCursor={config.syncCursor} + shouldUseVeil={handlers.shouldUseSizeTransitionVeil()} uiState={handlers.uiState as PersistedState} renderComplete={renderComplete} + setChartSize={setChartSize} />
diff --git a/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts b/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts index 33c76be0bcb8b..54406cdefb095 100644 --- a/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts +++ b/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts @@ -224,6 +224,25 @@ const rules = { // populated by a global rule }, }, + ip_prefix: { + __template: { + field: '', + }, + ipPrefix: { + __template: { + prefixLength: 1, + isIpv6: false, + }, + prefixLength: 1, + isIpv6: false, + }, + field: '{field}', + format: '', + keyed: { __one_of: [true, false] }, + script: { + // populated by a global rule + }, + }, ip_range: { __template: { field: '', diff --git a/src/plugins/data/common/search/aggs/agg_types.ts b/src/plugins/data/common/search/aggs/agg_types.ts index 33485b2fda629..659a9b4a67cea 100644 --- a/src/plugins/data/common/search/aggs/agg_types.ts +++ b/src/plugins/data/common/search/aggs/agg_types.ts @@ -58,6 +58,7 @@ export const getAggTypes = () => ({ { name: BUCKET_TYPES.HISTOGRAM, fn: buckets.getHistogramBucketAgg }, { name: BUCKET_TYPES.RANGE, fn: buckets.getRangeBucketAgg }, { name: BUCKET_TYPES.DATE_RANGE, fn: buckets.getDateRangeBucketAgg }, + { name: BUCKET_TYPES.IP_PREFIX, fn: buckets.getIpPrefixBucketAgg }, { name: BUCKET_TYPES.IP_RANGE, fn: buckets.getIpRangeBucketAgg }, { name: BUCKET_TYPES.TERMS, fn: buckets.getTermsBucketAgg }, { name: BUCKET_TYPES.MULTI_TERMS, fn: buckets.getMultiTermsBucketAgg }, @@ -79,6 +80,7 @@ export const getAggTypesFunctions = () => [ buckets.aggFilters, buckets.aggSignificantTerms, buckets.aggSignificantText, + buckets.aggIpPrefix, buckets.aggIpRange, buckets.aggDateRange, buckets.aggRange, diff --git a/src/plugins/data/common/search/aggs/aggs_service.test.ts b/src/plugins/data/common/search/aggs/aggs_service.test.ts index ebc357a20571a..1699d9815edc6 100644 --- a/src/plugins/data/common/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/common/search/aggs/aggs_service.test.ts @@ -57,6 +57,7 @@ describe('Aggs service', () => { "histogram", "range", "date_range", + "ip_prefix", "ip_range", "terms", "multi_terms", @@ -112,6 +113,7 @@ describe('Aggs service', () => { "histogram", "range", "date_range", + "ip_prefix", "ip_range", "terms", "multi_terms", diff --git a/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts b/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts index 91b0bc1b56fc3..2d6702d5ca721 100644 --- a/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts +++ b/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts @@ -10,6 +10,7 @@ export enum BUCKET_TYPES { FILTER = 'filter', FILTERS = 'filters', HISTOGRAM = 'histogram', + IP_PREFIX = 'ip_prefix', IP_RANGE = 'ip_range', DATE_RANGE = 'date_range', RANGE = 'range', diff --git a/src/plugins/data/common/search/aggs/buckets/create_filter/ip_prefix.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/ip_prefix.test.ts new file mode 100644 index 0000000000000..8ee2376a47416 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/ip_prefix.test.ts @@ -0,0 +1,122 @@ +/* + * 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 { createFilterIpPrefix } from './ip_prefix'; +import { AggConfigs, CreateAggConfigParams } from '../../agg_configs'; +import { mockAggTypesRegistry } from '../../test_helpers'; +import { IpFormat } from '@kbn/field-formats-plugin/common'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { IBucketAggConfig } from '../bucket_agg_type'; +import { RangeFilter } from '@kbn/es-query'; + +describe('AggConfig Filters', () => { + describe('IP prefix', () => { + const typesRegistry = mockAggTypesRegistry(); + const getAggConfigs = (aggs: CreateAggConfigParams[]) => { + const field = { + name: 'ip', + format: IpFormat, + }; + + const indexPattern = { + id: '1234', + title: 'logstash-*', + fields: { + getByName: () => field, + filter: () => [field], + }, + } as any; + + return new AggConfigs(indexPattern, aggs, { typesRegistry }, jest.fn()); + }; + + test('should return a range filter for ip_prefix agg - ipv4', () => { + const aggConfigs = getAggConfigs([ + { + type: BUCKET_TYPES.IP_PREFIX, + schema: 'segment', + params: { + field: 'ip', + address: '10.0.0.0', + prefix_length: 8, + }, + }, + ]); + + const filter = createFilterIpPrefix(aggConfigs.aggs[0] as IBucketAggConfig, { + type: 'ip_prefix', + address: '10.0.0.0', + prefix_length: 8, + }) as RangeFilter; + + expect(filter.query).toHaveProperty('range'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.query.range).toHaveProperty('ip'); + expect(filter.query.range.ip).toHaveProperty('gte', '10.0.0.0'); + expect(filter.query.range.ip).toHaveProperty('lte', '10.255.255.255'); + }); + + test('should return a range filter for ip_prefix agg - ipv4 mapped to ipv6', () => { + const aggConfigs = getAggConfigs([ + { + type: BUCKET_TYPES.IP_PREFIX, + schema: 'segment', + params: { + field: 'ip', + address: '0.0.0.0', + prefix_length: 96, + }, + }, + ]); + + const filter = createFilterIpPrefix(aggConfigs.aggs[0] as IBucketAggConfig, { + type: 'ip_prefix', + address: '0.0.0.0', + prefix_length: 96, + }) as RangeFilter; + + expect(filter.query).toHaveProperty('range'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.query.range).toHaveProperty('ip'); + expect(filter.query.range.ip).toHaveProperty('gte', '::ffff:0:0'); + expect(filter.query.range.ip).toHaveProperty('lte', '::ffff:ffff:ffff'); + }); + + test('should return a range filter for ip_prefix agg - ipv6', () => { + const aggConfigs = getAggConfigs([ + { + type: BUCKET_TYPES.IP_PREFIX, + schema: 'segment', + params: { + field: 'ip', + address: '1989:1337:c0de:7e57::', + prefix_length: 56, + }, + }, + ]); + + const filter = createFilterIpPrefix(aggConfigs.aggs[0] as IBucketAggConfig, { + type: 'ip_prefix', + address: '1989:1337:c0de:7e57::', + prefix_length: 56, + }) as RangeFilter; + + expect(filter.query).toHaveProperty('range'); + expect(filter).toHaveProperty('meta'); + expect(filter.meta).toHaveProperty('index', '1234'); + expect(filter.query.range).toHaveProperty('ip'); + expect(filter.query.range.ip).toHaveProperty('gte', '1989:1337:c0de:7e00::'); + expect(filter.query.range.ip).toHaveProperty( + 'lte', + '1989:1337:c0de:7eff:ffff:ffff:ffff:ffff' + ); + }); + }); +}); diff --git a/src/plugins/data/common/search/aggs/buckets/create_filter/ip_prefix.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/ip_prefix.ts new file mode 100644 index 0000000000000..fb979ca2b7967 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/ip_prefix.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 { buildRangeFilter } from '@kbn/es-query'; +import { CidrMask } from '../lib/cidr_mask'; +import { IBucketAggConfig } from '../bucket_agg_type'; +import { IpPrefixKey } from '../lib/ip_prefix'; + +export const createFilterIpPrefix = (aggConfig: IBucketAggConfig, key: IpPrefixKey) => { + let ipAddress = key.address; + + /* + * Can occur when both IPv4 and IPv6 addresses are in the field being + * aggregated. When prefix_length is < 96, ES will group all IPv4 addresses + * into an IPv6 address and display that as the key, thus no mapping is required. + * Per RFC 4038 section 4.2, the IPv6 address ::FFFF:x.y.z.w represents the IPv4 + * address x.y.z.w. Therefore, if they key is an IPv4 address (e.g. it contains + * a dot) and the requested prefix is >= 96, then prepending ::ffff: will properly + * map the IPv4 address to IPv6 according to the RFC mentioned above which will + * enable proper filtering on the visualization. + */ + if (ipAddress.includes('.') && key.prefix_length >= 96) { + ipAddress = '::ffff:' + key.address; + } + + const range = new CidrMask(ipAddress + '/' + key.prefix_length).getRange(); + + return buildRangeFilter( + aggConfig.params.field, + { gte: range.from, lte: range.to }, + aggConfig.getIndexPattern() + ); +}; diff --git a/src/plugins/data/common/search/aggs/buckets/index.ts b/src/plugins/data/common/search/aggs/buckets/index.ts index 369e56caf1859..6a4ad38560cc3 100644 --- a/src/plugins/data/common/search/aggs/buckets/index.ts +++ b/src/plugins/data/common/search/aggs/buckets/index.ts @@ -21,6 +21,8 @@ export * from './geo_tile_fn'; export * from './geo_tile'; export * from './histogram_fn'; export * from './histogram'; +export * from './ip_prefix_fn'; +export * from './ip_prefix'; export * from './ip_range_fn'; export * from './ip_range'; export * from './lib/cidr_mask'; diff --git a/src/plugins/data/common/search/aggs/buckets/ip_prefix.ts b/src/plugins/data/common/search/aggs/buckets/ip_prefix.ts new file mode 100644 index 0000000000000..6b3cc8e28ac9c --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/ip_prefix.ts @@ -0,0 +1,73 @@ +/* + * 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'; +import { IpPrefix, ipPrefixToAst } from '../../expressions'; + +import { BucketAggType } from './bucket_agg_type'; +import { BUCKET_TYPES } from './bucket_agg_types'; +import { createFilterIpPrefix } from './create_filter/ip_prefix'; +import { IpPrefixKey } from './lib/ip_prefix'; +import { aggIpPrefixFnName } from './ip_prefix_fn'; +import { KBN_FIELD_TYPES } from '../../..'; +import { BaseAggParams } from '../types'; + +const ipPrefixTitle = i18n.translate('data.search.aggs.buckets.ipPrefixTitle', { + defaultMessage: 'IP Prefix', +}); + +export interface AggParamsIpPrefix extends BaseAggParams { + field: string; + ipPrefix?: IpPrefix; +} + +export const getIpPrefixBucketAgg = () => + new BucketAggType({ + name: BUCKET_TYPES.IP_PREFIX, + expressionName: aggIpPrefixFnName, + title: ipPrefixTitle, + createFilter: createFilterIpPrefix, + getKey(bucket, key, agg): IpPrefixKey { + return { type: 'ip_prefix', address: key, prefix_length: bucket.prefix_length }; + }, + getSerializedFormat(agg) { + return { + id: 'ip_prefix', + params: agg.params.field + ? agg.aggConfigs.indexPattern.getFormatterForField(agg.params.field).toJSON() + : {}, + }; + }, + makeLabel(aggConfig) { + return i18n.translate('data.search.aggs.buckets.ipPrefixLabel', { + defaultMessage: '{fieldName} IP prefixes', + values: { + fieldName: aggConfig.getFieldDisplayName(), + }, + }); + }, + params: [ + { + name: 'field', + type: 'field', + filterFieldTypes: KBN_FIELD_TYPES.IP, + }, + { + name: 'ipPrefix', + default: { + prefixLength: 0, + isIpv6: false, + }, + write: (aggConfig, output) => { + output.params.prefix_length = aggConfig.params.ipPrefix.prefixLength; + output.params.is_ipv6 = aggConfig.params.ipPrefix.isIpv6; + }, + toExpressionAst: ipPrefixToAst, + }, + ], + }); diff --git a/src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.test.ts new file mode 100644 index 0000000000000..fb0c6e378a2b4 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { functionWrapper } from '../test_helpers'; +import { aggIpPrefix } from './ip_prefix_fn'; + +describe('agg_expression_functions', () => { + describe('aggIpPrefix', () => { + const fn = functionWrapper(aggIpPrefix()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({ + field: 'ip_field', + }); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "ip_field", + "ipPrefix": undefined, + "json": undefined, + }, + "schema": undefined, + "type": "ip_prefix", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'ip_field', + ipPrefix: { prefixLength: 1, isIpv6: false, type: 'ip_prefix' }, + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "ip_field", + "ipPrefix": Object { + "isIpv6": false, + "prefixLength": 1, + "type": "ip_prefix", + }, + "json": undefined, + }, + "schema": undefined, + "type": "ip_prefix", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'ip_field', + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual('{ "foo": true }'); + }); + }); +}); diff --git a/src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.ts b/src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.ts new file mode 100644 index 0000000000000..68d7fc40544d3 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/ip_prefix_fn.ts @@ -0,0 +1,96 @@ +/* + * 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'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '@kbn/expressions-plugin/common'; +import { IpPrefixOutput } from '../../expressions'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '..'; + +export const aggIpPrefixFnName = 'aggIpPrefix'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition< + typeof aggIpPrefixFnName, + Input, + Arguments, + Output +>; + +export const aggIpPrefix = (): FunctionDefinition => ({ + name: aggIpPrefixFnName, + help: i18n.translate('data.search.aggs.function.buckets.ipPrefix.help', { + defaultMessage: 'Generates a serialized agg config for a Ip Prefix agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipPrefix.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.ipPrefix.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipPrefix.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.ipPrefix.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + ipPrefix: { + types: ['ip_prefix'], + help: i18n.translate('data.search.aggs.buckets.ipPrefix.help', { + defaultMessage: 'Length of the network prefix and whether it is for IPv4 or IPv6', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipPrefix.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipPrefix.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, { id, enabled, schema, ...params }) => { + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.IP_PREFIX, + params: { + ...params, + }, + }, + }; + }, +}); diff --git a/src/plugins/data/common/search/aggs/buckets/lib/ip_prefix.ts b/src/plugins/data/common/search/aggs/buckets/lib/ip_prefix.ts new file mode 100644 index 0000000000000..5b64c95290fe9 --- /dev/null +++ b/src/plugins/data/common/search/aggs/buckets/lib/ip_prefix.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface IpPrefixAggKey { + type: 'ip_prefix'; + address: string; + prefix_length: number; +} + +export type IpPrefixKey = IpPrefixAggKey; + +export const convertIPPrefixToString = (cidr: IpPrefixKey, format: (val: any) => string) => { + return format(cidr.address); +}; diff --git a/src/plugins/data/common/search/aggs/types.ts b/src/plugins/data/common/search/aggs/types.ts index 06320728105d2..bf8375724fe7f 100644 --- a/src/plugins/data/common/search/aggs/types.ts +++ b/src/plugins/data/common/search/aggs/types.ts @@ -30,6 +30,7 @@ import { aggGeoCentroid, aggGeoTile, aggHistogram, + aggIpPrefix, aggIpRange, aggMax, aggMedian, @@ -59,6 +60,7 @@ import { AggParamsGeoCentroid, AggParamsGeoTile, AggParamsHistogram, + AggParamsIpPrefix, AggParamsIpRange, AggParamsMax, AggParamsMedian, @@ -123,6 +125,7 @@ export type { IAggType } from './agg_type'; export type { AggParam, AggParamOption } from './agg_params'; export type { IFieldParamType } from './param_types'; export type { IMetricAggType } from './metrics/metric_agg_type'; +export type { IpPrefixKey } from './buckets/lib/ip_prefix'; export type { IpRangeKey } from './buckets/lib/ip_range'; export type { OptionedValueProp } from './param_types/optioned'; @@ -173,6 +176,7 @@ export type AggExpressionFunctionArgs; aggFilters: ReturnType; aggSignificantTerms: ReturnType; + aggIpPrefix: ReturnType; aggIpRange: ReturnType; aggDateRange: ReturnType; aggRange: ReturnType; diff --git a/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts index 24312060147cb..cfc5d96351128 100644 --- a/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts +++ b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts @@ -19,6 +19,7 @@ import { import { SerializableRecord } from '@kbn/utility-types'; import { DateRange } from '../../expressions'; import { convertDateRangeToString } from '../buckets/lib/date_range'; +import { convertIPPrefixToString, IpPrefixKey } from '../buckets/lib/ip_prefix'; import { convertIPRangeToString, IpRangeKey } from '../buckets/lib/ip_range'; import { MultiFieldKey } from '../buckets/multi_field_key'; @@ -113,6 +114,20 @@ export function getAggsFormats(getFieldFormat: GetFieldFormat): FieldFormatInsta return convertDateRangeToString(range, format.convert.bind(format)); }; }, + class AggsIpPrefixFieldFormat extends FieldFormatWithCache { + static id = 'ip_prefix'; + static hidden = true; + + textConvert = (cidr: IpPrefixKey) => { + if (cidr == null) { + return ''; + } + + const nestedFormatter = this._params as SerializedFieldFormat; + const format = this.getCachedFormat(nestedFormatter); + return convertIPPrefixToString(cidr, format.convert.bind(format)); + }; + }, class AggsIpRangeFieldFormat extends FieldFormatWithCache { static id = 'ip_range'; static hidden = true; diff --git a/src/plugins/data/common/search/expressions/index.ts b/src/plugins/data/common/search/expressions/index.ts index 8c37836e30dea..01e1f62193ad5 100644 --- a/src/plugins/data/common/search/expressions/index.ts +++ b/src/plugins/data/common/search/expressions/index.ts @@ -16,6 +16,8 @@ export * from './geo_bounding_box'; export * from './geo_bounding_box_to_ast'; export * from './geo_point'; export * from './geo_point_to_ast'; +export * from './ip_prefix'; +export * from './ip_prefix_to_ast'; export * from './ip_range'; export * from './ip_range_to_ast'; export * from './kibana'; diff --git a/src/plugins/data/common/search/expressions/ip_prefix.test.ts b/src/plugins/data/common/search/expressions/ip_prefix.test.ts new file mode 100644 index 0000000000000..953e3ae3d5619 --- /dev/null +++ b/src/plugins/data/common/search/expressions/ip_prefix.test.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 { functionWrapper } from './utils'; +import { ipPrefixFunction } from './ip_prefix'; + +describe('interpreter/functions#ipPrefix', () => { + const fn = functionWrapper(ipPrefixFunction); + + it('should return an IP prefix structure', () => { + expect(fn(null, { prefixLength: 2, isIpv6: true })).toEqual( + expect.objectContaining({ + prefixLength: 2, + isIpv6: true, + type: 'ip_prefix', + }) + ); + }); +}); diff --git a/src/plugins/data/common/search/expressions/ip_prefix.ts b/src/plugins/data/common/search/expressions/ip_prefix.ts new file mode 100644 index 0000000000000..bcdbb67e4f23b --- /dev/null +++ b/src/plugins/data/common/search/expressions/ip_prefix.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import { ExpressionFunctionDefinition, ExpressionValueBoxed } from '@kbn/expressions-plugin/common'; + +export interface IpPrefix { + prefixLength?: number; + isIpv6?: boolean; +} + +export type IpPrefixOutput = ExpressionValueBoxed<'ip_prefix', IpPrefix>; + +export type ExpressionFunctionIpPrefix = ExpressionFunctionDefinition< + 'ipPrefix', + null, + IpPrefix, + IpPrefixOutput +>; + +export const ipPrefixFunction: ExpressionFunctionIpPrefix = { + name: 'ipPrefix', + type: 'ip_prefix', + inputTypes: ['null'], + help: i18n.translate('data.search.functions.ipPrefix.help', { + defaultMessage: 'Create an IP prefix', + }), + args: { + prefixLength: { + types: ['number'], + help: i18n.translate('data.search.functions.ipPrefix.prefixLength.help', { + defaultMessage: 'Specify the length of the network prefix', + }), + }, + isIpv6: { + types: ['boolean'], + help: i18n.translate('data.search.functions.ipPrefix.isIpv6.help', { + defaultMessage: 'Specify whether the prefix applies to IPv6 addresses', + }), + }, + }, + + fn(input, { prefixLength, isIpv6 }) { + return { + type: 'ip_prefix', + prefixLength, + isIpv6, + }; + }, +}; diff --git a/src/plugins/data/common/search/expressions/ip_prefix_to_ast.test.ts b/src/plugins/data/common/search/expressions/ip_prefix_to_ast.test.ts new file mode 100644 index 0000000000000..5dc5642fb96e1 --- /dev/null +++ b/src/plugins/data/common/search/expressions/ip_prefix_to_ast.test.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 { ipPrefixToAst } from './ip_prefix_to_ast'; + +describe('ipPrefixToAst', () => { + it('should return an expression', () => { + expect(ipPrefixToAst({ prefixLength: 2, isIpv6: false })).toHaveProperty('type', 'expression'); + }); + + it('should forward arguments', () => { + expect(ipPrefixToAst({ prefixLength: 2, isIpv6: false })).toHaveProperty( + 'chain.0.arguments', + expect.objectContaining({ + prefixLength: [2], + isIpv6: [false], + }) + ); + }); +}); diff --git a/src/plugins/data/common/search/expressions/ip_prefix_to_ast.ts b/src/plugins/data/common/search/expressions/ip_prefix_to_ast.ts new file mode 100644 index 0000000000000..82f2e03a4d813 --- /dev/null +++ b/src/plugins/data/common/search/expressions/ip_prefix_to_ast.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 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 { buildExpression, buildExpressionFunction } from '@kbn/expressions-plugin/common'; +import { ExpressionFunctionIpPrefix, IpPrefix } from './ip_prefix'; + +export const ipPrefixToAst = (ipPrefix: IpPrefix) => { + return buildExpression([ + buildExpressionFunction('ipPrefix', ipPrefix), + ]).toAst(); +}; diff --git a/src/plugins/data/public/search/aggs/aggs_service.test.ts b/src/plugins/data/public/search/aggs/aggs_service.test.ts index cbd0cbc40eb03..8f3a54f2de86f 100644 --- a/src/plugins/data/public/search/aggs/aggs_service.test.ts +++ b/src/plugins/data/public/search/aggs/aggs_service.test.ts @@ -52,7 +52,7 @@ describe('AggsService - public', () => { test('registers default agg types', () => { service.setup(setupDeps); const start = service.start(startDeps); - expect(start.types.getAll().buckets.length).toBe(16); + expect(start.types.getAll().buckets.length).toBe(17); expect(start.types.getAll().metrics.length).toBe(27); }); @@ -68,7 +68,7 @@ describe('AggsService - public', () => { ); const start = service.start(startDeps); - expect(start.types.getAll().buckets.length).toBe(17); + expect(start.types.getAll().buckets.length).toBe(18); expect(start.types.getAll().buckets.some(({ name }) => name === 'foo')).toBe(true); expect(start.types.getAll().metrics.length).toBe(28); expect(start.types.getAll().metrics.some(({ name }) => name === 'bar')).toBe(true); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index f336096468606..eded37dd3dd6f 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -39,6 +39,7 @@ import { fieldFunction, geoBoundingBoxFunction, geoPointFunction, + ipPrefixFunction, ipRangeFunction, ISearchGeneric, kibana, @@ -149,6 +150,7 @@ export class SearchService implements Plugin { expressions.registerFunction(cidrFunction); expressions.registerFunction(dateRangeFunction); expressions.registerFunction(extendedBoundsFunction); + expressions.registerFunction(ipPrefixFunction); expressions.registerFunction(ipRangeFunction); expressions.registerFunction(luceneFunction); expressions.registerFunction(kqlFunction); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 188f853e6a2ce..ea7ec05d74ca9 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -60,6 +60,7 @@ import { IEsSearchResponse, IKibanaSearchRequest, IKibanaSearchResponse, + ipPrefixFunction, ipRangeFunction, ISearchOptions, kibana, @@ -225,6 +226,7 @@ export class SearchService implements Plugin { expressions.registerFunction(extendedBoundsFunction); expressions.registerFunction(geoBoundingBoxFunction); expressions.registerFunction(geoPointFunction); + expressions.registerFunction(ipPrefixFunction); expressions.registerFunction(ipRangeFunction); expressions.registerFunction(kibana); expressions.registerFunction(luceneFunction); diff --git a/src/plugins/discover/public/application/main/services/discover_saved_search_container.ts b/src/plugins/discover/public/application/main/services/discover_saved_search_container.ts index 422fa787da849..ef88aba74d7db 100644 --- a/src/plugins/discover/public/application/main/services/discover_saved_search_container.ts +++ b/src/plugins/discover/public/application/main/services/discover_saved_search_container.ts @@ -318,7 +318,9 @@ function getSearchSourceFieldValueForComparison( searchSourceFieldName: keyof SearchSourceFields ) { if (searchSourceFieldName === 'index') { - return searchSource.getField('index')?.id; + const query = searchSource.getField('query'); + // ad-hoc data view id can change, so we rather compare the ES|QL query itself here + return query && 'esql' in query ? query.esql : searchSource.getField('index')?.id; } if (searchSourceFieldName === 'filter') { diff --git a/src/plugins/expressions/common/execution/execution.ts b/src/plugins/expressions/common/execution/execution.ts index 593e437fd9dc7..03a0923b4b313 100644 --- a/src/plugins/expressions/common/execution/execution.ts +++ b/src/plugins/expressions/common/execution/execution.ts @@ -287,6 +287,7 @@ export class Execution< isSyncColorsEnabled: () => execution.params.syncColors!, isSyncCursorEnabled: () => execution.params.syncCursor!, isSyncTooltipsEnabled: () => execution.params.syncTooltips!, + shouldUseSizeTransitionVeil: () => execution.params.shouldUseSizeTransitionVeil!, ...execution.executor.context, getExecutionContext: () => execution.params.executionContext, }; diff --git a/src/plugins/expressions/common/execution/types.ts b/src/plugins/expressions/common/execution/types.ts index 03dbcc8a6ff13..ac216515a3f1b 100644 --- a/src/plugins/expressions/common/execution/types.ts +++ b/src/plugins/expressions/common/execution/types.ts @@ -72,6 +72,11 @@ export interface ExecutionContext */ isSyncTooltipsEnabled?: () => boolean; + /** + * Returns whether or not to use the size transition veil when resizing visualizations. + */ + shouldUseSizeTransitionVeil?: () => boolean; + /** * Contains the meta-data about the source of the expression. */ diff --git a/src/plugins/expressions/common/expression_renderers/types.ts b/src/plugins/expressions/common/expression_renderers/types.ts index 7dae307aa6c01..46908e8b38e6e 100644 --- a/src/plugins/expressions/common/expression_renderers/types.ts +++ b/src/plugins/expressions/common/expression_renderers/types.ts @@ -97,6 +97,9 @@ export interface IInterpreterRenderHandlers { isSyncCursorEnabled(): boolean; isSyncTooltipsEnabled(): boolean; + + shouldUseSizeTransitionVeil(): boolean; + /** * This uiState interface is actually `PersistedState` from the visualizations plugin, * but expressions cannot know about vis or it creates a mess of circular dependencies. diff --git a/src/plugins/expressions/common/service/expressions_services.ts b/src/plugins/expressions/common/service/expressions_services.ts index e73e07a387c46..2683921bc038b 100644 --- a/src/plugins/expressions/common/service/expressions_services.ts +++ b/src/plugins/expressions/common/service/expressions_services.ts @@ -156,6 +156,11 @@ export interface ExpressionExecutionParams { syncTooltips?: boolean; + // if this is set to true, a veil will be shown when resizing visualizations in response + // to a chart resize event (see src/plugins/chart_expressions/common/chart_size_transition_veil.tsx). + // This should be only set to true if the client will be responding to the resize events + shouldUseSizeTransitionVeil?: boolean; + inspectorAdapters?: Adapters; executionContext?: KibanaExecutionContext; diff --git a/src/plugins/expressions/public/loader.ts b/src/plugins/expressions/public/loader.ts index f10b8db1f1287..0a3c0e0990645 100644 --- a/src/plugins/expressions/public/loader.ts +++ b/src/plugins/expressions/public/loader.ts @@ -60,6 +60,7 @@ export class ExpressionLoader { syncColors: params?.syncColors, syncTooltips: params?.syncTooltips, syncCursor: params?.syncCursor, + shouldUseSizeTransitionVeil: params?.shouldUseSizeTransitionVeil, hasCompatibleActions: params?.hasCompatibleActions, getCompatibleCellValueActions: params?.getCompatibleCellValueActions, executionContext: params?.executionContext, @@ -148,6 +149,7 @@ export class ExpressionLoader { syncColors: params.syncColors, syncCursor: params?.syncCursor, syncTooltips: params.syncTooltips, + shouldUseSizeTransitionVeil: params.shouldUseSizeTransitionVeil, executionContext: params.executionContext, partial: params.partial, throttle: params.throttle, diff --git a/src/plugins/expressions/public/render.ts b/src/plugins/expressions/public/render.ts index a7b919625b8d6..0b494f30b2e69 100644 --- a/src/plugins/expressions/public/render.ts +++ b/src/plugins/expressions/public/render.ts @@ -33,6 +33,7 @@ export interface ExpressionRenderHandlerParams { syncCursor?: boolean; syncTooltips?: boolean; interactive?: boolean; + shouldUseSizeTransitionVeil?: boolean; hasCompatibleActions?: (event: ExpressionRendererEvent) => Promise; getCompatibleCellValueActions?: (data: object[]) => Promise; executionContext?: KibanaExecutionContext; @@ -62,6 +63,7 @@ export class ExpressionRenderHandler { syncColors, syncTooltips, syncCursor, + shouldUseSizeTransitionVeil, interactive, hasCompatibleActions = async () => false, getCompatibleCellValueActions = async () => [], @@ -113,6 +115,9 @@ export class ExpressionRenderHandler { isSyncCursorEnabled: () => { return syncCursor || true; }, + shouldUseSizeTransitionVeil: () => { + return Boolean(shouldUseSizeTransitionVeil); + }, isInteractive: () => { return interactive ?? true; }, diff --git a/src/plugins/expressions/public/types/index.ts b/src/plugins/expressions/public/types/index.ts index 7bbb486fde390..27090f36fdc7c 100644 --- a/src/plugins/expressions/public/types/index.ts +++ b/src/plugins/expressions/public/types/index.ts @@ -52,6 +52,10 @@ export interface IExpressionLoaderParams { syncColors?: boolean; syncCursor?: boolean; syncTooltips?: boolean; + // if this is set to true, a veil will be shown when resizing visualizations in response + // to a chart resize event (see src/plugins/chart_expressions/common/chart_size_transition_veil.tsx). + // This should be only set to true if the client will be responding to the resize events + shouldUseSizeTransitionVeil?: boolean; hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions']; getCompatibleCellValueActions?: ExpressionRenderHandlerParams['getCompatibleCellValueActions']; executionContext?: KibanaExecutionContext; diff --git a/src/plugins/presentation_util/public/__stories__/render.tsx b/src/plugins/presentation_util/public/__stories__/render.tsx index ca9f968842270..e02f1c803d332 100644 --- a/src/plugins/presentation_util/public/__stories__/render.tsx +++ b/src/plugins/presentation_util/public/__stories__/render.tsx @@ -18,6 +18,7 @@ export const defaultHandlers: IInterpreterRenderHandlers = { isSyncColorsEnabled: () => false, isSyncCursorEnabled: () => true, isSyncTooltipsEnabled: () => false, + shouldUseSizeTransitionVeil: () => false, isInteractive: () => true, getExecutionContext: () => undefined, done: action('done'), diff --git a/src/plugins/unified_histogram/public/chart/histogram.tsx b/src/plugins/unified_histogram/public/chart/histogram.tsx index a4071b4ac8cfa..29940af44193c 100644 --- a/src/plugins/unified_histogram/public/chart/histogram.tsx +++ b/src/plugins/unified_histogram/public/chart/histogram.tsx @@ -181,6 +181,8 @@ export function Histogram({ }); const { euiTheme } = useEuiTheme(); + const boxShadow = `0 2px 2px -1px ${euiTheme.colors.mediumShade}, + 0 1px 5px -2px ${euiTheme.colors.mediumShade}`; const chartCss = css` position: relative; flex-grow: 1; @@ -195,6 +197,7 @@ export function Histogram({ & .lnsExpressionRenderer { width: ${chartSize}; margin: auto; + box-shadow: ${attributes.visualizationType === 'lnsMetric' ? boxShadow : 'none'}; } & .echLegend .echLegendList { diff --git a/src/plugins/vis_default_editor/public/components/agg_params_map.ts b/src/plugins/vis_default_editor/public/components/agg_params_map.ts index 7802da7bf9e2f..253d4e581a4f6 100644 --- a/src/plugins/vis_default_editor/public/components/agg_params_map.ts +++ b/src/plugins/vis_default_editor/public/components/agg_params_map.ts @@ -31,6 +31,9 @@ const buckets = { has_extended_bounds: controls.HasExtendedBoundsParamEditor, extended_bounds: controls.ExtendedBoundsParamEditor, }, + [BUCKET_TYPES.IP_PREFIX]: { + ipPrefix: controls.IpPrefixParamEditor, + }, [BUCKET_TYPES.IP_RANGE]: { ipRangeType: controls.IpRangeTypeParamEditor, ranges: controls.IpRangesParamEditor, diff --git a/src/plugins/vis_default_editor/public/components/controls/index.ts b/src/plugins/vis_default_editor/public/components/controls/index.ts index 3d040130b2acd..b1c2672328fc5 100644 --- a/src/plugins/vis_default_editor/public/components/controls/index.ts +++ b/src/plugins/vis_default_editor/public/components/controls/index.ts @@ -13,6 +13,7 @@ export { FieldParamEditor } from './field'; export { FiltersParamEditor } from './filters'; export { HasExtendedBoundsParamEditor } from './has_extended_bounds'; export { IncludeExcludeParamEditor } from './include_exclude'; +export { IpPrefixParamEditor } from './ip_prefix'; export { IpRangesParamEditor } from './ip_ranges'; export { IpRangeTypeParamEditor } from './ip_range_type'; export { MetricAggParamEditor } from './metric_agg'; diff --git a/src/plugins/vis_default_editor/public/components/controls/ip_prefix.tsx b/src/plugins/vis_default_editor/public/components/controls/ip_prefix.tsx new file mode 100644 index 0000000000000..02bd8111fa9af --- /dev/null +++ b/src/plugins/vis_default_editor/public/components/controls/ip_prefix.tsx @@ -0,0 +1,125 @@ +/* + * 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, { ChangeEvent, useCallback } from 'react'; + +import { + EuiFormRow, + EuiFieldNumber, + EuiFieldNumberProps, + EuiFlexGroup, + EuiFlexItem, + EuiSwitch, + EuiSwitchEvent, + EuiSwitchProps, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { AggParamEditorProps } from '../agg_param_props'; +import { useValidation } from './utils'; + +export interface IpPrefix { + prefixLength: number; + isIpv6: boolean; +} + +function isPrefixValid({ prefixLength, isIpv6 }: IpPrefix): boolean { + if (prefixLength < 0) { + return false; + } else if (prefixLength > 32 && !isIpv6) { + return false; + } else if (prefixLength > 128 && isIpv6) { + return false; + } + + return true; +} + +const prefixLengthLabel = i18n.translate('visDefaultEditor.controls.IpPrefix.prefixLength', { + defaultMessage: 'Prefix length', +}); + +const isIpv6Label = i18n.translate('visDefaultEditor.controls.IpPrefix.isIpv6', { + defaultMessage: 'Prefix applies to IPv6 addresses', +}); + +function IpPrefixParamEditor({ + agg, + value = {} as IpPrefix, + setTouched, + setValue, + setValidity, + showValidation, +}: AggParamEditorProps) { + const isValid = isPrefixValid(value); + let error; + + if (!isValid) { + if (!value.isIpv6) { + error = i18n.translate('visDefaultEditor.controls.ipPrefix.errorMessageIpv4', { + defaultMessage: 'Prefix length must be between 0 and 32 for IPv4 addresses.', + }); + } else { + error = i18n.translate('visDefaultEditor.controls.ipPrefix.errorMessageIpv6', { + defaultMessage: 'Prefix length must be between 0 and 128 for IPv6 addresses.', + }); + } + } + + useValidation(setValidity, isValid); + + const onPrefixLengthChange: EuiFieldNumberProps['onChange'] = useCallback( + (ev: ChangeEvent) => { + setValue({ ...value, prefixLength: ev.target.valueAsNumber }); + }, + [setValue, value] + ); + + const onIsIpv6Change: EuiSwitchProps['onChange'] = useCallback( + (ev: EuiSwitchEvent) => { + setValue({ ...value, isIpv6: ev.target.checked }); + }, + [setValue, value] + ); + + return ( + + + + + + + + + + + ); +} + +export { IpPrefixParamEditor }; diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index 7743ca46f95ba..285612700863c 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -40,6 +40,7 @@ import { import type { RenderMode } from '@kbn/expressions-plugin/common'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/public'; import { mapAndFlattenFilters } from '@kbn/data-plugin/public'; +import { isChartSizeEvent } from '@kbn/chart-expressions-common'; import { isFallbackDataView } from '../visualize_app/utils'; import { VisualizationMissedSavedObjectError } from '../components/visualization_missed_saved_object_error'; import VisualizationError from '../components/visualization_error'; @@ -477,6 +478,10 @@ export class VisualizeEmbeddable this.handler.events$ .pipe( mergeMap(async (event) => { + // Visualize doesn't respond to sizing events, so ignore. + if (isChartSizeEvent(event)) { + return; + } if (!this.input.disableTriggers) { const triggerId = get(VIS_EVENT_TO_TRIGGER, event.name, VIS_EVENT_TO_TRIGGER.filter); let context; diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index 813c47ca83872..296367543271a 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -66,6 +66,7 @@ "@kbn/search-response-warnings", "@kbn/logging", "@kbn/content-management-table-list-view-common", + "@kbn/chart-expressions-common", "@kbn/shared-ux-utility" ], "exclude": [ diff --git a/test/functional/apps/discover/group3/_unsaved_changes_badge.ts b/test/functional/apps/discover/group3/_unsaved_changes_badge.ts index c931a11f4f5f4..305298ff2ccc6 100644 --- a/test/functional/apps/discover/group3/_unsaved_changes_badge.ts +++ b/test/functional/apps/discover/group3/_unsaved_changes_badge.ts @@ -11,6 +11,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; const SAVED_SEARCH_NAME = 'test saved search'; const SAVED_SEARCH_WITH_FILTERS_NAME = 'test saved search with filters'; +const SAVED_SEARCH_ESQL = 'test saved search ES|QL'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); @@ -18,6 +19,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const dataGrid = getService('dataGrid'); const filterBar = getService('filterBar'); + const monacoEditor = getService('monacoEditor'); + const browser = getService('browser'); const PageObjects = getPageObjects([ 'settings', 'common', @@ -194,5 +197,32 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await filterBar.isFilterNegated('bytes')).to.be(false); expect(await PageObjects.discover.getHitCount()).to.be('1,373'); }); + + it('should not show a badge after loading an ES|QL saved search, only after changes', async () => { + await PageObjects.discover.selectTextBaseLang(); + + await monacoEditor.setCodeEditorValue('from logstash-* | limit 10'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await PageObjects.discover.saveSearch(SAVED_SEARCH_ESQL); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await testSubjects.missingOrFail('unsavedChangesBadge'); + + await browser.refresh(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await testSubjects.missingOrFail('unsavedChangesBadge'); + + await monacoEditor.setCodeEditorValue('from logstash-* | limit 100'); + await testSubjects.click('querySubmitButton'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.discover.waitUntilSearchingHasFinished(); + + await testSubjects.existOrFail('unsavedChangesBadge'); + }); }); } diff --git a/x-pack/packages/ml/in_memory_table/hooks/use_table_state.ts b/x-pack/packages/ml/in_memory_table/hooks/use_table_state.ts index 726c3eb0dd268..74c8a54b69c57 100644 --- a/x-pack/packages/ml/in_memory_table/hooks/use_table_state.ts +++ b/x-pack/packages/ml/in_memory_table/hooks/use_table_state.ts @@ -39,10 +39,11 @@ export interface UseTableState { export function useTableState( items: T[], initialSortField: string, - initialSortDirection: 'asc' | 'desc' = 'asc' + initialSortDirection: 'asc' | 'desc' = 'asc', + initialPagionation?: Partial ) { - const [pageIndex, setPageIndex] = useState(0); - const [pageSize, setPageSize] = useState(10); + const [pageIndex, setPageIndex] = useState(initialPagionation?.pageIndex ?? 0); + const [pageSize, setPageSize] = useState(initialPagionation?.pageSize ?? 10); const [sortField, setSortField] = useState(initialSortField); const [sortDirection, setSortDirection] = useState(initialSortDirection); @@ -63,7 +64,7 @@ export function useTableState( pageIndex, pageSize, totalItemCount: (items ?? []).length, - pageSizeOptions: [10, 20, 50], + pageSizeOptions: initialPagionation?.pageSizeOptions ?? [10, 20, 50], showPerPageOptions: true, }; diff --git a/x-pack/performance/journeys/infra_hosts_view.ts b/x-pack/performance/journeys/infra_hosts_view.ts new file mode 100644 index 0000000000000..b936cc7c1719c --- /dev/null +++ b/x-pack/performance/journeys/infra_hosts_view.ts @@ -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 { Journey } from '@kbn/journeys'; +import { + createLogger, + InfraSynthtraceEsClient, + LogLevel, + InfraSynthtraceKibanaClient, +} from '@kbn/apm-synthtrace'; +import { infra, timerange } from '@kbn/apm-synthtrace-client'; +import { subj } from '@kbn/test-subj-selector'; + +export const journey = new Journey({ + beforeSteps: async ({ kbnUrl, auth, es }) => { + const logger = createLogger(LogLevel.debug); + const synthKibanaClient = new InfraSynthtraceKibanaClient({ + logger, + target: kbnUrl.get(), + username: auth.getUsername(), + password: auth.getPassword(), + }); + + const pkgVersion = await synthKibanaClient.fetchLatestSystemPackageVersion(); + await synthKibanaClient.installSystemPackage(pkgVersion); + + const synthEsClient = new InfraSynthtraceEsClient({ + logger, + client: es, + refreshAfterIndex: true, + }); + + const start = Date.now() - 1000 * 60 * 10; + await synthEsClient.index( + generateHostsData({ + from: new Date(start).toISOString(), + to: new Date().toISOString(), + count: 1000, + }) + ); + }, +}).step('Navigate to Hosts view and load 500 hosts', async ({ page, kbnUrl, kibanaPage }) => { + await page.goto( + kbnUrl.get( + `app/metrics/hosts?_a=(dateRange:(from:now-15m,to:now),filters:!(),limit:500,panelFilters:!(),query:(language:kuery,query:''))` + ) + ); + // wait for table to be loaded + await page.waitForSelector(subj('hostsView-table-loaded')); + // wait for metric charts to be loaded + await kibanaPage.waitForCharts({ count: 5, timeout: 60000 }); +}); + +export function generateHostsData({ + from, + to, + count = 1, +}: { + from: string; + to: string; + count: number; +}) { + const range = timerange(from, to); + + const hosts = Array(count) + .fill(0) + .map((_, idx) => infra.host(`my-host-${idx}`)); + + return range + .interval('30s') + .rate(1) + .generator((timestamp, index) => + hosts.flatMap((host) => [ + host.cpu().timestamp(timestamp), + host.memory().timestamp(timestamp), + host.network().timestamp(timestamp), + host.load().timestamp(timestamp), + host.filesystem().timestamp(timestamp), + host.diskio().timestamp(timestamp), + ]) + ); +} diff --git a/x-pack/plugins/aiops/common/constants.ts b/x-pack/plugins/aiops/common/constants.ts index 5916464e90980..334bb64dd2484 100644 --- a/x-pack/plugins/aiops/common/constants.ts +++ b/x-pack/plugins/aiops/common/constants.ts @@ -26,9 +26,19 @@ export const CASES_ATTACHMENT_CHANGE_POINT_CHART = 'aiopsChangePointChart'; export const EMBEDDABLE_CHANGE_POINT_CHART_TYPE = 'aiopsChangePointChart' as const; +export type EmbeddableChangePointType = typeof EMBEDDABLE_CHANGE_POINT_CHART_TYPE; + export const AIOPS_TELEMETRY_ID = { AIOPS_DEFAULT_SOURCE: 'ml_aiops_labs', AIOPS_ANALYSIS_RUN_ORIGIN: 'aiops-analysis-run-origin', } as const; export const EMBEDDABLE_ORIGIN = 'embeddable'; + +export const CHANGE_POINT_DETECTION_VIEW_TYPE = { + CHARTS: 'charts', + TABLE: 'table', +} as const; + +export type ChangePointDetectionViewType = + typeof CHANGE_POINT_DETECTION_VIEW_TYPE[keyof typeof CHANGE_POINT_DETECTION_VIEW_TYPE]; diff --git a/x-pack/plugins/aiops/public/cases/change_point_charts_attachment.tsx b/x-pack/plugins/aiops/public/cases/change_point_charts_attachment.tsx index 4aa830328e805..c5b88bc7e92cd 100644 --- a/x-pack/plugins/aiops/public/cases/change_point_charts_attachment.tsx +++ b/x-pack/plugins/aiops/public/cases/change_point_charts_attachment.tsx @@ -45,7 +45,7 @@ export const initComponent = memoize( return ( <> - + ); }, diff --git a/x-pack/plugins/aiops/public/cases/register_change_point_charts_attachment.tsx b/x-pack/plugins/aiops/public/cases/register_change_point_charts_attachment.tsx index cc70d7ff98a3b..d91a50ab13d36 100644 --- a/x-pack/plugins/aiops/public/cases/register_change_point_charts_attachment.tsx +++ b/x-pack/plugins/aiops/public/cases/register_change_point_charts_attachment.tsx @@ -10,7 +10,10 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { CasesUiSetup } from '@kbn/cases-plugin/public'; import type { CoreStart } from '@kbn/core/public'; -import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '../../common/constants'; +import { + CASES_ATTACHMENT_CHANGE_POINT_CHART, + EMBEDDABLE_CHANGE_POINT_CHART_TYPE, +} from '../../common/constants'; import { getEmbeddableChangePointChart } from '../embeddable/embeddable_change_point_chart_component'; import { AiopsPluginStartDeps } from '../types'; @@ -19,7 +22,11 @@ export function registerChangePointChartsAttachment( coreStart: CoreStart, pluginStart: AiopsPluginStartDeps ) { - const EmbeddableComponent = getEmbeddableChangePointChart(coreStart, pluginStart); + const EmbeddableComponent = getEmbeddableChangePointChart( + EMBEDDABLE_CHANGE_POINT_CHART_TYPE, + coreStart, + pluginStart + ); cases.attachmentFramework.registerPersistableState({ id: CASES_ATTACHMENT_CHANGE_POINT_CHART, diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/change_points_table.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/change_points_table.tsx index 84c5723548ee2..6abf5102a37ca 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/change_points_table.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/change_points_table.tsx @@ -7,35 +7,37 @@ import { EuiBadge, - type EuiBasicTableColumn, EuiEmptyPrompt, EuiIcon, EuiInMemoryTable, EuiToolTip, type DefaultItemAction, + type EuiBasicTableColumn, } from '@elastic/eui'; -import React, { type FC, useMemo } from 'react'; +import { EuiTableSelectionType } from '@elastic/eui/src/components/basic_table/table_types'; +import { FilterStateStore, type Filter } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiTableSelectionType } from '@elastic/eui/src/components/basic_table/table_types'; -import { type Filter, FilterStateStore } from '@kbn/es-query'; -import { NoChangePointsWarning } from './no_change_points_warning'; +import { useTableState } from '@kbn/ml-in-memory-table'; +import React, { useCallback, useEffect, useMemo, useRef, type FC } from 'react'; +import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { useDataSource } from '../../hooks/use_data_source'; -import { useCommonChartProps } from './use_common_chart_props'; import { - type ChangePointAnnotation, FieldConfig, SelectedChangePoint, useChangePointDetectionContext, + type ChangePointAnnotation, } from './change_point_detection_context'; import { type ChartComponentProps } from './chart_component'; -import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; +import { NoChangePointsWarning } from './no_change_points_warning'; +import { useCommonChartProps } from './use_common_chart_props'; export interface ChangePointsTableProps { annotations: ChangePointAnnotation[]; fieldConfig: FieldConfig; isLoading: boolean; - onSelectionChange: (update: SelectedChangePoint[]) => void; + onSelectionChange?: (update: SelectedChangePoint[]) => void; + onRenderComplete?: () => void; } function getFilterConfig( @@ -68,31 +70,62 @@ function getFilterConfig( }; } +const pageSizeOptions = [5, 10, 15]; + export const ChangePointsTable: FC = ({ isLoading, annotations, fieldConfig, onSelectionChange, + onRenderComplete, }) => { const { fieldFormats, data: { query: { filterManager }, }, + embeddingOrigin, } = useAiopsAppContext(); const { dataView } = useDataSource(); + const chartLoadingCount = useRef(0); + + const { onTableChange, pagination, sorting } = useTableState( + annotations ?? [], + 'p_value', + 'asc', + { + pageIndex: 0, + pageSize: 10, + pageSizeOptions, + } + ); + const dateFormatter = useMemo(() => fieldFormats.deserialize({ id: 'date' }), [fieldFormats]); - const defaultSorting = { - sort: { - field: 'p_value', - // Lower p_value indicates a bigger change point, hence the asc sorting - direction: 'asc' as const, + useEffect(() => { + // Reset loading counter on pagination or sort change + chartLoadingCount.current = 0; + }, [pagination.pageIndex, pagination.pageSize, sorting.sort]); + + /** + * Callback to track render of each chart component + * to report when all charts on the current page are ready. + */ + const onChartRenderCompleteCallback = useCallback( + (isLoadingChart: boolean) => { + if (!onRenderComplete) return; + if (!isLoadingChart) { + chartLoadingCount.current++; + } + if (chartLoadingCount.current === pagination.pageSize) { + onRenderComplete(); + } }, - }; + [onRenderComplete, pagination.pageSize] + ); - const hasActions = fieldConfig.splitField !== undefined; + const hasActions = fieldConfig.splitField !== undefined && embeddingOrigin !== 'cases'; const { bucketInterval } = useChangePointDetectionContext(); @@ -131,6 +164,7 @@ export const ChangePointsTable: FC = ({ annotation={annotation} fieldConfig={fieldConfig} interval={bucketInterval.expression} + onRenderComplete={onChartRenderCompleteCallback.bind(null, false)} /> ); }, @@ -190,70 +224,83 @@ export const ChangePointsTable: FC = ({ truncateText: false, sortable: true, }, - { - name: i18n.translate('xpack.aiops.changePointDetection.actionsColumn', { - defaultMessage: 'Actions', - }), - actions: [ - { - name: i18n.translate( - 'xpack.aiops.changePointDetection.actions.filterForValueAction', - { - defaultMessage: 'Filter for value', - } - ), - description: i18n.translate( - 'xpack.aiops.changePointDetection.actions.filterForValueAction', - { - defaultMessage: 'Filter for value', - } - ), - icon: 'plusInCircle', - color: 'primary', - type: 'icon', - onClick: (item) => { - filterManager.addFilters( - getFilterConfig(dataView.id!, item as Required, false)! - ); - }, - isPrimary: true, - 'data-test-subj': 'aiopsChangePointFilterForValue', - }, - { - name: i18n.translate( - 'xpack.aiops.changePointDetection.actions.filterOutValueAction', - { - defaultMessage: 'Filter out value', - } - ), - description: i18n.translate( - 'xpack.aiops.changePointDetection.actions.filterOutValueAction', - { - defaultMessage: 'Filter out value', - } - ), - icon: 'minusInCircle', - color: 'primary', - type: 'icon', - onClick: (item) => { - filterManager.addFilters( - getFilterConfig(dataView.id!, item as Required, true)! - ); + ...(hasActions + ? [ + { + name: i18n.translate('xpack.aiops.changePointDetection.actionsColumn', { + defaultMessage: 'Actions', + }), + actions: [ + { + name: i18n.translate( + 'xpack.aiops.changePointDetection.actions.filterForValueAction', + { + defaultMessage: 'Filter for value', + } + ), + description: i18n.translate( + 'xpack.aiops.changePointDetection.actions.filterForValueAction', + { + defaultMessage: 'Filter for value', + } + ), + icon: 'plusInCircle', + color: 'primary', + type: 'icon', + onClick: (item) => { + filterManager.addFilters( + getFilterConfig( + dataView.id!, + item as Required, + false + )! + ); + }, + isPrimary: true, + 'data-test-subj': 'aiopsChangePointFilterForValue', + }, + { + name: i18n.translate( + 'xpack.aiops.changePointDetection.actions.filterOutValueAction', + { + defaultMessage: 'Filter out value', + } + ), + description: i18n.translate( + 'xpack.aiops.changePointDetection.actions.filterOutValueAction', + { + defaultMessage: 'Filter out value', + } + ), + icon: 'minusInCircle', + color: 'primary', + type: 'icon', + onClick: (item) => { + filterManager.addFilters( + getFilterConfig( + dataView.id!, + item as Required, + true + )! + ); + }, + isPrimary: true, + 'data-test-subj': 'aiopsChangePointFilterOutValue', + }, + ] as Array>, }, - isPrimary: true, - 'data-test-subj': 'aiopsChangePointFilterOutValue', - }, - ] as Array>, - }, + ] + : []), ] : []), ]; - const selectionValue = useMemo>(() => { + const selectionValue = useMemo | undefined>(() => { + if (!onSelectionChange) return; return { selectable: (item) => true, onSelectionChange: (selection) => { - onSelectionChange( + onSelectionChange!( selection.map((s) => { return { ...s, @@ -273,8 +320,11 @@ export const ChangePointsTable: FC = ({ data-test-subj={`aiopsChangePointResultsTable ${isLoading ? 'loading' : 'loaded'}`} items={annotations} columns={columns} - pagination={{ pageSizeOptions: [5, 10, 15] }} - sorting={defaultSorting} + pagination={ + pagination.pageSizeOptions![0] > pagination!.totalItemCount ? undefined : pagination + } + sorting={sorting} + onTableChange={onTableChange} hasActions={hasActions} rowProps={(item) => ({ 'data-test-subj': `aiopsChangePointResultsTableRow row-${item.id}`, @@ -300,7 +350,12 @@ export const ChangePointsTable: FC = ({ ); }; -export const MiniChartPreview: FC = ({ fieldConfig, annotation }) => { +export const MiniChartPreview: FC = ({ + fieldConfig, + annotation, + onRenderComplete, + onLoading, +}) => { const { lens: { EmbeddableComponent }, } = useAiopsAppContext(); @@ -314,8 +369,31 @@ export const MiniChartPreview: FC = ({ fieldConfig, annotat bucketInterval: bucketInterval.expression, }); + const chartWrapperRef = useRef(null); + + const renderCompleteListener = useCallback( + (event: Event) => { + if (event.target === chartWrapperRef.current) return; + if (onRenderComplete) { + onRenderComplete(); + } + }, + [onRenderComplete] + ); + + useEffect(() => { + if (!chartWrapperRef.current) { + throw new Error('Reference to the chart wrapper is not set'); + } + const chartWrapper = chartWrapperRef.current; + chartWrapper.addEventListener('renderComplete', renderCompleteListener); + return () => { + chartWrapper.removeEventListener('renderComplete', renderCompleteListener); + }; + }, [renderCompleteListener]); + return ( -
+
= ({ fieldConfig, annotat type: 'aiops_change_point_detection_chart', name: 'Change point detection', }} + onLoad={onLoading} />
); diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx index 7429ad7ba9f0a..3a6a00624b719 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/fields_config.tsx @@ -33,7 +33,11 @@ import { import { EuiContextMenuProps } from '@elastic/eui/src/components/context_menu/context_menu'; import { isDefined } from '@kbn/ml-is-defined'; import { MaxSeriesControl } from './max_series_control'; -import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../../common/constants'; +import { + ChangePointDetectionViewType, + CHANGE_POINT_DETECTION_VIEW_TYPE, + EMBEDDABLE_CHANGE_POINT_CHART_TYPE, +} from '../../../common/constants'; import { useCasesModal } from '../../hooks/use_cases_modal'; import { type EmbeddableChangePointChartInput } from '../../embeddable/embeddable_change_point_chart'; import { useDataSource } from '../../hooks/use_data_source'; @@ -51,6 +55,7 @@ import { } from './change_point_detection_context'; import { useChangePointResults } from './use_change_point_agg_request'; import { useSplitFieldCardinality } from './use_split_field_cardinality'; +import { ViewTypeSelector } from './view_type_selector'; const selectControlCss = { width: '350px' }; @@ -191,10 +196,17 @@ const FieldPanel: FC = ({ const [dashboardAttachment, setDashboardAttachment] = useState<{ applyTimeRange: boolean; maxSeriesToPlot: number; + viewType: ChangePointDetectionViewType; }>({ applyTimeRange: false, maxSeriesToPlot: 6, + viewType: CHANGE_POINT_DETECTION_VIEW_TYPE.CHARTS, }); + + const [caseAttachment, setCaseAttachment] = useState<{ + viewType: ChangePointDetectionViewType; + }>({ viewType: CHANGE_POINT_DETECTION_VIEW_TYPE.CHARTS }); + const [dashboardAttachmentReady, setDashboardAttachmentReady] = useState(false); const { @@ -294,20 +306,7 @@ const FieldPanel: FC = ({ } : {}), 'data-test-subj': 'aiopsChangePointDetectionAttachToCaseButton', - onClick: () => { - openCasesModalCallback({ - timeRange, - fn: fieldConfig.fn, - metricField: fieldConfig.metricField, - dataViewId: dataView.id, - ...(fieldConfig.splitField - ? { - splitField: fieldConfig.splitField, - partitions: selectedPartitions, - } - : {}), - }); - }, + panel: 'attachToCasePanel', }, ] : []), @@ -324,6 +323,17 @@ const FieldPanel: FC = ({ + { + setDashboardAttachment((prevState) => { + return { + ...prevState, + viewType: v, + }; + }); + }} + /> = ({ fill type={'submit'} fullWidth - onClick={setDashboardAttachmentReady.bind(null, true)} + onClick={() => { + setIsActionMenuOpen(false); + setDashboardAttachmentReady(true); + }} + disabled={!isDashboardFormValid} + > + + + + + ), + }, + { + id: 'attachToCasePanel', + title: i18n.translate('xpack.aiops.changePointDetection.attachToCaseTitle', { + defaultMessage: 'Attach to case', + }), + size: 's', + content: ( + + + + { + setCaseAttachment((prevState) => { + return { + ...prevState, + viewType: v, + }; + }); + }} + /> + { + setIsActionMenuOpen(false); + openCasesModalCallback({ + timeRange, + viewType: caseAttachment.viewType, + fn: fieldConfig.fn, + metricField: fieldConfig.metricField, + dataViewId: dataView.id, + ...(fieldConfig.splitField + ? { + splitField: fieldConfig.splitField, + partitions: selectedPartitions, + } + : {}), + }); + }} disabled={!isDashboardFormValid} > = ({ canCreateCase, canEditDashboards, canUpdateCase, + caseAttachment.viewType, caseAttachmentButtonDisabled, dashboardAttachment.applyTimeRange, dashboardAttachment.maxSeriesToPlot, + dashboardAttachment.viewType, dataView.id, fieldConfig.fn, fieldConfig.metricField, @@ -405,6 +473,7 @@ const FieldPanel: FC = ({ const embeddableInput: Partial = { title: newTitle, description: newDescription, + viewType: dashboardAttachment.viewType, dataViewId: dataView.id, metricField: fieldConfig.metricField, splitField: fieldConfig.splitField, @@ -428,12 +497,13 @@ const FieldPanel: FC = ({ }, [ embeddable, + dashboardAttachment.viewType, + dashboardAttachment.applyTimeRange, + dashboardAttachment.maxSeriesToPlot, dataView.id, fieldConfig.metricField, fieldConfig.splitField, fieldConfig.fn, - dashboardAttachment.applyTimeRange, - dashboardAttachment.maxSeriesToPlot, timeRange, selectedChangePoints, panelIndex, diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx index 4363de30ce162..79b6930e7e50a 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/partitions_selector.tsx @@ -6,7 +6,14 @@ */ import React, { type FC, useState, useCallback, useMemo, useEffect } from 'react'; -import { EuiComboBox, EuiFormRow } from '@elastic/eui'; +import { + EuiComboBox, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIcon, + EuiToolTip, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { type SearchRequest } from '@elastic/elasticsearch/lib/api/types'; import { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types'; @@ -171,9 +178,26 @@ export const PartitionsSelector: FC = ({ return ( + + {i18n.translate('xpack.aiops.changePointDetection.partitionsLabel', { + defaultMessage: 'Partitions', + })} + + + + + + + + } > isLoading={isLoading} diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/use_change_point_agg_request.ts b/x-pack/plugins/aiops/public/components/change_point_detection/use_change_point_agg_request.ts index 0393ab5e5a6fc..b8e43511c8c58 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/use_change_point_agg_request.ts +++ b/x-pack/plugins/aiops/public/components/change_point_detection/use_change_point_agg_request.ts @@ -136,7 +136,7 @@ export function useChangePointResults( /** * null also means the fetching has been complete */ - const [progress, setProgress] = useState(null); + const [progress, setProgress] = useState(0); const isSingleMetric = !isDefined(fieldConfig.splitField); diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/view_type_selector.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/view_type_selector.tsx new file mode 100644 index 0000000000000..1182a56fbe9d4 --- /dev/null +++ b/x-pack/plugins/aiops/public/components/change_point_detection/view_type_selector.tsx @@ -0,0 +1,59 @@ +/* + * 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, { FC } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiButtonGroup, EuiFormRow, type EuiButtonGroupOptionProps } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ChangePointDetectionViewType } from '../../../common/constants'; + +const viewTypeOptions: EuiButtonGroupOptionProps[] = [ + { + id: `charts`, + label: ( + + ), + iconType: 'visLine', + }, + { + id: `table`, + label: ( + + ), + iconType: 'visTable', + }, +]; + +export interface ViewTypeSelectorProps { + value: ChangePointDetectionViewType; + onChange: (update: ChangePointDetectionViewType) => void; +} + +export const ViewTypeSelector: FC = ({ value, onChange }) => { + return ( + + void} + /> + + ); +}; diff --git a/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx b/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx index 71780f26a4fcb..83ee5c65b082d 100644 --- a/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx +++ b/x-pack/plugins/aiops/public/embeddable/change_point_chart_initializer.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { EuiButton, EuiButtonEmpty, @@ -18,28 +17,30 @@ import { EuiModalHeader, EuiModalHeaderTitle, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; +import { ES_FIELD_TYPES } from '@kbn/field-types'; import { i18n } from '@kbn/i18n'; -import usePrevious from 'react-use/lib/usePrevious'; -import { pick } from 'lodash'; +import { FormattedMessage } from '@kbn/i18n-react'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { ES_FIELD_TYPES } from '@kbn/field-types'; -import { PartitionsSelector } from '../components/change_point_detection/partitions_selector'; -import { DEFAULT_SERIES } from './const'; -import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart_component'; -import { type EmbeddableChangePointChartExplicitInput } from './types'; -import { MaxSeriesControl } from '../components/change_point_detection/max_series_control'; -import { SplitFieldSelector } from '../components/change_point_detection/split_field_selector'; -import { MetricFieldSelector } from '../components/change_point_detection/metric_field_selector'; +import { pick } from 'lodash'; +import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import usePrevious from 'react-use/lib/usePrevious'; import { ChangePointDetectionControlsContextProvider, useChangePointDetectionControlsContext, } from '../components/change_point_detection/change_point_detection_context'; -import { useAiopsAppContext } from '../hooks/use_aiops_app_context'; -import { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; +import { DEFAULT_AGG_FUNCTION } from '../components/change_point_detection/constants'; import { FunctionPicker } from '../components/change_point_detection/function_picker'; +import { MaxSeriesControl } from '../components/change_point_detection/max_series_control'; +import { MetricFieldSelector } from '../components/change_point_detection/metric_field_selector'; +import { PartitionsSelector } from '../components/change_point_detection/partitions_selector'; +import { SplitFieldSelector } from '../components/change_point_detection/split_field_selector'; +import { ViewTypeSelector } from '../components/change_point_detection/view_type_selector'; +import { useAiopsAppContext } from '../hooks/use_aiops_app_context'; import { DataSourceContextProvider } from '../hooks/use_data_source'; -import { DEFAULT_AGG_FUNCTION } from '../components/change_point_detection/constants'; +import { DEFAULT_SERIES } from './const'; +import { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; +import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart_component'; +import { type EmbeddableChangePointChartExplicitInput } from './types'; export interface AnomalyChartsInitializerProps { initialInput?: Partial; @@ -59,6 +60,7 @@ export const ChangePointChartInitializer: FC = ({ } = useAiopsAppContext(); const [dataViewId, setDataViewId] = useState(initialInput?.dataViewId ?? ''); + const [viewType, setViewType] = useState(initialInput?.viewType ?? 'charts'); const [formInput, setFormInput] = useState( pick(initialInput ?? {}, [ @@ -75,6 +77,7 @@ export const ChangePointChartInitializer: FC = ({ const updatedProps = useMemo(() => { return { ...formInput, + viewType, title: isPopulatedObject(formInput) ? i18n.translate('xpack.aiops.changePointDetection.attachmentTitle', { defaultMessage: 'Change point: {function}({metric}){splitBy}', @@ -92,7 +95,7 @@ export const ChangePointChartInitializer: FC = ({ : '', dataViewId, }; - }, [formInput, dataViewId]); + }, [formInput, dataViewId, viewType]); return ( @@ -100,13 +103,14 @@ export const ChangePointChartInitializer: FC = ({ + = ({ }} /> - diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx index 3422d980f5fd8..42fffe5edaac1 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart.tsx @@ -23,8 +23,9 @@ import { LensPublicStart } from '@kbn/lens-plugin/public'; import { Subject } from 'rxjs'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/common'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { EmbeddableInputTracker } from './embeddable_chart_component_wrapper'; -import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE, EMBEDDABLE_ORIGIN } from '../../common/constants'; +import { EMBEDDABLE_ORIGIN, EmbeddableChangePointType } from '../../common/constants'; import { AiopsAppContext, type AiopsAppDependencies } from '../hooks/use_aiops_app_context'; import { EmbeddableChangePointChartProps } from './embeddable_change_point_chart_component'; @@ -42,6 +43,7 @@ export interface EmbeddableChangePointChartDeps { i18n: CoreStart['i18n']; lens: LensPublicStart; usageCollection: UsageCollectionSetup; + fieldFormats: FieldFormatsStart; } export type IEmbeddableChangePointChart = typeof EmbeddableChangePointChart; @@ -50,8 +52,6 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable< EmbeddableChangePointChartInput, EmbeddableChangePointChartOutput > { - public readonly type = EMBEDDABLE_CHANGE_POINT_CHART_TYPE; - private reload$ = new Subject(); public reload(): void { @@ -64,6 +64,7 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable< deferEmbeddableLoad = true; constructor( + public readonly type: EmbeddableChangePointType, private readonly deps: EmbeddableChangePointChartDeps, initialInput: EmbeddableChangePointChartInput, parent?: IContainer @@ -91,9 +92,9 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable< return true; } - public onLoading() { + public onLoading(isLoading: boolean) { this.renderComplete.dispatchInProgress(); - this.updateOutput({ loading: true, error: undefined }); + this.updateOutput({ loading: isLoading, error: undefined }); } public onError(error: Error) { @@ -103,7 +104,7 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable< public onRenderComplete() { this.renderComplete.dispatchComplete(); - this.updateOutput({ loading: false, error: undefined }); + this.updateOutput({ loading: false, rendered: true, error: undefined }); } render(el: HTMLElement): void { @@ -127,8 +128,8 @@ export class EmbeddableChangePointChart extends AbstractEmbeddable< const input$ = this.getInput$(); const aiopsAppContextValue = { + embeddingOrigin: this.parent?.type ?? input.embeddingOrigin ?? EMBEDDABLE_ORIGIN, ...this.deps, - embeddingOrigin: this.parent?.type ?? EMBEDDABLE_ORIGIN, } as unknown as AiopsAppDependencies; ReactDOM.render( diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx index 38a75ca327c95..9ce286fddf94c 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_component.tsx @@ -15,12 +15,16 @@ import { useEmbeddableFactory, } from '@kbn/embeddable-plugin/public'; import { EuiLoadingChart } from '@elastic/eui'; -import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../common/constants'; +import { + type ChangePointDetectionViewType, + type EmbeddableChangePointType, +} from '../../common/constants'; import type { AiopsPluginStartDeps } from '../types'; import type { EmbeddableChangePointChartInput } from './embeddable_change_point_chart'; import type { ChangePointAnnotation } from '../components/change_point_detection/change_point_detection_context'; export interface EmbeddableChangePointChartProps { + viewType?: ChangePointDetectionViewType; dataViewId: string; timeRange: TimeRange; fn: 'avg' | 'sum' | 'min' | 'max' | string; @@ -40,12 +44,16 @@ export interface EmbeddableChangePointChartProps { * Last reload request time, can be used for manual reload */ lastReloadRequestTime?: number; + /** Origin of the embeddable instance */ + embeddingOrigin?: string; } -export function getEmbeddableChangePointChart(core: CoreStart, plugins: AiopsPluginStartDeps) { +export function getEmbeddableChangePointChart( + visType: EmbeddableChangePointType, + core: CoreStart, + plugins: AiopsPluginStartDeps +) { const { embeddable: embeddableStart } = plugins; - const factory = embeddableStart.getEmbeddableFactory( - EMBEDDABLE_CHANGE_POINT_CHART_TYPE - )!; + const factory = embeddableStart.getEmbeddableFactory(visType)!; return (props: EmbeddableChangePointChartProps) => { const input = { ...props }; diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts index ef7c3a431cc18..8dfc6e28ac760 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_change_point_chart_factory.ts @@ -13,7 +13,10 @@ import { import { i18n } from '@kbn/i18n'; import { type DataPublicPluginStart } from '@kbn/data-plugin/public'; import { StartServicesAccessor } from '@kbn/core-lifecycle-browser'; -import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../common/constants'; +import { + EMBEDDABLE_CHANGE_POINT_CHART_TYPE, + EmbeddableChangePointType, +} from '../../common/constants'; import type { AiopsPluginStart, AiopsPluginStartDeps } from '../types'; import { EmbeddableChangePointChart, @@ -27,8 +30,6 @@ export interface EmbeddableChangePointChartStartServices { export type EmbeddableChangePointChartType = typeof EMBEDDABLE_CHANGE_POINT_CHART_TYPE; export class EmbeddableChangePointChartFactory implements EmbeddableFactoryDefinition { - public readonly type = EMBEDDABLE_CHANGE_POINT_CHART_TYPE; - public readonly grouping = [ { id: 'ml', @@ -41,6 +42,8 @@ export class EmbeddableChangePointChartFactory implements EmbeddableFactoryDefin ]; constructor( + public readonly type: EmbeddableChangePointType, + private readonly name: string, private readonly getStartServices: StartServicesAccessor ) {} @@ -49,9 +52,7 @@ export class EmbeddableChangePointChartFactory implements EmbeddableFactoryDefin }; getDisplayName() { - return i18n.translate('xpack.aiops.embeddableChangePointChartDisplayName', { - defaultMessage: 'Change point detection', - }); + return this.name; } canCreateNew() { @@ -73,10 +74,11 @@ export class EmbeddableChangePointChartFactory implements EmbeddableFactoryDefin try { const [ { i18n: i18nService, theme, http, uiSettings, notifications }, - { lens, data, usageCollection }, + { lens, data, usageCollection, fieldFormats }, ] = await this.getStartServices(); return new EmbeddableChangePointChart( + this.type, { theme, http, @@ -86,6 +88,7 @@ export class EmbeddableChangePointChartFactory implements EmbeddableFactoryDefin notifications, lens, usageCollection, + fieldFormats, }, input, parent diff --git a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx index 0392f28184b8b..0cb49eb4ccf39 100644 --- a/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx +++ b/x-pack/plugins/aiops/public/embeddable/embeddable_chart_component_wrapper.tsx @@ -5,12 +5,14 @@ * 2.0. */ -import { BehaviorSubject, type Observable, combineLatest } from 'rxjs'; -import { map, distinctUntilChanged } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest, type Observable } from 'rxjs'; +import { distinctUntilChanged, map } from 'rxjs/operators'; import React, { FC, useEffect, useMemo, useState } from 'react'; import { useTimefilter } from '@kbn/ml-date-picker'; import { css } from '@emotion/react'; import useObservable from 'react-use/lib/useObservable'; +import { ChangePointsTable } from '../components/change_point_detection/change_points_table'; +import { CHANGE_POINT_DETECTION_VIEW_TYPE } from '../../common/constants'; import { ReloadContextProvider } from '../hooks/use_reload'; import { type ChangePointAnnotation, @@ -42,7 +44,7 @@ export interface EmbeddableInputTrackerProps { reload$: Observable; onOutputChange: (output: Partial) => void; onRenderComplete: () => void; - onLoading: () => void; + onLoading: (isLoading: boolean) => void; onError: (error: Error) => void; } @@ -86,6 +88,7 @@ export const EmbeddableInputTracker: FC = ({ = ({ export const ChartGridEmbeddableWrapper: FC< EmbeddableChangePointChartProps & { onRenderComplete: () => void; - onLoading: () => void; + onLoading: (isLoading: boolean) => void; onError: (error: Error) => void; } > = ({ + viewType = CHANGE_POINT_DETECTION_VIEW_TYPE.CHARTS, fn, metricField, maxSeriesToPlot, @@ -202,9 +206,7 @@ export const ChartGridEmbeddableWrapper: FC< ); useEffect(() => { - if (isLoading) { - onLoading(); - } + onLoading(isLoading); }, [onLoading, isLoading]); const changePoints = useMemo(() => { @@ -235,16 +237,27 @@ export const ChartGridEmbeddableWrapper: FC< `} > {changePoints.length > 0 ? ( - ({ ...r, ...fieldConfig }))} - interval={requestParams.interval} - onRenderComplete={onRenderComplete} - /> - ) : emptyState ? ( - emptyState - ) : ( - - )} + viewType === CHANGE_POINT_DETECTION_VIEW_TYPE.CHARTS ? ( + ({ ...r, ...fieldConfig }))} + interval={requestParams.interval} + onRenderComplete={onRenderComplete} + /> + ) : viewType === CHANGE_POINT_DETECTION_VIEW_TYPE.TABLE ? ( + + ) : null + ) : !isLoading ? ( + emptyState ? ( + emptyState + ) : ( + + ) + ) : null}
); }; diff --git a/x-pack/plugins/aiops/public/embeddable/register_embeddable.ts b/x-pack/plugins/aiops/public/embeddable/register_embeddable.ts index e3a3f31e757a0..219b628552557 100644 --- a/x-pack/plugins/aiops/public/embeddable/register_embeddable.ts +++ b/x-pack/plugins/aiops/public/embeddable/register_embeddable.ts @@ -7,6 +7,8 @@ import type { CoreSetup } from '@kbn/core-lifecycle-browser'; import type { EmbeddableSetup } from '@kbn/embeddable-plugin/public'; +import { i18n } from '@kbn/i18n'; +import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../../common/constants'; import type { AiopsPluginStart, AiopsPluginStartDeps } from '../types'; import { EmbeddableChangePointChartFactory } from './embeddable_change_point_chart_factory'; @@ -14,6 +16,12 @@ export const registerEmbeddable = ( core: CoreSetup, embeddable: EmbeddableSetup ) => { - const factory = new EmbeddableChangePointChartFactory(core.getStartServices); - embeddable.registerEmbeddableFactory(factory.type, factory); + const changePointChartFactory = new EmbeddableChangePointChartFactory( + EMBEDDABLE_CHANGE_POINT_CHART_TYPE, + i18n.translate('xpack.aiops.embeddableChangePointChartDisplayName', { + defaultMessage: 'Change point detection', + }), + core.getStartServices + ); + embeddable.registerEmbeddableFactory(changePointChartFactory.type, changePointChartFactory); }; diff --git a/x-pack/plugins/aiops/public/embeddable/types.ts b/x-pack/plugins/aiops/public/embeddable/types.ts index 0184c2e4fa3eb..aa4ae65dbc5a9 100644 --- a/x-pack/plugins/aiops/public/embeddable/types.ts +++ b/x-pack/plugins/aiops/public/embeddable/types.ts @@ -5,7 +5,9 @@ * 2.0. */ +import type { FC } from 'react'; import { IEmbeddable } from '@kbn/embeddable-plugin/public'; +import type { SelectedChangePoint } from '../components/change_point_detection/change_point_detection_context'; import { EmbeddableChangePointChartInput, EmbeddableChangePointChartOutput, @@ -19,3 +21,9 @@ export type EmbeddableChangePointChartExplicitInput = { export interface EditChangePointChartsPanelContext { embeddable: IEmbeddable; } + +export type ViewComponent = FC<{ + changePoints: SelectedChangePoint[]; + interval: string; + onRenderComplete?: () => void; +}>; diff --git a/x-pack/plugins/aiops/public/plugin.tsx b/x-pack/plugins/aiops/public/plugin.tsx index 12a7f659135ae..e9f470cd6e04d 100755 --- a/x-pack/plugins/aiops/public/plugin.tsx +++ b/x-pack/plugins/aiops/public/plugin.tsx @@ -8,6 +8,7 @@ import type { CoreStart, Plugin } from '@kbn/core/public'; import { type CoreSetup } from '@kbn/core/public'; import { firstValueFrom } from 'rxjs'; +import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '../common/constants'; import type { AiopsPluginSetup, AiopsPluginSetupDeps, @@ -58,7 +59,11 @@ export class AiopsPlugin public start(core: CoreStart, plugins: AiopsPluginStartDeps): AiopsPluginStart { return { - EmbeddableChangePointChart: getEmbeddableChangePointChart(core, plugins), + EmbeddableChangePointChart: getEmbeddableChangePointChart( + EMBEDDABLE_CHANGE_POINT_CHART_TYPE, + core, + plugins + ), }; } diff --git a/x-pack/plugins/aiops/public/types.ts b/x-pack/plugins/aiops/public/types.ts index 8b40d4c257434..0ecb0851572a4 100755 --- a/x-pack/plugins/aiops/public/types.ts +++ b/x-pack/plugins/aiops/public/types.ts @@ -11,13 +11,12 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; -import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; +import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; -import type { UiActionsStart, UiActionsSetup } from '@kbn/ui-actions-plugin/public'; +import type { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { CasesUiSetup } from '@kbn/cases-plugin/public'; -import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import type { EmbeddableChangePointChartInput } from './embeddable/embeddable_change_point_chart'; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts index d230f18f7ea60..81c4dc8562bf3 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; @@ -61,6 +62,7 @@ const rulesClientParams: jest.Mocked = { alertsService: null, maxScheduledPerMinute: 1000, internalSavedObjectsRepository, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts index c3cbfd340984c..6fec4e8a636da 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts @@ -6,7 +6,11 @@ */ import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client'; -import { savedObjectsClientMock, savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; +import { + savedObjectsClientMock, + savedObjectsRepositoryMock, + uiSettingsServiceMock, +} from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { schema } from '@kbn/config-schema'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; @@ -82,6 +86,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; const getBulkOperationStatusErrorResponse = (statusCode: number) => ({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts index 2b7c72fd4c51b..81a8466e23a22 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts @@ -6,7 +6,11 @@ */ import { AlertConsumers } from '@kbn/rule-data-utils'; import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client'; -import { savedObjectsClientMock, savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; +import { + savedObjectsClientMock, + savedObjectsRepositoryMock, + uiSettingsServiceMock, +} from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import type { SavedObject } from '@kbn/core-saved-objects-server'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; @@ -96,6 +100,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts index dbd056bb1df30..7faa85b3ef0cd 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts @@ -14,6 +14,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; @@ -105,6 +106,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: getAuthenticationApiKeyMock, getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; const paramsModifier = jest.fn(); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts index d9ff12bf9d3f3..1a4898418a8c4 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts @@ -638,7 +638,7 @@ async function getUpdatedAttributesFromOperations({ case 'actions': { const updatedOperation = { ...operation, - value: addGeneratedActionValues(operation.value), + value: await addGeneratedActionValues(operation.value, context), }; try { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.test.ts index 4a79e0a07b580..f8e8b1288634a 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.test.ts @@ -5,7 +5,11 @@ * 2.0. */ import { RulesClient, ConstructorOptions } from '../../../../rules_client/rules_client'; -import { savedObjectsClientMock, savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; +import { + savedObjectsClientMock, + savedObjectsRepositoryMock, + uiSettingsServiceMock, +} from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; @@ -56,6 +60,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService, + uiSettings: uiSettingsServiceMock.createStartContract(), }; describe('bulkUntrackAlerts()', () => { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts index ca2ccc98ea292..21a7b170e2871 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts @@ -12,6 +12,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; @@ -85,6 +86,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts index bdd11da2483f7..11cd4d5f9e328 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts @@ -59,7 +59,10 @@ export async function createRule( // TODO (http-versioning): Remove this cast when we fix addGeneratedActionValues const data = { ...initialData, - actions: addGeneratedActionValues(initialData.actions as NormalizedAlertAction[]), + actions: await addGeneratedActionValues( + initialData.actions as NormalizedAlertAction[], + context + ), }; const id = options?.id || SavedObjectsUtils.generateId(); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts index c9c890b2ff6ad..03f23256041b6 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; @@ -55,6 +56,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; const getMockAggregationResult = ( diff --git a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts index 28e9fc08c3b8a..6ae8285d7fa30 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; @@ -57,6 +58,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; const listedTypes = new Set([ diff --git a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap index 95f1fca184d56..c23428b0f15a4 100644 --- a/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap +++ b/x-pack/plugins/alerting/server/integration_tests/__snapshots__/alert_as_data_fields.test.ts.snap @@ -546,33 +546,89 @@ Object { } `; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_cluster_health 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_cluster_health 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_cpu_usage 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_cpu_usage 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_disk_usage 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_disk_usage 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_elasticsearch_version_mismatch 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_elasticsearch_version_mismatch 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_jvm_memory_usage 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_jvm_memory_usage 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_kibana_version_mismatch 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_kibana_version_mismatch 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_license_expiration 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_license_expiration 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_logstash_version_mismatch 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_logstash_version_mismatch 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_missing_monitoring_data 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_missing_monitoring_data 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_nodes_changed 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_nodes_changed 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_thread_pool_search_rejections 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_thread_pool_search_rejections 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_thread_pool_write_rejections 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_alert_thread_pool_write_rejections 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_ccr_read_exceptions 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_ccr_read_exceptions 1`] = ` +Object { + "fieldMap": Object {}, +} +`; -exports[`Alert as data fields checks detect AAD fields changes for: monitoring_shard_size 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: monitoring_shard_size 1`] = ` +Object { + "fieldMap": Object {}, +} +`; exports[`Alert as data fields checks detect AAD fields changes for: observability.rules.custom_threshold 1`] = ` Object { @@ -5802,7 +5858,11 @@ Object { } `; -exports[`Alert as data fields checks detect AAD fields changes for: siem.notifications 1`] = `undefined`; +exports[`Alert as data fields checks detect AAD fields changes for: siem.notifications 1`] = ` +Object { + "fieldMap": Object {}, +} +`; exports[`Alert as data fields checks detect AAD fields changes for: siem.queryRule 1`] = ` Object { diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 87f6e4c3a3979..34472ed6066d9 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -459,7 +459,6 @@ export class AlertingPlugin { security, licenseState, } = this; - licenseState?.setNotifyUsage(plugins.licensing.featureUsage.notifyUsage); const encryptedSavedObjectsClient = plugins.encryptedSavedObjects.getClient({ @@ -508,6 +507,7 @@ export class AlertingPlugin { maxScheduledPerMinute: this.config.rules.maxScheduledPerMinute, getAlertIndicesAlias: createGetAlertIndicesAliasFn(this.ruleTypeRegistry!), alertsService: this.alertsService, + uiSettings: core.uiSettings, }); rulesSettingsClientFactory.initialize({ diff --git a/x-pack/plugins/alerting/server/rules_client/lib/__snapshots__/add_generated_action_values.test.ts.snap b/x-pack/plugins/alerting/server/rules_client/lib/__snapshots__/add_generated_action_values.test.ts.snap new file mode 100644 index 0000000000000..bfb8efef24896 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/lib/__snapshots__/add_generated_action_values.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`addGeneratedActionValues() throws error if KQL is not valid: "Error creating DSL query: invalid KQL" 1`] = `"Error creating DSL query: invalid KQL"`; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.test.ts index 6605d9c22a72b..1c04ca38bf655 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.test.ts @@ -7,12 +7,63 @@ import { addGeneratedActionValues } from './add_generated_action_values'; import { RuleAction } from '../../../common'; +import { ActionsAuthorization } from '@kbn/actions-plugin/server'; +import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { + savedObjectsClientMock, + savedObjectsRepositoryMock, +} from '@kbn/core-saved-objects-api-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { AlertingAuthorization } from '../../authorization'; +import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock'; +import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; +import { ConstructorOptions } from '../rules_client'; jest.mock('uuid', () => ({ v4: () => '111-222', })); describe('addGeneratedActionValues()', () => { + const taskManager = taskManagerMock.createStart(); + const ruleTypeRegistry = ruleTypeRegistryMock.create(); + const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); + + const encryptedSavedObjects = encryptedSavedObjectsMock.createClient(); + const authorization = alertingAuthorizationMock.create(); + const actionsAuthorization = actionsAuthorizationMock.create(); + const internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); + + const kibanaVersion = 'v7.10.0'; + const logger = loggingSystemMock.create().get(); + + const rulesClientParams: jest.Mocked = { + taskManager, + ruleTypeRegistry, + unsecuredSavedObjectsClient, + authorization: authorization as unknown as AlertingAuthorization, + actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization, + spaceId: 'default', + namespace: 'default', + getUserName: jest.fn(), + createAPIKey: jest.fn(), + logger, + internalSavedObjectsRepository, + encryptedSavedObjectsClient: encryptedSavedObjects, + getActionsClient: jest.fn(), + getEventLogClient: jest.fn(), + kibanaVersion, + maxScheduledPerMinute: 10000, + minimumScheduleInterval: { value: '1m', enforce: false }, + isAuthenticationTypeAPIKey: jest.fn(), + getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), + }; + const mockAction: RuleAction = { id: '1', group: 'default', @@ -42,25 +93,40 @@ describe('addGeneratedActionValues()', () => { }; test('adds uuid', async () => { - const actionWithGeneratedValues = addGeneratedActionValues([mockAction]); + const actionWithGeneratedValues = await addGeneratedActionValues([mockAction], { + ...rulesClientParams, + fieldsToExcludeFromPublicApi: [], + minimumScheduleIntervalInMs: 0, + }); expect(actionWithGeneratedValues[0].uuid).toBe('111-222'); }); test('adds DSL', async () => { - const actionWithGeneratedValues = addGeneratedActionValues([mockAction]); + const actionWithGeneratedValues = await addGeneratedActionValues([mockAction], { + ...rulesClientParams, + fieldsToExcludeFromPublicApi: [], + minimumScheduleIntervalInMs: 0, + }); expect(actionWithGeneratedValues[0].alertsFilter?.query?.dsl).toBe( '{"bool":{"must":[],"filter":[{"bool":{"should":[{"match":{"test":"testValue"}}],"minimum_should_match":1}},{"match_phrase":{"foo":"bar "}}],"should":[],"must_not":[]}}' ); }); test('throws error if KQL is not valid', async () => { - expect(() => - addGeneratedActionValues([ + expect(async () => + addGeneratedActionValues( + [ + { + ...mockAction, + alertsFilter: { query: { kql: 'foo:bar:1', filters: [] } }, + }, + ], { - ...mockAction, - alertsFilter: { query: { kql: 'foo:bar:1', filters: [] } }, - }, - ]) - ).toThrowErrorMatchingInlineSnapshot('"Error creating DSL query: invalid KQL"'); + ...rulesClientParams, + fieldsToExcludeFromPublicApi: [], + minimumScheduleIntervalInMs: 0, + } + ) + ).rejects.toThrowErrorMatchingSnapshot('"Error creating DSL query: invalid KQL"'); }); }); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.ts b/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.ts index 71cbf01ea1a4e..551c1ab1d2819 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/add_generated_action_values.ts @@ -8,16 +8,34 @@ import { v4 } from 'uuid'; import { buildEsQuery, Filter } from '@kbn/es-query'; import Boom from '@hapi/boom'; -import { NormalizedAlertAction, NormalizedAlertActionWithGeneratedValues } from '..'; +import { UI_SETTINGS } from '@kbn/data-plugin/common'; +import { + NormalizedAlertAction, + NormalizedAlertActionWithGeneratedValues, + RulesClientContext, +} from '..'; -export function addGeneratedActionValues( - actions: NormalizedAlertAction[] = [] -): NormalizedAlertActionWithGeneratedValues[] { +export async function addGeneratedActionValues( + actions: NormalizedAlertAction[] = [], + context: RulesClientContext +): Promise { + const uiSettingClient = context.uiSettings.asScopedToClient(context.unsecuredSavedObjectsClient); + const [allowLeadingWildcards, queryStringOptions, ignoreFilterIfFieldNotInIndex] = + await Promise.all([ + uiSettingClient.get(UI_SETTINGS.QUERY_ALLOW_LEADING_WILDCARDS), + uiSettingClient.get(UI_SETTINGS.QUERY_STRING_OPTIONS), + uiSettingClient.get(UI_SETTINGS.COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX), + ]); + const esQueryConfig = { + allowLeadingWildcards, + queryStringOptions, + ignoreFilterIfFieldNotInIndex, + }; return actions.map(({ uuid, alertsFilter, ...action }) => { const generateDSL = (kql: string, filters: Filter[]) => { try { return JSON.stringify( - buildEsQuery(undefined, [{ query: kql, language: 'kuery' }], filters) + buildEsQuery(undefined, [{ query: kql, language: 'kuery' }], filters, esQueryConfig) ); } catch (e) { throw Boom.badRequest(`Error creating DSL query: invalid KQL`); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts index ae5bf3f759194..44fb6d2e73c36 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/create_new_api_key_set.test.ts @@ -9,6 +9,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -54,6 +55,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; const username = 'test'; diff --git a/x-pack/plugins/alerting/server/rules_client/methods/update.ts b/x-pack/plugins/alerting/server/rules_client/methods/update.ts index 8fb0de5f3519c..33afee4c20d26 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/update.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/update.ts @@ -218,7 +218,10 @@ async function updateAlert( currentRule: SavedObject ): Promise> { const { attributes, version } = currentRule; - const data = { ...initialData, actions: addGeneratedActionValues(initialData.actions) }; + const data = { + ...initialData, + actions: await addGeneratedActionValues(initialData.actions, context), + }; const ruleType = context.ruleTypeRegistry.get(attributes.alertTypeId); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts index e9317972474cd..b9904055c8c0c 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts @@ -6,7 +6,11 @@ */ import { AlertConsumers } from '@kbn/rule-data-utils'; import { RulesClient, ConstructorOptions } from '../rules_client'; -import { savedObjectsClientMock, savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; +import { + savedObjectsClientMock, + savedObjectsRepositoryMock, + uiSettingsServiceMock, +} from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock'; @@ -85,6 +89,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts index 59dbfd8c87998..a9673c8aa0f96 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts @@ -12,6 +12,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -72,6 +73,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; describe('clearExpiredSnoozes()', () => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts index dbdfea132e2ef..c7988b7644fcd 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts @@ -12,6 +12,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -74,6 +75,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts index 01b9d551174cf..4f539f5a9f7b1 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -76,6 +77,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts index aa587dfb99bfa..580e557e7fdf4 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -73,6 +74,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; setGlobalDate(); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts index a6fa751469625..2281264adaf35 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -66,6 +67,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts index c8eaa3eb319ec..e377c334d0b1f 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -63,6 +64,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts index d6c8f0a0df3ec..761aca1972dd5 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { fromKueryExpression } from '@kbn/es-query'; @@ -62,6 +63,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts index 671dcc59c886f..63d86843512c0 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -54,6 +55,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts index ba0e2d7a1a485..0dcc87889b8c4 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -60,6 +61,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts index 1d00d74d1ddf8..82e07adea061a 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -63,6 +64,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts index 20c0759e1d628..994d87320b0b6 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts @@ -10,6 +10,7 @@ import { IEventLogClient } from '@kbn/event-log-plugin/server'; import { actionsClientMock } from '@kbn/actions-plugin/server/mocks'; import { eventLogClientMock } from '@kbn/event-log-plugin/server/mocks'; import { TaskStatus } from '@kbn/task-manager-plugin/server'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; import { ConstructorOptions } from '../rules_client'; import { RuleTypeRegistry } from '../../rule_type_registry'; import { RecoveredActionGroup } from '../../../common'; @@ -50,6 +51,8 @@ export function getBeforeSetup( eventLogClient?: jest.Mocked ) { jest.resetAllMocks(); + rulesClientParams.uiSettings.asScopedToClient = + uiSettingsServiceMock.createStartContract().asScopedToClient; rulesClientParams.createAPIKey.mockResolvedValue({ apiKeysEnabled: false }); rulesClientParams.getUserName.mockResolvedValue('elastic'); taskManager.runSoon.mockResolvedValue({ id: '' }); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts index ef9e864ad0eca..a9dd69f1a0e9f 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -57,6 +58,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts index cf585cc67a417..fcafeea9a640c 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -54,6 +55,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts index 3aae21df3133d..9c06960ee91ca 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -54,6 +55,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts index 13ab4778f82bc..dcf28f3d03290 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts @@ -11,6 +11,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -63,6 +64,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts index b156838704e0b..2874759f98d1e 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -56,6 +57,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; setGlobalDate(); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts index f8329f20fc432..d999a7604e9b9 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -54,6 +55,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts index 8d9232c4381c3..35ba9b37bfff1 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -54,6 +55,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts index aa03a71d93e14..be3221c8ed2f1 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts @@ -13,6 +13,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -93,6 +94,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts index de54ab9f8d5f1..b0b943cd78f68 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts @@ -10,6 +10,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; @@ -61,6 +62,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/rules_client/types.ts b/x-pack/plugins/alerting/server/rules_client/types.ts index 7428f81529f20..6b3abf6fe3a38 100644 --- a/x-pack/plugins/alerting/server/rules_client/types.ts +++ b/x-pack/plugins/alerting/server/rules_client/types.ts @@ -11,6 +11,7 @@ import { SavedObjectsClientContract, PluginInitializerContext, ISavedObjectsRepository, + UiSettingsServiceStart, } from '@kbn/core/server'; import { ActionsClient, ActionsAuthorization } from '@kbn/actions-plugin/server'; import { @@ -78,6 +79,7 @@ export interface RulesClientContext { readonly getAuthenticationAPIKey: (name: string) => CreateAPIKeyResult; readonly getAlertIndicesAlias: GetAlertIndicesAlias; readonly alertsService: AlertsService | null; + readonly uiSettings: UiSettingsServiceStart; } export type NormalizedAlertAction = Omit; diff --git a/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts b/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts index 821a04601c62d..579eacdca377b 100644 --- a/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts @@ -12,6 +12,7 @@ import { savedObjectsClientMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from './rule_type_registry.mock'; @@ -69,6 +70,7 @@ const rulesClientParams: jest.Mocked = { getAuthenticationAPIKey: jest.fn(), getAlertIndicesAlias: jest.fn(), alertsService: null, + uiSettings: uiSettingsServiceMock.createStartContract(), }; // this suite consists of two suites running tests against mutable RulesClient APIs: @@ -115,6 +117,8 @@ describe('rules_client_conflict_retries', () => { async function update(success: boolean) { try { + rulesClientParams.uiSettings.asScopedToClient = + uiSettingsServiceMock.createStartContract().asScopedToClient; await rulesClient.update({ id: MockAlertId, data: { diff --git a/x-pack/plugins/alerting/server/rules_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_client_factory.test.ts index 76f4943172a4b..a0b83ca344688 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.test.ts @@ -13,6 +13,7 @@ import { savedObjectsServiceMock, loggingSystemMock, savedObjectsRepositoryMock, + uiSettingsServiceMock, } from '@kbn/core/server/mocks'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; @@ -58,6 +59,7 @@ const rulesClientFactoryParams: jest.Mocked = { kibanaVersion: '7.10.0', authorization: alertingAuthorizationClientFactory as unknown as AlertingAuthorizationClientFactory, + uiSettings: uiSettingsServiceMock.createStartContract(), }; const actionsAuthorization = actionsAuthorizationMock.create(); @@ -70,6 +72,8 @@ beforeEach(() => { ).getActionsAuthorizationWithRequest.mockReturnValue(actionsAuthorization); rulesClientFactoryParams.getSpaceId.mockReturnValue('default'); rulesClientFactoryParams.spaceIdToNamespace.mockReturnValue('default'); + rulesClientFactoryParams.uiSettings.asScopedToClient = + uiSettingsServiceMock.createStartContract().asScopedToClient; }); test('creates a rules client with proper constructor arguments when security is enabled', async () => { @@ -117,6 +121,7 @@ test('creates a rules client with proper constructor arguments when security is getAuthenticationAPIKey: expect.any(Function), getAlertIndicesAlias: expect.any(Function), alertsService: null, + uiSettings: rulesClientFactoryParams.uiSettings, }); }); @@ -161,6 +166,7 @@ test('creates a rules client with proper constructor arguments', async () => { getAuthenticationAPIKey: expect.any(Function), getAlertIndicesAlias: expect.any(Function), alertsService: null, + uiSettings: rulesClientFactoryParams.uiSettings, }); }); diff --git a/x-pack/plugins/alerting/server/rules_client_factory.ts b/x-pack/plugins/alerting/server/rules_client_factory.ts index 6b637eed5cd1f..66ee93a1f4aeb 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.ts @@ -11,6 +11,7 @@ import { SavedObjectsServiceStart, PluginInitializerContext, ISavedObjectsRepository, + CoreStart, } from '@kbn/core/server'; import { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server'; import { @@ -48,6 +49,7 @@ export interface RulesClientFactoryOpts { maxScheduledPerMinute: AlertingRulesConfig['maxScheduledPerMinute']; getAlertIndicesAlias: GetAlertIndicesAlias; alertsService: AlertsService | null; + uiSettings: CoreStart['uiSettings']; } export class RulesClientFactory { @@ -70,6 +72,7 @@ export class RulesClientFactory { private maxScheduledPerMinute!: AlertingRulesConfig['maxScheduledPerMinute']; private getAlertIndicesAlias!: GetAlertIndicesAlias; private alertsService!: AlertsService | null; + private uiSettings!: CoreStart['uiSettings']; public initialize(options: RulesClientFactoryOpts) { if (this.isInitialized) { @@ -94,6 +97,7 @@ export class RulesClientFactory { this.maxScheduledPerMinute = options.maxScheduledPerMinute; this.getAlertIndicesAlias = options.getAlertIndicesAlias; this.alertsService = options.alertsService; + this.uiSettings = options.uiSettings; } public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): RulesClient { @@ -124,6 +128,8 @@ export class RulesClientFactory { auditLogger: securityPluginSetup?.audit.asScoped(request), getAlertIndicesAlias: this.getAlertIndicesAlias, alertsService: this.alertsService, + uiSettings: this.uiSettings, + async getUserName() { if (!securityPluginStart) { return null; diff --git a/x-pack/plugins/alerting/tsconfig.json b/x-pack/plugins/alerting/tsconfig.json index fa409e3286b6d..ada9116393748 100644 --- a/x-pack/plugins/alerting/tsconfig.json +++ b/x-pack/plugins/alerting/tsconfig.json @@ -64,7 +64,11 @@ "@kbn/core-saved-objects-api-server", "@kbn/alerts-ui-shared", "@kbn/core-http-browser", + "@kbn/core-saved-objects-api-server-mocks", + "@kbn/core-ui-settings-server-mocks", "@kbn/core-test-helpers-kbn-server" ], - "exclude": ["target/**/*"] + "exclude": [ + "target/**/*" + ] } diff --git a/x-pack/plugins/apm/server/lib/helpers/get_document_sources.ts b/x-pack/plugins/apm/server/lib/helpers/get_document_sources.ts index 02258283ac554..97b8f17b3712b 100644 --- a/x-pack/plugins/apm/server/lib/helpers/get_document_sources.ts +++ b/x-pack/plugins/apm/server/lib/helpers/get_document_sources.ts @@ -10,8 +10,22 @@ import { ApmDocumentType } from '../../../common/document_type'; import { RollupInterval } from '../../../common/rollup'; import { APMEventClient } from './create_es_client/create_apm_event_client'; import { getConfigForDocumentType } from './create_es_client/document_type'; -import { TRANSACTION_DURATION_SUMMARY } from '../../../common/es_fields/apm'; import { TimeRangeMetadata } from '../../../common/time_range_metadata'; +import { getDurationLegacyFilter } from './transactions'; + +const QUERY_INDEX = { + BEFORE: 0, + CURRENT: 1, + DURATION_SUMMARY: 2, +} as const; + +interface DocumentTypeData { + documentType: ApmDocumentType; + rollupInterval: RollupInterval; + hasDocBefore: boolean; + hasDocAfter: boolean; + allHaveDurationSummary: boolean; +} const getRequest = ({ documentType, @@ -64,129 +78,156 @@ export async function getDocumentSources({ kuery: string; enableServiceTransactionMetrics: boolean; enableContinuousRollups: boolean; -}) { - const currentRange = rangeQuery(start, end); - const diff = end - start; - const kql = kqlQuery(kuery); - const beforeRange = rangeQuery(start - diff, end - diff); - - const sourcesToCheck = [ +}): Promise { + const documentTypesToCheck = [ ...(enableServiceTransactionMetrics ? [ApmDocumentType.ServiceTransactionMetric as const] : []), ApmDocumentType.TransactionMetric as const, - ].flatMap((documentType) => { - const docTypeConfig = getConfigForDocumentType(documentType); - - return ( - enableContinuousRollups - ? docTypeConfig.rollupIntervals - : [RollupInterval.OneMinute] - ).flatMap((rollupInterval) => { - return { - documentType, - rollupInterval, - meta: { - checkSummaryFieldExists: false, - }, - before: getRequest({ - documentType, - rollupInterval, - filters: [...kql, ...beforeRange], - }), - current: getRequest({ - documentType, - rollupInterval, - filters: [...kql, ...currentRange], - }), - }; - }); + ]; + + const documentTypesInfo = await getDocumentTypesInfo({ + apmEventClient, + start, + end, + kuery, + enableContinuousRollups, + documentTypesToCheck, }); - const sourcesToCheckWithSummary = [ - ApmDocumentType.TransactionMetric as const, - ].flatMap((documentType) => { - const docTypeConfig = getConfigForDocumentType(documentType); - - return ( - enableContinuousRollups - ? docTypeConfig.rollupIntervals - : [RollupInterval.OneMinute] - ).flatMap((rollupInterval) => { - const summaryExistsFilter = { - bool: { - filter: [ - { - exists: { - field: TRANSACTION_DURATION_SUMMARY, - }, - }, - ], - }, - }; + const hasAnySourceDocBefore = documentTypesInfo.some( + (source) => source.hasDocBefore + ); - return { - documentType, - rollupInterval, - meta: { - checkSummaryFieldExists: true, - }, - before: getRequest({ - documentType, - rollupInterval, - filters: [...kql, ...beforeRange, summaryExistsFilter], - }), - current: getRequest({ - documentType, - rollupInterval, - filters: [...kql, ...currentRange, summaryExistsFilter], - }), - }; - }); + return [ + ...mapToSources(documentTypesInfo, hasAnySourceDocBefore), + { + documentType: ApmDocumentType.TransactionEvent, + rollupInterval: RollupInterval.None, + hasDocs: true, + hasDurationSummaryField: false, + }, + ]; +} + +const getDocumentTypesInfo = async ({ + apmEventClient, + start, + end, + kuery, + enableContinuousRollups, + documentTypesToCheck, +}: { + apmEventClient: APMEventClient; + start: number; + end: number; + kuery: string; + enableContinuousRollups: boolean; + documentTypesToCheck: ApmDocumentType[]; +}) => { + const getRequests = getDocumentTypeRequestsFn({ + enableContinuousRollups, + start, + end, + kuery, }); - const allSourcesToCheck = [...sourcesToCheck, ...sourcesToCheckWithSummary]; + const sourceRequests = documentTypesToCheck.flatMap(getRequests); - const allSearches = allSourcesToCheck.flatMap(({ before, current }) => [ - before, - current, - ]); + const allSearches = sourceRequests + .flatMap(({ before, current, durationSummaryCheck }) => [ + before, + current, + durationSummaryCheck, + ]) + .filter( + (request): request is ReturnType => + request !== undefined + ); const allResponses = ( await apmEventClient.msearch('get_document_availability', ...allSearches) ).responses; - const checkedSources = allSourcesToCheck.map((source, index) => { - const { documentType, rollupInterval } = source; - const responseBefore = allResponses[index * 2]; - const responseAfter = allResponses[index * 2 + 1]; - - const hasDocBefore = responseBefore.hits.total.value > 0; - const hasDocAfter = responseAfter.hits.total.value > 0; + return sourceRequests.map(({ documentType, rollupInterval, ...queries }) => { + const numberOfQueries = Object.values(queries).filter(Boolean).length; + // allResponses is sorted by the order of the requests in sourceRequests + const docTypeResponses = allResponses.splice(0, numberOfQueries); return { documentType, rollupInterval, - hasDocBefore, - hasDocAfter, - checkSummaryFieldExists: source.meta.checkSummaryFieldExists, + hasDocBefore: docTypeResponses[QUERY_INDEX.BEFORE].hits.total.value > 0, + hasDocAfter: docTypeResponses[QUERY_INDEX.CURRENT].hits.total.value > 0, + allHaveDurationSummary: docTypeResponses[QUERY_INDEX.DURATION_SUMMARY] + ? docTypeResponses[QUERY_INDEX.DURATION_SUMMARY].hits.total.value === 0 + : true, }; }); +}; - const hasAnySourceDocBefore = checkedSources.some( - (source) => source.hasDocBefore - ); +const getDocumentTypeRequestsFn = + ({ + enableContinuousRollups, + start, + end, + kuery, + }: { + enableContinuousRollups: boolean; + start: number; + end: number; + kuery: string; + }) => + (documentType: ApmDocumentType) => { + const currentRange = rangeQuery(start, end); + const diff = end - start; + const kql = kqlQuery(kuery); + const beforeRange = rangeQuery(start - diff, end - diff); + + const rollupIntervals = enableContinuousRollups + ? getConfigForDocumentType(documentType).rollupIntervals + : [RollupInterval.OneMinute]; + + return rollupIntervals.map((rollupInterval) => ({ + documentType, + rollupInterval, + before: getRequest({ + documentType, + rollupInterval, + filters: [...kql, ...beforeRange], + }), + current: getRequest({ + documentType, + rollupInterval, + filters: [...kql, ...currentRange], + }), + ...(documentType !== ApmDocumentType.ServiceTransactionMetric + ? { + durationSummaryCheck: getRequest({ + documentType, + rollupInterval, + filters: [...kql, ...currentRange, getDurationLegacyFilter()], + }), + } + : {}), + })); + }; - const sourcesWithHasDocs = checkedSources.map((checkedSource) => { +const mapToSources = ( + sources: DocumentTypeData[], + hasAnySourceDocBefore: boolean +) => { + return sources.map((source) => { const { documentType, hasDocAfter, hasDocBefore, rollupInterval, - checkSummaryFieldExists, - } = checkedSource; + allHaveDurationSummary, + } = source; const hasDocBeforeOrAfter = hasDocBefore || hasDocAfter; + // If there is any data before, we require that data is available before // this time range to mark this source as available. If we don't do that, // users that upgrade to a version that starts generating service tx metrics @@ -194,40 +235,12 @@ export async function getDocumentSources({ // If we only check before, users with a new deployment will use raw transaction // events. const hasDocs = hasAnySourceDocBefore ? hasDocBefore : hasDocBeforeOrAfter; + return { documentType, rollupInterval, - checkSummaryFieldExists, hasDocs, + hasDurationSummaryField: allHaveDurationSummary, }; }); - - const sources: TimeRangeMetadata['sources'] = sourcesWithHasDocs - .filter((source) => !source.checkSummaryFieldExists) - .map((checkedSource) => { - const { documentType, hasDocs, rollupInterval } = checkedSource; - return { - documentType, - rollupInterval, - hasDocs, - hasDurationSummaryField: - documentType === ApmDocumentType.ServiceTransactionMetric || - Boolean( - sourcesWithHasDocs.find((eSource) => { - return ( - eSource.documentType === documentType && - eSource.rollupInterval === rollupInterval && - eSource.checkSummaryFieldExists - ); - })?.hasDocs - ), - }; - }); - - return sources.concat({ - documentType: ApmDocumentType.TransactionEvent, - rollupInterval: RollupInterval.None, - hasDocs: true, - hasDurationSummaryField: false, - }); -} +}; diff --git a/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts b/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts index 182d2419c2543..dfe449e5fa635 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transactions/index.ts @@ -7,6 +7,7 @@ import { kqlQuery, rangeQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SearchAggregatedTransactionSetting } from '../../../../common/aggregated_transactions'; import { TRANSACTION_DURATION, @@ -90,13 +91,12 @@ export async function getSearchTransactionsEvents({ } } -export function getDurationFieldForTransactions( +export function isSummaryFieldSupportedByDocType( typeOrSearchAgggregatedTransactions: | ApmDocumentType.ServiceTransactionMetric | ApmDocumentType.TransactionMetric | ApmDocumentType.TransactionEvent - | boolean, - useDurationSummaryField?: boolean + | boolean ) { let type: ApmDocumentType; @@ -108,10 +108,20 @@ export function getDurationFieldForTransactions( type = typeOrSearchAgggregatedTransactions; } - if ( + return ( type === ApmDocumentType.ServiceTransactionMetric || type === ApmDocumentType.TransactionMetric - ) { + ); +} +export function getDurationFieldForTransactions( + typeOrSearchAgggregatedTransactions: + | ApmDocumentType.ServiceTransactionMetric + | ApmDocumentType.TransactionMetric + | ApmDocumentType.TransactionEvent + | boolean, + useDurationSummaryField?: boolean +) { + if (isSummaryFieldSupportedByDocType(typeOrSearchAgggregatedTransactions)) { if (useDurationSummaryField) { return TRANSACTION_DURATION_SUMMARY; } @@ -163,3 +173,18 @@ export function isRootTransaction(searchAggregatedTransactions: boolean) { }, }; } + +export function getDurationLegacyFilter(): QueryDslQueryContainer { + return { + bool: { + must: [ + { + bool: { + filter: [{ exists: { field: TRANSACTION_DURATION_HISTOGRAM } }], + must_not: [{ exists: { field: TRANSACTION_DURATION_SUMMARY } }], + }, + }, + ], + }, + }; +} diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts index 6362b4a3c5e5a..7fbeb1cc9d24c 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_service_transaction_stats.ts @@ -189,6 +189,6 @@ export async function getServiceTransactionStats({ }; }) ?? [], serviceOverflowCount: - response.aggregations?.sample?.overflowCount.value || 0, + response.aggregations?.sample?.overflowCount?.value || 0, }; } diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx b/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx index e53dce0a46886..c921bf5db2fe1 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/__stories__/render.tsx @@ -17,6 +17,7 @@ export const defaultHandlers: RendererHandlers = { isSyncColorsEnabled: () => false, isSyncCursorEnabled: () => true, isSyncTooltipsEnabled: () => false, + shouldUseSizeTransitionVeil: () => false, isInteractive: () => true, onComplete: (fn) => undefined, onEmbeddableDestroyed: action('onEmbeddableDestroyed'), diff --git a/x-pack/plugins/canvas/public/lib/create_handlers.ts b/x-pack/plugins/canvas/public/lib/create_handlers.ts index 374bdaff99721..b9c0ad97f4eb1 100644 --- a/x-pack/plugins/canvas/public/lib/create_handlers.ts +++ b/x-pack/plugins/canvas/public/lib/create_handlers.ts @@ -29,6 +29,7 @@ export const createBaseHandlers = (): IInterpreterRenderHandlers => ({ isSyncColorsEnabled: () => false, isSyncTooltipsEnabled: () => false, isSyncCursorEnabled: () => true, + shouldUseSizeTransitionVeil: () => false, isInteractive: () => true, getExecutionContext: () => undefined, }); diff --git a/x-pack/plugins/cases/public/components/case_action_bar/index.test.tsx b/x-pack/plugins/cases/public/components/case_action_bar/index.test.tsx index 2429e68cbefa5..4386f996608f6 100644 --- a/x-pack/plugins/cases/public/components/case_action_bar/index.test.tsx +++ b/x-pack/plugins/cases/public/components/case_action_bar/index.test.tsx @@ -10,7 +10,7 @@ import { mount } from 'enzyme'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { basicCase } from '../../containers/mock'; +import { basicCase, basicCaseClosed } from '../../containers/mock'; import type { CaseActionBarProps } from '.'; import { CaseActionBar } from '.'; import { @@ -74,6 +74,18 @@ describe('CaseActionBar', () => { ); }); + it('should show the status as closed when the case is closed', () => { + const wrapper = mount( + + + + ); + + expect(wrapper.find(`[data-test-subj="case-view-status-dropdown"]`).first().text()).toBe( + 'Closed' + ); + }); + it('should show the correct date', () => { const wrapper = mount( diff --git a/x-pack/plugins/cases/public/components/case_view/case_view_page.test.tsx b/x-pack/plugins/cases/public/components/case_view/case_view_page.test.tsx index a2fb4a8ae1a08..59ca9a98de12e 100644 --- a/x-pack/plugins/cases/public/components/case_view/case_view_page.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/case_view_page.test.tsx @@ -6,248 +6,104 @@ */ import React from 'react'; -import { waitFor, within, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { waitFor, screen } from '@testing-library/react'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; import '../../common/mock/match_media'; -import { useCaseViewNavigation, useUrlParams } from '../../common/navigation/hooks'; -import { useGetSupportedActionConnectors } from '../../containers/configure/use_get_supported_action_connectors'; -import { basicCaseClosed, connectorsMock, getCaseUsersMockResponse } from '../../containers/mock'; -import type { UseGetCase } from '../../containers/use_get_case'; -import { useGetCase } from '../../containers/use_get_case'; -import { useGetCaseMetrics } from '../../containers/use_get_case_metrics'; -import { useFindCaseUserActions } from '../../containers/use_find_case_user_actions'; -import { useGetTags } from '../../containers/use_get_tags'; -import { usePostPushToService } from '../../containers/use_post_push_to_service'; -import { useGetCaseConnectors } from '../../containers/use_get_case_connectors'; -import { useUpdateCase } from '../../containers/use_update_case'; -import { useGetCaseUsers } from '../../containers/use_get_case_users'; +import { useUrlParams } from '../../common/navigation/hooks'; import { CaseViewPage } from './case_view_page'; -import { - caseData, - caseViewProps, - defaultGetCase, - defaultGetCaseMetrics, - defaultInfiniteUseFindCaseUserActions, - defaultUpdateCaseState, - defaultUseFindCaseUserActions, -} from './mocks'; +import { caseData, caseViewProps } from './mocks'; import type { CaseViewPageProps } from './types'; -import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; -import { CASE_VIEW_PAGE_TABS } from '../../../common/types'; -import { getCaseConnectorsMockResponse } from '../../common/mock/connectors'; -import { useInfiniteFindCaseUserActions } from '../../containers/use_infinite_find_case_user_actions'; -import { useGetCaseUserActionsStats } from '../../containers/use_get_case_user_actions_stats'; -import { createQueryWithMarkup } from '../../common/test_utils'; -import { useCasesFeatures } from '../../common/use_cases_features'; -import { CaseMetricsFeature } from '../../../common/types/api'; +import { waitForComponentToUpdate } from '../../common/test_utils'; +import { useCasesTitleBreadcrumbs } from '../use_breadcrumbs'; -jest.mock('../../containers/use_get_action_license'); -jest.mock('../../containers/use_update_case'); -jest.mock('../../containers/use_get_case_metrics'); -jest.mock('../../containers/use_find_case_user_actions'); -jest.mock('../../containers/use_infinite_find_case_user_actions'); -jest.mock('../../containers/use_get_case_user_actions_stats'); -jest.mock('../../containers/use_get_tags'); -jest.mock('../../containers/use_get_case'); -jest.mock('../../containers/configure/use_get_supported_action_connectors'); -jest.mock('../../containers/use_post_push_to_service'); -jest.mock('../../containers/use_get_case_connectors'); -jest.mock('../../containers/use_get_case_users'); -jest.mock('../../containers/user_profiles/use_bulk_get_user_profiles'); -jest.mock('../../common/use_cases_features'); -jest.mock('../user_actions/timestamp', () => ({ - UserActionTimestamp: () => <>, -})); jest.mock('../../common/navigation/hooks'); +jest.mock('../use_breadcrumbs'); +jest.mock('./use_on_refresh_case_view_page'); jest.mock('../../common/hooks'); -jest.mock('../connectors/resilient/api'); jest.mock('../../common/lib/kibana'); -const useFetchCaseMock = useGetCase as jest.Mock; -const useUrlParamsMock = useUrlParams as jest.Mock; -const useCaseViewNavigationMock = useCaseViewNavigation as jest.Mock; -const useUpdateCaseMock = useUpdateCase as jest.Mock; -const useFindCaseUserActionsMock = useFindCaseUserActions as jest.Mock; -const useInfiniteFindCaseUserActionsMock = useInfiniteFindCaseUserActions as jest.Mock; -const useGetCaseUserActionsStatsMock = useGetCaseUserActionsStats as jest.Mock; -const useGetConnectorsMock = useGetSupportedActionConnectors as jest.Mock; -const usePostPushToServiceMock = usePostPushToService as jest.Mock; -const useGetCaseConnectorsMock = useGetCaseConnectors as jest.Mock; -const useGetCaseMetricsMock = useGetCaseMetrics as jest.Mock; -const useGetTagsMock = useGetTags as jest.Mock; -const useGetCaseUsersMock = useGetCaseUsers as jest.Mock; -const useCasesFeaturesMock = useCasesFeatures as jest.Mock; +jest.mock('../header_page', () => ({ + HeaderPage: jest + .fn() + .mockReturnValue(
{'Case view header'}
), +})); -const mockGetCase = (props: Partial = {}) => { - const data = { - ...defaultGetCase.data, - ...props.data, - }; +jest.mock('./metrics', () => ({ + CaseViewMetrics: jest + .fn() + .mockReturnValue(
{'Case view metrics'}
), +})); - useFetchCaseMock.mockReturnValue({ - ...defaultGetCase, - ...props, - data, - }); -}; +jest.mock('./components/case_view_activity', () => ({ + CaseViewActivity: jest + .fn() + .mockReturnValue(
{'Case view activity'}
), +})); -export const caseProps: CaseViewPageProps = { +jest.mock('./components/case_view_alerts', () => ({ + CaseViewAlerts: jest + .fn() + .mockReturnValue(
{'Case view alerts'}
), +})); + +jest.mock('./components/case_view_files', () => ({ + CaseViewFiles: jest + .fn() + .mockReturnValue(
{'Case view files'}
), +})); + +const useUrlParamsMock = useUrlParams as jest.Mock; +const useCasesTitleBreadcrumbsMock = useCasesTitleBreadcrumbs as jest.Mock; + +const caseProps: CaseViewPageProps = { ...caseViewProps, - caseId: caseData.id, caseData, fetchCase: jest.fn(), }; -export const caseClosedProps: CaseViewPageProps = { - ...caseProps, - caseData: basicCaseClosed, -}; - -const userActionsStats = { - total: 21, - totalComments: 9, - totalOtherActions: 11, -}; - describe('CaseViewPage', () => { - const updateCaseProperty = defaultUpdateCaseState.mutate; - const pushCaseToExternalService = jest.fn(); - const caseConnectors = getCaseConnectorsMockResponse(); - const caseUsers = getCaseUsersMockResponse(); - let appMockRenderer: AppMockRenderer; - // eslint-disable-next-line prefer-object-spread - const originalGetComputedStyle = Object.assign({}, window.getComputedStyle); - - const platinumLicense = licensingMock.createLicense({ - license: { type: 'platinum' }, - }); - - beforeAll(() => { - // The JSDOM implementation is too slow - // Especially for dropdowns that try to position themselves - // perf issue - https://github.com/jsdom/jsdom/issues/3234 - Object.defineProperty(window, 'getComputedStyle', { - value: (el: HTMLElement) => { - /** - * This is based on the jsdom implementation of getComputedStyle - * https://github.com/jsdom/jsdom/blob/9dae17bf0ad09042cfccd82e6a9d06d3a615d9f4/lib/jsdom/browser/Window.js#L779-L820 - * - * It is missing global style parsing and will only return styles applied directly to an element. - * Will not return styles that are global or from emotion - */ - const declaration = new CSSStyleDeclaration(); - const { style } = el; - - Array.prototype.forEach.call(style, (property: string) => { - declaration.setProperty( - property, - style.getPropertyValue(property), - style.getPropertyPriority(property) - ); - }); - - return declaration; - }, - configurable: true, - writable: true, - }); - }); - beforeEach(() => { jest.clearAllMocks(); - mockGetCase(); - useUpdateCaseMock.mockReturnValue(defaultUpdateCaseState); - useGetCaseMetricsMock.mockReturnValue(defaultGetCaseMetrics); - useFindCaseUserActionsMock.mockReturnValue(defaultUseFindCaseUserActions); - useInfiniteFindCaseUserActionsMock.mockReturnValue(defaultInfiniteUseFindCaseUserActions); - useGetCaseUserActionsStatsMock.mockReturnValue({ data: userActionsStats, isLoading: false }); - usePostPushToServiceMock.mockReturnValue({ - isLoading: false, - mutateAsync: pushCaseToExternalService, - }); - useGetCaseConnectorsMock.mockReturnValue({ - isLoading: false, - data: caseConnectors, - }); - useGetConnectorsMock.mockReturnValue({ data: connectorsMock, isLoading: false }); - useGetTagsMock.mockReturnValue({ data: [], isLoading: false }); - useGetCaseUsersMock.mockReturnValue({ isLoading: false, data: caseUsers }); - useCasesFeaturesMock.mockReturnValue({ - metricsFeatures: [CaseMetricsFeature.ALERTS_COUNT], - pushToServiceAuthorized: true, - caseAssignmentAuthorized: true, - isAlertsEnabled: true, - isSyncAlertsEnabled: true, - }); - - appMockRenderer = createAppMockRenderer({ license: platinumLicense }); - }); - - afterAll(() => { - Object.defineProperty(window, 'getComputedStyle', originalGetComputedStyle); + useUrlParamsMock.mockReturnValue({}); + appMockRenderer = createAppMockRenderer(); }); - it('shows the metrics section', async () => { + it('shows the header section', async () => { appMockRenderer.render(); - expect(await screen.findByTestId('case-view-metrics-panel')).toBeInTheDocument(); + expect(await screen.findByTestId('test-case-view-header')).toBeInTheDocument(); }); - it('should show closed indicators in header when case is closed', async () => { - useUpdateCaseMock.mockImplementation(() => ({ - ...defaultUpdateCaseState, - caseData: basicCaseClosed, - })); - - appMockRenderer.render(); + it('shows the metrics section', async () => { + appMockRenderer.render(); - expect(await screen.findByTestId('case-view-status-dropdown')).toHaveTextContent('Closed'); + expect(await screen.findByTestId('test-case-view-metrics')).toBeInTheDocument(); }); - it('should push updates on button click', async () => { - useGetCaseConnectorsMock.mockImplementation(() => ({ - isLoading: false, - data: { - ...caseConnectors, - 'resilient-2': { - ...caseConnectors['resilient-2'], - push: { ...caseConnectors['resilient-2'].push, needsToBePushed: true }, - }, - }, - })); - + it('shows the activity section', async () => { appMockRenderer.render(); - expect(await screen.findByTestId('edit-connectors')).toBeInTheDocument(); - expect(await screen.findByTestId('push-to-external-service')).toBeInTheDocument(); - - userEvent.click(screen.getByTestId('push-to-external-service')); - - await waitFor(() => { - expect(pushCaseToExternalService).toHaveBeenCalled(); - }); + expect(await screen.findByTestId('test-case-view-activity')).toBeInTheDocument(); }); - it('should disable the push button when connector is invalid', async () => { + it('should set the breadcrumbs correctly', async () => { + const onComponentInitialized = jest.fn(); + appMockRenderer.render( - + ); - expect(await screen.findByTestId('edit-connectors')).toBeInTheDocument(); - expect(await screen.findByTestId('push-to-external-service')).toBeDisabled(); + await waitFor(() => { + expect(useCasesTitleBreadcrumbsMock).toHaveBeenCalledWith(caseProps.caseData.title); + }); }); it('should call onComponentInitialized on mount', async () => { const onComponentInitialized = jest.fn(); + appMockRenderer.render( ); @@ -257,229 +113,21 @@ describe('CaseViewPage', () => { }); }); - it('should show loading content when loading user actions stats', async () => { - const useFetchAlertData = jest.fn().mockReturnValue([true]); - useGetCaseUserActionsStatsMock.mockReturnValue({ isLoading: true }); - - appMockRenderer.render(); - - expect(await screen.findByTestId('case-view-loading-content')).toBeInTheDocument(); - expect(screen.queryByTestId('user-actions-list')).not.toBeInTheDocument(); - }); - - it('should call show alert details with expected arguments', async () => { - const showAlertDetails = jest.fn(); - appMockRenderer.render(); - - userEvent.click((await screen.findAllByTestId('comment-action-show-alert-alert-action-id'))[1]); - - await waitFor(() => { - expect(showAlertDetails).toHaveBeenCalledWith('alert-id-1', 'alert-index-1'); - }); - }); - - it('should show the rule name', async () => { - appMockRenderer.render(); - - expect( - ( - await screen.findAllByTestId('user-action-alert-comment-create-action-alert-action-id') - )[1].querySelector('.euiCommentEvent__headerEvent') - ).toHaveTextContent('added an alert from Awesome rule'); - }); - - it('should update settings', async () => { - appMockRenderer.render(); - - userEvent.click(await screen.findByTestId('sync-alerts-switch')); - - await waitFor(() => { - const updateObject = updateCaseProperty.mock.calls[0][0]; - - expect(updateObject.updateKey).toEqual('settings'); - expect(updateObject.updateValue).toEqual({ syncAlerts: false }); - }); - }); - - it('should show the correct connector name on the push button', async () => { - useGetConnectorsMock.mockImplementation(() => ({ data: connectorsMock, isLoading: false })); + it('should call onComponentInitialized only once', async () => { + const onComponentInitialized = jest.fn(); - appMockRenderer.render( - + const { rerender } = appMockRenderer.render( + ); - expect(await screen.findByTestId('edit-connectors')).toBeInTheDocument(); - expect(await screen.findByText('Update My Resilient connector incident')).toBeInTheDocument(); - }); - - describe('Callouts', () => { - const errorText = - 'The connector used to send updates to the external service has been deleted or you do not have the appropriate licenseExternal link(opens in a new tab or window) to use it. To update cases in external systems, select a different connector or create a new one.'; - - it('it shows the danger callout when a connector has been deleted', async () => { - useGetConnectorsMock.mockImplementation(() => ({ data: [], isLoading: false })); - appMockRenderer.render(); - - expect(await screen.findByTestId('edit-connectors')).toBeInTheDocument(); - - const getByText = createQueryWithMarkup(screen.getByText); - expect(getByText(errorText)).toBeInTheDocument(); - }); - - it('it does NOT shows the danger callout when connectors are loading', async () => { - useGetConnectorsMock.mockImplementation(() => ({ data: [], isLoading: true })); - appMockRenderer.render(); - - expect(await screen.findByTestId('edit-connectors')).toBeInTheDocument(); - expect( - screen.queryByTestId('case-callout-a25a5b368b6409b179ef4b6c5168244f') - ).not.toBeInTheDocument(); - }); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/149777 - describe.skip('Tabs', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('renders tabs correctly', async () => { - appMockRenderer.render(); - - expect(await screen.findByRole('tablist')).toBeInTheDocument(); - - expect(await screen.findByTestId('case-view-tab-title-activity')).toBeInTheDocument(); - expect(await screen.findByTestId('case-view-tab-title-alerts')).toBeInTheDocument(); - expect(await screen.findByTestId('case-view-tab-title-files')).toBeInTheDocument(); - }); - - it('renders the activity tab by default', async () => { - appMockRenderer.render(); - expect(await screen.findByTestId('case-view-tab-content-activity')).toBeInTheDocument(); - }); - - it('renders the alerts tab when the query parameter tabId has alerts', async () => { - useUrlParamsMock.mockReturnValue({ - urlParams: { - tabId: CASE_VIEW_PAGE_TABS.ALERTS, - }, - }); - - appMockRenderer.render(); - - expect(await screen.findByTestId('case-view-tab-content-alerts')).toBeInTheDocument(); - expect(await screen.findByTestId('alerts-table')).toBeInTheDocument(); - }); - - it('renders the activity tab when the query parameter tabId has activity', async () => { - useUrlParamsMock.mockReturnValue({ - urlParams: { - tabId: CASE_VIEW_PAGE_TABS.ACTIVITY, - }, - }); - - appMockRenderer.render(); - - expect(await screen.findByTestId('case-view-tab-content-activity')).toBeInTheDocument(); - }); - - it('renders the activity tab when the query parameter tabId has an unknown value', async () => { - useUrlParamsMock.mockReturnValue({ - urlParams: { - tabId: 'what-is-love', - }, - }); - - appMockRenderer.render(); - - expect(await screen.findByTestId('case-view-tab-content-activity')).toBeInTheDocument(); - expect(screen.queryByTestId('case-view-tab-content-alerts')).not.toBeInTheDocument(); - }); - - it('navigates to the activity tab when the activity tab is clicked', async () => { - const navigateToCaseViewMock = useCaseViewNavigationMock().navigateToCaseView; - appMockRenderer.render(); - - userEvent.click(await screen.findByTestId('case-view-tab-title-activity')); - - await waitFor(() => { - expect(navigateToCaseViewMock).toHaveBeenCalledWith({ - detailName: caseData.id, - tabId: CASE_VIEW_PAGE_TABS.ACTIVITY, - }); - }); - }); - - it('navigates to the alerts tab when the alerts tab is clicked', async () => { - const navigateToCaseViewMock = useCaseViewNavigationMock().navigateToCaseView; - appMockRenderer.render(); - - userEvent.click(await screen.findByTestId('case-view-tab-title-alerts')); - - await waitFor(async () => { - expect(navigateToCaseViewMock).toHaveBeenCalledWith({ - detailName: caseData.id, - tabId: CASE_VIEW_PAGE_TABS.ALERTS, - }); - }); - }); - - it('should display the alerts tab when the feature is enabled', async () => { - appMockRenderer = createAppMockRenderer({ features: { alerts: { enabled: true } } }); - appMockRenderer.render(); - - expect(await screen.findByTestId('case-view-tab-title-activity')).toBeInTheDocument(); - expect(await screen.findByTestId('case-view-tab-title-alerts')).toBeInTheDocument(); - }); - - it('should not display the alerts tab when the feature is disabled', async () => { - appMockRenderer = createAppMockRenderer({ features: { alerts: { enabled: false } } }); - appMockRenderer.render(); - - expect(await screen.findByTestId('case-view-tab-title-activity')).toBeInTheDocument(); - expect(screen.queryByTestId('case-view-tab-title-alerts')).not.toBeInTheDocument(); - }); - - it('should not show the experimental badge on the alerts table', async () => { - appMockRenderer = createAppMockRenderer({ - features: { alerts: { isExperimental: false } }, - }); - appMockRenderer.render(); - - expect( - screen.queryByTestId('case-view-alerts-table-experimental-badge') - ).not.toBeInTheDocument(); - }); - - it('should show the experimental badge on the alerts table', async () => { - appMockRenderer = createAppMockRenderer({ features: { alerts: { isExperimental: true } } }); - appMockRenderer.render(); - - expect( - await screen.findByTestId('case-view-alerts-table-experimental-badge') - ).toBeInTheDocument(); + await waitFor(() => { + expect(onComponentInitialized).toHaveBeenCalled(); }); - describe('description', () => { - it('renders the description correctly', async () => { - appMockRenderer.render(); + rerender(); - const description = within(await screen.findByTestId('description')); + await waitForComponentToUpdate(); - expect(await description.findByText(caseData.description)).toBeInTheDocument(); - }); - - it('should display description when case is loading', async () => { - useUpdateCaseMock.mockImplementation(() => ({ - ...defaultUpdateCaseState, - isLoading: true, - updateKey: 'description', - })); - - appMockRenderer.render(); - - expect(await screen.findByTestId('description')).toBeInTheDocument(); - }); - }); + expect(onComponentInitialized).toBeCalledTimes(1); }); }); diff --git a/x-pack/plugins/cases/public/components/case_view/case_view_page.tsx b/x-pack/plugins/cases/public/components/case_view/case_view_page.tsx index 30af8a4a00552..4d9e3ba640449 100644 --- a/x-pack/plugins/cases/public/components/case_view/case_view_page.tsx +++ b/x-pack/plugins/cases/public/components/case_view/case_view_page.tsx @@ -6,7 +6,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import React, { useCallback, useEffect, useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; import { CASE_VIEW_PAGE_TABS } from '../../../common/types'; import { useUrlParams } from '../../common/navigation'; import { useCasesContext } from '../cases_context/use_cases_context'; @@ -23,6 +23,14 @@ import type { CaseViewPageProps } from './types'; import { useRefreshCaseViewPage } from './use_on_refresh_case_view_page'; import { useOnUpdateField } from './use_on_update_field'; +const getActiveTabId = (tabId?: string) => { + if (tabId && Object.values(CASE_VIEW_PAGE_TABS).includes(tabId as CASE_VIEW_PAGE_TABS)) { + return tabId; + } + + return CASE_VIEW_PAGE_TABS.ACTIVITY; +}; + export const CaseViewPage = React.memo( ({ caseData, @@ -39,12 +47,7 @@ export const CaseViewPage = React.memo( useCasesTitleBreadcrumbs(caseData.title); - const activeTabId = useMemo(() => { - if (urlParams.tabId && Object.values(CASE_VIEW_PAGE_TABS).includes(urlParams.tabId)) { - return urlParams.tabId; - } - return CASE_VIEW_PAGE_TABS.ACTIVITY; - }, [urlParams.tabId]); + const activeTabId = getActiveTabId(urlParams?.tabId); const init = useRef(true); const timelineUi = useTimelineContext()?.ui; @@ -113,15 +116,12 @@ export const CaseViewPage = React.memo( onUpdateField={onUpdateField} /> - - - {activeTabId === CASE_VIEW_PAGE_TABS.ACTIVITY && ( { expect(screen.queryByTestId('case-view-files-stats-badge')).not.toBeInTheDocument(); }); - it('the files tab count has a different colour if the tab is not active', async () => { + it('the files tab count has a different color if the tab is not active', async () => { appMockRenderer.render(); expect( @@ -140,7 +140,7 @@ describe('CaseViewTabs', () => { expect(badge).toHaveTextContent('3'); }); - it('the alerts tab count has a different colour if the tab is not active', async () => { + it('the alerts tab count has a different color if the tab is not active', async () => { appMockRenderer.render( ); @@ -191,4 +191,54 @@ describe('CaseViewTabs', () => { }); }); }); + + it('should display the alerts tab when the feature is enabled', async () => { + appMockRenderer = createAppMockRenderer({ features: { alerts: { enabled: true } } }); + + appMockRenderer.render( + + ); + + expect(await screen.findByTestId('case-view-tab-title-alerts')).toBeInTheDocument(); + }); + + it('should not display the alerts tab when the feature is disabled', async () => { + appMockRenderer = createAppMockRenderer({ features: { alerts: { enabled: false } } }); + + appMockRenderer.render( + + ); + + expect(await screen.findByTestId('case-view-tabs')).toBeInTheDocument(); + expect(screen.queryByTestId('case-view-tab-title-alerts')).not.toBeInTheDocument(); + }); + + it('should not show the experimental badge on the alerts table', async () => { + appMockRenderer = createAppMockRenderer({ + features: { alerts: { isExperimental: false } }, + }); + + appMockRenderer.render( + + ); + + expect(await screen.findByTestId('case-view-tabs')).toBeInTheDocument(); + expect( + screen.queryByTestId('case-view-alerts-table-experimental-badge') + ).not.toBeInTheDocument(); + }); + + it('should show the experimental badge on the alerts table', async () => { + appMockRenderer = createAppMockRenderer({ + features: { alerts: { isExperimental: true } }, + }); + + appMockRenderer.render( + + ); + + expect( + await screen.findByTestId('case-view-alerts-table-experimental-badge') + ).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx b/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx index 671ce6606a141..cf5b2e7bd6802 100644 --- a/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx +++ b/x-pack/plugins/cases/public/components/case_view/case_view_tabs.tsx @@ -143,7 +143,7 @@ export const CaseViewTabs = React.memo(({ caseData, activeTab return ( <> - {renderTabs()} + {renderTabs()} ); diff --git a/x-pack/plugins/cases/public/components/case_view/index.tsx b/x-pack/plugins/cases/public/components/case_view/index.tsx index 4ba3f912b9d0b..ecbde67ba15df 100644 --- a/x-pack/plugins/cases/public/components/case_view/index.tsx +++ b/x-pack/plugins/cases/public/components/case_view/index.tsx @@ -86,7 +86,6 @@ export const CaseView = React.memo( {getLegacyUrlConflictCallout()} void; caseData: CaseUI; } diff --git a/x-pack/plugins/cases/public/components/custom_fields/flyout.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/flyout.test.tsx index ce7a9687b89ec..63dc30d69c2e0 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/flyout.test.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/flyout.test.tsx @@ -16,7 +16,12 @@ import { customFieldsConfigurationMock } from '../../containers/mock'; import { MAX_CUSTOM_FIELD_LABEL_LENGTH } from '../../../common/constants'; import * as i18n from './translations'; -describe('CustomFieldFlyout ', () => { +// FLAKY: https://github.com/elastic/kibana/issues/174285 +// FLAKY: https://github.com/elastic/kibana/issues/174286 +// FLAKY: https://github.com/elastic/kibana/issues/174287 +// FLAKY: https://github.com/elastic/kibana/issues/174288 +// FLAKY: https://github.com/elastic/kibana/issues/174289 +describe.skip('CustomFieldFlyout ', () => { let appMockRender: AppMockRenderer; const props = { diff --git a/x-pack/plugins/cases/public/components/description/index.test.tsx b/x-pack/plugins/cases/public/components/description/index.test.tsx index 386d6b6e7154f..3c2f32437f4a0 100644 --- a/x-pack/plugins/cases/public/components/description/index.test.tsx +++ b/x-pack/plugins/cases/public/components/description/index.test.tsx @@ -27,7 +27,13 @@ const defaultProps = { isLoadingDescription: false, }; -describe('Description', () => { +// FLAKY: https://github.com/elastic/kibana/issues/174321 +// FLAKY: https://github.com/elastic/kibana/issues/174322 +// FLAKY: https://github.com/elastic/kibana/issues/174323 +// FLAKY: https://github.com/elastic/kibana/issues/164045 +// FLAKY: https://github.com/elastic/kibana/issues/164048 +// FLAKY: https://github.com/elastic/kibana/issues/164049 +describe.skip('Description', () => { const onUpdateField = jest.fn(); let appMockRender: AppMockRenderer; @@ -144,6 +150,14 @@ describe('Description', () => { expect(screen.queryByTestId('description-edit-icon')).not.toBeInTheDocument(); }); + it('should display description when case is loading', async () => { + appMockRender.render( + + ); + + expect(await screen.findByTestId('description')).toBeInTheDocument(); + }); + describe('draft message', () => { const draftStorageKey = `cases.testAppId.basic-case-id.description.markdownEditor`; diff --git a/x-pack/plugins/cases/public/components/edit_connector/index.test.tsx b/x-pack/plugins/cases/public/components/edit_connector/index.test.tsx index b68641526c46a..1f50670b05291 100644 --- a/x-pack/plugins/cases/public/components/edit_connector/index.test.tsx +++ b/x-pack/plugins/cases/public/components/edit_connector/index.test.tsx @@ -15,13 +15,15 @@ import { EditConnector } from '.'; import { type AppMockRenderer, createAppMockRenderer, - readCasesPermissions, - noPushCasesPermissions, TestProviders, noConnectorsCasePermission, + noCasesPermissions, } from '../../common/mock'; import { basicCase, connectorsMock } from '../../containers/mock'; import { getCaseConnectorsMockResponse } from '../../common/mock/connectors'; +import type { ReturnUsePushToService } from '../use_push_to_service'; +import { usePushToService } from '../use_push_to_service'; +import { ConnectorTypes } from '../../../common'; const onSubmit = jest.fn(); const caseConnectors = getCaseConnectorsMockResponse(); @@ -34,35 +36,50 @@ const defaultProps: EditConnectorProps = { onSubmit, }; +jest.mock('../use_push_to_service'); + +const handlePushToService = jest.fn(); +const usePushToServiceMock = usePushToService as jest.Mock; + +const errorMsg = { id: 'test-error-msg', title: 'My error msg', description: 'My error desc' }; + +const usePushToServiceMockRes: ReturnUsePushToService = { + errorsMsg: [], + hasErrorMessages: false, + needsToBePushed: true, + hasBeenPushed: true, + isLoading: false, + hasLicenseError: false, + hasPushPermissions: true, + handlePushToService, +}; + describe('EditConnector ', () => { let appMockRender: AppMockRenderer; beforeEach(() => { jest.clearAllMocks(); appMockRender = createAppMockRenderer(); + usePushToServiceMock.mockReturnValue(usePushToServiceMockRes); }); - it('Renders the none connector', async () => { + it('renders an error message correctly', async () => { + usePushToServiceMock.mockReturnValue({ + ...usePushToServiceMockRes, + errorsMsg: [errorMsg], + hasErrorMessages: true, + }); + render( ); - expect( - await screen.findByText( - 'To create and update a case in an external system, select a connector.' - ) - ).toBeInTheDocument(); - - userEvent.click(screen.getByTestId('connector-edit-button')); - - await waitFor(() => { - expect(screen.getAllByTestId('dropdown-connector-no-connector').length).toBeGreaterThan(0); - }); + expect(await screen.findByText(errorMsg.description)).toBeInTheDocument(); }); - it('Edit external service on submit', async () => { + it('calls onSubmit when changing connector', async () => { render( @@ -97,6 +114,31 @@ describe('EditConnector ', () => { ); }); + it('should call handlePushToService when pushing to an external service', async () => { + usePushToServiceMock.mockReturnValue({ ...usePushToServiceMockRes, needsToBePushed: true }); + const props = { + ...defaultProps, + caseData: { + ...defaultProps.caseData, + connector: { + ...defaultProps.caseData.connector, + id: 'servicenow-1', + }, + }, + }; + + render( + + + + ); + + expect(await screen.findByTestId('push-to-external-service')).toBeInTheDocument(); + userEvent.click(screen.getByTestId('push-to-external-service')); + + await waitFor(() => expect(handlePushToService).toHaveBeenCalled()); + }); + it('reverts to the initial selection if the caseData do not change', async () => { const props = { ...defaultProps, @@ -201,6 +243,7 @@ describe('EditConnector ', () => { it('does not shows the callouts when is loading', async () => { const props = { ...defaultProps, isLoading: true }; + usePushToServiceMock.mockReturnValue({ ...usePushToServiceMockRes, errorsMsg: [errorMsg] }); render( @@ -215,7 +258,7 @@ describe('EditConnector ', () => { it('does not allow the connector to be edited when the user does not have write permissions', async () => { render( - + ); @@ -229,25 +272,15 @@ describe('EditConnector ', () => { }); }); - it('display the callout message when none is selected', async () => { - // default props has the none connector as selected - const result = appMockRender.render(); - - await waitFor(() => { - expect(result.getByTestId('push-callouts')).toBeInTheDocument(); - }); - }); - it('shows the actions permission message if the user does not have read access to actions', async () => { appMockRender.coreStart.application.capabilities = { ...appMockRender.coreStart.application.capabilities, actions: { save: false, show: false }, }; - const result = appMockRender.render(); - await waitFor(() => { - expect(result.getByTestId('edit-connector-permissions-error-msg')).toBeInTheDocument(); - }); + appMockRender.render(); + + expect(await screen.findByTestId('edit-connector-permissions-error-msg')).toBeInTheDocument(); }); it('does not show the actions permission message if the user has read access to actions', async () => { @@ -256,35 +289,34 @@ describe('EditConnector ', () => { actions: { save: true, show: true }, }; - const result = appMockRender.render(); - await waitFor(() => { - expect(result.queryByTestId('edit-connector-permissions-error-msg')).toBe(null); - }); + appMockRender.render(); + + expect(screen.queryByTestId('edit-connector-permissions-error-msg')).not.toBeInTheDocument(); }); it('does not show the callout if the user does not have read access to actions', async () => { const props = { ...defaultProps, connectors: [] }; + appMockRender.coreStart.application.capabilities = { ...appMockRender.coreStart.application.capabilities, actions: { save: false, show: false }, }; - const result = appMockRender.render(); - await waitFor(() => { - expect(result.getByTestId('edit-connector-permissions-error-msg')).toBeInTheDocument(); - expect(result.queryByTestId('push-callouts')).toBe(null); - }); + appMockRender.render(); + + expect(await screen.findByTestId('edit-connector-permissions-error-msg')).toBeInTheDocument(); + expect(screen.queryByTestId('push-callouts')).not.toBeInTheDocument(); }); - it('does not show the callout if the user does not have access to cases connectors', async () => { + it('does not show the callouts if the user does not have access to cases connectors', async () => { + usePushToServiceMock.mockReturnValue({ ...usePushToServiceMockRes, errorsMsg: [errorMsg] }); const props = { ...defaultProps, connectors: [] }; + appMockRender = createAppMockRenderer({ permissions: noConnectorsCasePermission() }); - const result = appMockRender.render(); - await waitFor(() => { - expect(result.getByTestId('edit-connector-permissions-error-msg')).toBeInTheDocument(); - expect(result.queryByTestId('push-callouts')).toBe(null); - }); + appMockRender.render(); + + expect(screen.queryByTestId('push-callouts')).toBe(null); }); it('does not show the connectors previewer if the user does not have read access to actions', async () => { @@ -294,16 +326,16 @@ describe('EditConnector ', () => { actions: { save: false, show: false }, }; - const result = appMockRender.render(); - expect(result.queryByTestId('connector-fields-preview')).not.toBeInTheDocument(); + appMockRender.render(); + expect(screen.queryByTestId('connector-fields-preview')).not.toBeInTheDocument(); }); it('does not show the connectors previewer if the user does not have access to cases connectors', async () => { const props = { ...defaultProps, connectors: [] }; appMockRender = createAppMockRenderer({ permissions: noConnectorsCasePermission() }); - const result = appMockRender.render(); - expect(result.queryByTestId('connector-fields-preview')).not.toBeInTheDocument(); + appMockRender.render(); + expect(screen.queryByTestId('connector-fields-preview')).not.toBeInTheDocument(); }); it('does not show the connectors form if the user does not have read access to actions', async () => { @@ -313,16 +345,16 @@ describe('EditConnector ', () => { actions: { save: false, show: false }, }; - const result = appMockRender.render(); - expect(result.queryByTestId('edit-connector-fields-form-flex-item')).not.toBeInTheDocument(); + appMockRender.render(); + expect(screen.queryByTestId('edit-connector-fields-form-flex-item')).not.toBeInTheDocument(); }); it('does not show the connectors form if the user does not have access to cases connectors', async () => { const props = { ...defaultProps, connectors: [] }; appMockRender = createAppMockRenderer({ permissions: noConnectorsCasePermission() }); - const result = appMockRender.render(); - expect(result.queryByTestId('edit-connector-fields-form-flex-item')).not.toBeInTheDocument(); + appMockRender.render(); + expect(screen.queryByTestId('edit-connector-fields-form-flex-item')).not.toBeInTheDocument(); }); it('does not show the push button if the user does not have read access to actions', async () => { @@ -331,32 +363,45 @@ describe('EditConnector ', () => { actions: { save: false, show: false }, }; - const result = appMockRender.render(); - await waitFor(() => { - expect(result.queryByTestId('push-to-external-service')).toBe(null); - }); + appMockRender.render(); + + expect(screen.queryByTestId('push-to-external-service')).not.toBeInTheDocument(); }); it('does not show the push button if the user does not have push permissions', async () => { - appMockRender = createAppMockRenderer({ permissions: noPushCasesPermissions() }); - const result = appMockRender.render(); + usePushToServiceMock.mockReturnValue({ ...usePushToServiceMockRes, hasPushPermissions: false }); + appMockRender.render(); - await waitFor(() => { - expect(result.queryByTestId('push-to-external-service')).toBe(null); - }); + expect(screen.queryByTestId('push-to-external-service')).not.toBeInTheDocument(); + }); + + it('disable the push button when connector is invalid', async () => { + usePushToServiceMock.mockReturnValue({ ...usePushToServiceMockRes, needsToBePushed: true }); + + appMockRender.render( + + ); + + expect(await screen.findByTestId('push-to-external-service')).toBeDisabled(); }); it('does not show the push button if the user does not have access to cases actions', async () => { appMockRender = createAppMockRenderer({ permissions: noConnectorsCasePermission() }); - const result = appMockRender.render(); - await waitFor(() => { - expect(result.queryByTestId('push-to-external-service')).toBe(null); - }); + appMockRender.render(); + + expect(screen.queryByTestId('push-to-external-service')).not.toBeInTheDocument(); }); it('does not show the edit connectors pencil if the user does not have read access to actions', async () => { const props = { ...defaultProps, connectors: [] }; + appMockRender.coreStart.application.capabilities = { ...appMockRender.coreStart.application.capabilities, actions: { save: false, show: false }, @@ -364,10 +409,8 @@ describe('EditConnector ', () => { appMockRender.render(); - await waitFor(() => { - expect(screen.getByTestId('connector-edit-header')).toBeInTheDocument(); - expect(screen.queryByTestId('connector-edit-button')).not.toBeInTheDocument(); - }); + expect(await screen.findByTestId('connector-edit-header')).toBeInTheDocument(); + expect(screen.queryByTestId('connector-edit-button')).not.toBeInTheDocument(); }); it('does not show the edit connectors pencil if the user does not have access to case connectors', async () => { @@ -378,21 +421,36 @@ describe('EditConnector ', () => { appMockRender.render(); - await waitFor(() => { - expect(screen.getByTestId('connector-edit-header')).toBeInTheDocument(); - expect(screen.queryByTestId('connector-edit-button')).not.toBeInTheDocument(); - }); + expect(await screen.findByTestId('connector-edit-header')).toBeInTheDocument(); + expect(screen.queryByTestId('connector-edit-button')).not.toBeInTheDocument(); }); it('does not show the edit connectors pencil if the user does not have push permissions', async () => { const props = { ...defaultProps, connectors: [] }; - appMockRender = createAppMockRenderer({ permissions: noPushCasesPermissions() }); + usePushToServiceMock.mockReturnValue({ ...usePushToServiceMockRes, hasPushPermissions: false }); appMockRender.render(); - await waitFor(() => { - expect(screen.getByTestId('connector-edit-header')).toBeInTheDocument(); - expect(screen.queryByTestId('connector-edit-button')).toBe(null); - }); + expect(await screen.findByTestId('connector-edit-header')).toBeInTheDocument(); + expect(screen.queryByTestId('connector-edit-button')).not.toBeInTheDocument(); + }); + + it('should show the correct connector name on the push button', async () => { + const props = { + ...defaultProps, + caseData: { + ...defaultProps.caseData, + connector: { + id: 'resilient-2', + name: 'old name', + type: ConnectorTypes.resilient, + fields: null, + }, + }, + }; + + appMockRender.render(); + + expect(await screen.findByText('Update My Resilient connector incident')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx b/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx index e4d6641d6b751..d0404c089077e 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/editable_markdown_renderer.test.tsx @@ -7,8 +7,8 @@ import React from 'react'; import type { FormSchema } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { useForm, Form, FIELD_TYPES } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { waitFor, fireEvent, screen, render, act } from '@testing-library/react'; +import { FIELD_TYPES } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { waitFor, fireEvent, screen, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; import * as i18n from '../../common/translations'; @@ -16,7 +16,8 @@ import * as i18n from '../../common/translations'; const { emptyField, maxLengthField } = fieldValidators; import { EditableMarkdown } from '.'; -import { TestProviders } from '../../common/mock'; +import type { AppMockRenderer } from '../../common/mock'; +import { createAppMockRenderer } from '../../common/mock'; jest.mock('../../common/lib/kibana'); @@ -60,36 +61,12 @@ const defaultProps = { editorRef, }; -// FLAKY: https://github.com/elastic/kibana/issues/171177 -// FLAKY: https://github.com/elastic/kibana/issues/171178 -// FLAKY: https://github.com/elastic/kibana/issues/171179 -// FLAKY: https://github.com/elastic/kibana/issues/171180 -// FLAKY: https://github.com/elastic/kibana/issues/171181 -// FLAKY: https://github.com/elastic/kibana/issues/171182 -// FLAKY: https://github.com/elastic/kibana/issues/171183 -// FLAKY: https://github.com/elastic/kibana/issues/171184 -// FLAKY: https://github.com/elastic/kibana/issues/171185 -describe.skip('EditableMarkdown', () => { - const MockHookWrapperComponent: React.FC<{ testProviderProps?: unknown }> = ({ - children, - testProviderProps = {}, - }) => { - const { form } = useForm<{ content: string }>({ - defaultValue: { content }, - options: { stripEmptyFields: false }, - schema: mockSchema, - }); - - return ( - // @ts-expect-error ts upgrade v4.7.4 - -
{children}
-
- ); - }; +describe('EditableMarkdown', () => { + let appMockRender: AppMockRenderer; beforeEach(() => { jest.clearAllMocks(); + appMockRender = createAppMockRenderer(); }); afterEach(() => { @@ -97,17 +74,13 @@ describe.skip('EditableMarkdown', () => { }); it('Save button click calls onSaveContent and onChangeEditable when text area value changed', async () => { - render( - - - - ); + appMockRender.render(); - fireEvent.change(screen.getByTestId('euiMarkdownEditorTextArea'), { + fireEvent.change(await screen.findByTestId('euiMarkdownEditorTextArea'), { target: { value: newValue }, }); - userEvent.click(screen.getByTestId('editable-save-markdown')); + userEvent.click(await screen.findByTestId('editable-save-markdown')); await waitFor(() => { expect(onSaveContent).toHaveBeenCalledWith(newValue); @@ -116,13 +89,9 @@ describe.skip('EditableMarkdown', () => { }); it('Does not call onSaveContent if no change from current text', async () => { - render( - - - - ); + appMockRender.render(); - userEvent.click(screen.getByTestId('editable-save-markdown')); + userEvent.click(await screen.findByTestId('editable-save-markdown')); await waitFor(() => { expect(onChangeEditable).toHaveBeenCalledWith(defaultProps.id); @@ -131,13 +100,9 @@ describe.skip('EditableMarkdown', () => { }); it('Cancel button click calls only onChangeEditable', async () => { - render( - - - - ); + appMockRender.render(); - userEvent.click(screen.getByTestId('editable-cancel-markdown')); + userEvent.click(await screen.findByTestId('editable-cancel-markdown')); await waitFor(() => { expect(onSaveContent).not.toHaveBeenCalled(); @@ -147,60 +112,40 @@ describe.skip('EditableMarkdown', () => { describe('errors', () => { it('Shows error message and save button disabled if current text is empty', async () => { - render( - - - - ); - - userEvent.clear(screen.getByTestId('euiMarkdownEditorTextArea')); + appMockRender.render(); - userEvent.type(screen.getByTestId('euiMarkdownEditorTextArea'), ''); + userEvent.clear(await screen.findByTestId('euiMarkdownEditorTextArea')); + userEvent.paste(await screen.findByTestId('euiMarkdownEditorTextArea'), ''); - await waitFor(() => { - expect(screen.getByText('Required field')).toBeInTheDocument(); - expect(screen.getByTestId('editable-save-markdown')).toHaveProperty('disabled'); - }); + expect(await screen.findByText('Required field')).toBeInTheDocument(); + expect(await screen.findByTestId('editable-save-markdown')).toHaveProperty('disabled'); }); it('Shows error message and save button disabled if current text is of empty characters', async () => { - render( - - - - ); + appMockRender.render(); - userEvent.clear(screen.getByTestId('euiMarkdownEditorTextArea')); + userEvent.clear(await screen.findByTestId('euiMarkdownEditorTextArea')); + userEvent.paste(await screen.findByTestId('euiMarkdownEditorTextArea'), ' '); - userEvent.type(screen.getByTestId('euiMarkdownEditorTextArea'), ' '); - - await waitFor(() => { - expect(screen.getByText('Required field')).toBeInTheDocument(); - expect(screen.getByTestId('editable-save-markdown')).toHaveProperty('disabled'); - }); + expect(await screen.findByText('Required field')).toBeInTheDocument(); + expect(await screen.findByTestId('editable-save-markdown')).toHaveProperty('disabled'); }); it('Shows error message and save button disabled if current text is too long', async () => { const longComment = 'b'.repeat(maxLength + 1); - render( - - - - ); + appMockRender.render(); - const markdown = screen.getByTestId('euiMarkdownEditorTextArea'); + const markdown = await screen.findByTestId('euiMarkdownEditorTextArea'); userEvent.paste(markdown, longComment); - await waitFor(() => { - expect( - screen.getByText( - `The length of the textarea is too long. The maximum length is ${maxLength} characters.` - ) - ).toBeInTheDocument(); - expect(screen.getByTestId('editable-save-markdown')).toHaveProperty('disabled'); - }); + expect( + await screen.findByText( + `The length of the textarea is too long. The maximum length is ${maxLength} characters.` + ) + ).toBeInTheDocument(); + expect(await screen.findByTestId('editable-save-markdown')).toHaveProperty('disabled'); }); }); @@ -223,13 +168,9 @@ describe.skip('EditableMarkdown', () => { }); it('Save button click clears session storage', async () => { - const result = render( - - - - ); + appMockRender.render(); - fireEvent.change(result.getByTestId('euiMarkdownEditorTextArea'), { + fireEvent.change(await screen.findByTestId('euiMarkdownEditorTextArea'), { target: { value: newValue }, }); @@ -239,7 +180,7 @@ describe.skip('EditableMarkdown', () => { expect(sessionStorage.getItem(draftStorageKey)).toBe(newValue); - fireEvent.click(result.getByTestId(`editable-save-markdown`)); + fireEvent.click(await screen.findByTestId(`editable-save-markdown`)); await waitFor(() => { expect(onSaveContent).toHaveBeenCalledWith(newValue); @@ -249,15 +190,11 @@ describe.skip('EditableMarkdown', () => { }); it('Cancel button click clears session storage', async () => { - const result = render( - - - - ); + appMockRender.render(); expect(sessionStorage.getItem(draftStorageKey)).toBe(''); - fireEvent.change(result.getByTestId('euiMarkdownEditorTextArea'), { + fireEvent.change(await screen.findByTestId('euiMarkdownEditorTextArea'), { target: { value: newValue }, }); @@ -269,7 +206,7 @@ describe.skip('EditableMarkdown', () => { expect(sessionStorage.getItem(draftStorageKey)).toBe(newValue); }); - fireEvent.click(result.getByTestId('editable-cancel-markdown')); + fireEvent.click(await screen.findByTestId('editable-cancel-markdown')); await waitFor(() => { expect(sessionStorage.getItem(draftStorageKey)).toBe(null); @@ -282,13 +219,9 @@ describe.skip('EditableMarkdown', () => { }); it('should have session storage value same as draft comment', async () => { - const result = render( - - - - ); + appMockRender.render(); - expect(result.getByText('value set in storage')).toBeInTheDocument(); + expect(await screen.findByText('value set in storage')).toBeInTheDocument(); }); }); }); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.test.tsx index 982484f11ed47..ae0d7e39d5e1b 100644 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/alert_property_actions.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; -import { waitFor } from '@testing-library/react'; +import { waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import type { AppMockRenderer } from '../../../common/mock'; import { @@ -17,12 +17,7 @@ import { } from '../../../common/mock'; import { AlertPropertyActions } from './alert_property_actions'; -// FLAKY: https://github.com/elastic/kibana/issues/174667 -// FLAKY: https://github.com/elastic/kibana/issues/174668 -// FLAKY: https://github.com/elastic/kibana/issues/174669 -// FLAKY: https://github.com/elastic/kibana/issues/174670 -// FLAKY: https://github.com/elastic/kibana/issues/174671 -describe.skip('AlertPropertyActions', () => { +describe('AlertPropertyActions', () => { let appMock: AppMockRenderer; const props = { @@ -32,93 +27,89 @@ describe.skip('AlertPropertyActions', () => { }; beforeEach(() => { - appMock = createAppMockRenderer(); jest.clearAllMocks(); + appMock = createAppMockRenderer(); }); it('renders the correct number of actions', async () => { - const result = appMock.render(); + appMock.render(); - expect(result.getByTestId('property-actions-user-action')).toBeInTheDocument(); + expect(await screen.findByTestId('property-actions-user-action')).toBeInTheDocument(); - userEvent.click(result.getByTestId('property-actions-user-action-ellipses')); + userEvent.click(await screen.findByTestId('property-actions-user-action-ellipses')); await waitForEuiPopoverOpen(); - expect(result.getByTestId('property-actions-user-action-group').children.length).toBe(1); - expect(result.queryByTestId('property-actions-user-action-minusInCircle')).toBeInTheDocument(); + expect((await screen.findByTestId('property-actions-user-action-group')).children.length).toBe( + 1 + ); + + expect( + await screen.findByTestId('property-actions-user-action-minusInCircle') + ).toBeInTheDocument(); }); it('renders the modal info correctly for one alert', async () => { - const result = appMock.render(); + appMock.render(); - expect(result.getByTestId('property-actions-user-action')).toBeInTheDocument(); + expect(await screen.findByTestId('property-actions-user-action')).toBeInTheDocument(); - userEvent.click(result.getByTestId('property-actions-user-action-ellipses')); + userEvent.click(await screen.findByTestId('property-actions-user-action-ellipses')); await waitForEuiPopoverOpen(); - expect(result.queryByTestId('property-actions-user-action-minusInCircle')).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('property-actions-user-action-minusInCircle')); - userEvent.click(result.getByTestId('property-actions-user-action-minusInCircle')); - - await waitFor(() => { - expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); - }); + expect(await screen.findByTestId('property-actions-confirm-modal')).toBeInTheDocument(); - expect(result.getByTestId('confirmModalTitleText')).toHaveTextContent('Remove alert'); - expect(result.getByText('Remove')).toBeInTheDocument(); + expect(await screen.findByTestId('confirmModalTitleText')).toHaveTextContent('Remove alert'); + expect(await screen.findByText('Remove')).toBeInTheDocument(); }); it('renders the modal info correctly for multiple alert', async () => { - const result = appMock.render(); + appMock.render(); - expect(result.getByTestId('property-actions-user-action')).toBeInTheDocument(); + expect(await screen.findByTestId('property-actions-user-action')).toBeInTheDocument(); - userEvent.click(result.getByTestId('property-actions-user-action-ellipses')); + userEvent.click(await screen.findByTestId('property-actions-user-action-ellipses')); await waitForEuiPopoverOpen(); - expect(result.queryByTestId('property-actions-user-action-minusInCircle')).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('property-actions-user-action-minusInCircle')); - userEvent.click(result.getByTestId('property-actions-user-action-minusInCircle')); + expect(await screen.findByTestId('property-actions-confirm-modal')).toBeInTheDocument(); - await waitFor(() => { - expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); - }); - - expect(result.getByTestId('confirmModalTitleText')).toHaveTextContent('Remove alerts'); - expect(result.getByText('Remove')).toBeInTheDocument(); + expect(await screen.findByTestId('confirmModalTitleText')).toHaveTextContent('Remove alerts'); + expect(await screen.findByText('Remove')).toBeInTheDocument(); }); it('remove alerts correctly', async () => { - const result = appMock.render(); + appMock.render(); - expect(result.getByTestId('property-actions-user-action')).toBeInTheDocument(); + expect(await screen.findByTestId('property-actions-user-action')).toBeInTheDocument(); - userEvent.click(result.getByTestId('property-actions-user-action-ellipses')); + userEvent.click(await screen.findByTestId('property-actions-user-action-ellipses')); await waitForEuiPopoverOpen(); - expect(result.queryByTestId('property-actions-user-action-minusInCircle')).toBeInTheDocument(); + userEvent.click(await screen.findByTestId('property-actions-user-action-minusInCircle')); - userEvent.click(result.getByTestId('property-actions-user-action-minusInCircle')); + expect(await screen.findByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + + userEvent.click(screen.getByText('Remove')); await waitFor(() => { - expect(result.queryByTestId('property-actions-confirm-modal')).toBeInTheDocument(); + expect(props.onDelete).toHaveBeenCalled(); }); - - userEvent.click(result.getByText('Remove')); - expect(props.onDelete).toHaveBeenCalled(); }); it('does not show the property actions without delete permissions', async () => { appMock = createAppMockRenderer({ permissions: noCasesPermissions() }); - const result = appMock.render(); + appMock.render(); - expect(result.queryByTestId('property-actions-user-action')).not.toBeInTheDocument(); + expect(screen.queryByTestId('property-actions-user-action')).not.toBeInTheDocument(); }); it('does show the property actions with only delete permissions', async () => { appMock = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); - const result = appMock.render(); + appMock.render(); - expect(result.getByTestId('property-actions-user-action')).toBeInTheDocument(); + expect(await screen.findByTestId('property-actions-user-action')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx index 8cbc69e30039f..04b034a1d0a56 100644 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/registered_attachments_property_actions.test.tsx @@ -18,8 +18,7 @@ import { import { RegisteredAttachmentsPropertyActions } from './registered_attachments_property_actions'; import { AttachmentActionType } from '../../../client/attachment_framework/types'; -// FLAKY: https://github.com/elastic/kibana/issues/174384 -describe.skip('RegisteredAttachmentsPropertyActions', () => { +describe('RegisteredAttachmentsPropertyActions', () => { let appMock: AppMockRenderer; const props = { @@ -47,7 +46,7 @@ describe.skip('RegisteredAttachmentsPropertyActions', () => { 1 ); - expect(screen.queryByTestId('property-actions-user-action-trash')).toBeInTheDocument(); + expect(await screen.findByTestId('property-actions-user-action-trash')).toBeInTheDocument(); }); it('renders the modal info correctly', async () => { @@ -85,7 +84,7 @@ describe.skip('RegisteredAttachmentsPropertyActions', () => { expect(await screen.findByTestId('property-actions-confirm-modal')).toBeInTheDocument(); - userEvent.click(screen.getByText('Delete')); + userEvent.click(await screen.findByText('Delete')); await waitFor(() => { expect(props.onDelete).toHaveBeenCalled(); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx index ce4e453ecbbf1..b81f9d1448aa2 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx @@ -22,7 +22,7 @@ const initialData = { isLoading: true, }; -describe('UseGetCaseUserActionsStats', () => { +describe('useGetCaseUserActionsStats', () => { let appMockRender: AppMockRenderer; beforeEach(() => { diff --git a/x-pack/plugins/cloud_security_posture/common/schemas/csp_vulnerability_finding.ts b/x-pack/plugins/cloud_security_posture/common/schemas/csp_vulnerability_finding.ts index efe26dc6648ba..2dbab1bab77b6 100644 --- a/x-pack/plugins/cloud_security_posture/common/schemas/csp_vulnerability_finding.ts +++ b/x-pack/plugins/cloud_security_posture/common/schemas/csp_vulnerability_finding.ts @@ -87,7 +87,7 @@ export interface Vulnerability { id: string; title: string; reference: string; - severity: VulnSeverity; + severity?: VulnSeverity; cvss: { nvd: VectorScoreBase; redhat?: VectorScoreBase; diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_latest_findings_data_view.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_latest_findings_data_view.ts index c8e98703cdbf0..442330a888a50 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_latest_findings_data_view.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_latest_findings_data_view.ts @@ -9,9 +9,15 @@ import { useQuery } from '@tanstack/react-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import type { DataView } from '@kbn/data-plugin/common'; import { i18n } from '@kbn/i18n'; -import { LATEST_FINDINGS_INDEX_PATTERN } from '../../../common/constants'; +import { + LATEST_FINDINGS_INDEX_PATTERN, + LATEST_VULNERABILITIES_INDEX_PATTERN, +} from '../../../common/constants'; import { CspClientPluginStartDeps } from '../../types'; +/** + * TODO: Remove this static labels once https://github.com/elastic/kibana/issues/172615 is resolved + */ const cloudSecurityFieldLabels: Record = { 'result.evaluation': i18n.translate( 'xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel', @@ -45,6 +51,30 @@ const cloudSecurityFieldLabels: Record = { 'xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel', { defaultMessage: 'Last Checked' } ), + 'vulnerability.id': i18n.translate( + 'xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityIdColumnLabel', + { defaultMessage: 'Vulnerability' } + ), + 'vulnerability.score.base': i18n.translate( + 'xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilityScoreColumnLabel', + { defaultMessage: 'CVSS' } + ), + 'vulnerability.severity': i18n.translate( + 'xpack.csp.findings.findingsTable.findingsTableColumn.vulnerabilitySeverityColumnLabel', + { defaultMessage: 'Severity' } + ), + 'package.name': i18n.translate( + 'xpack.csp.findings.findingsTable.findingsTableColumn.packageNameColumnLabel', + { defaultMessage: 'Package' } + ), + 'package.version': i18n.translate( + 'xpack.csp.findings.findingsTable.findingsTableColumn.packageVersionColumnLabel', + { defaultMessage: 'Version' } + ), + 'package.fixed_version': i18n.translate( + 'xpack.csp.findings.findingsTable.findingsTableColumn.packageFixedVersionColumnLabel', + { defaultMessage: 'Fix Version' } + ), } as const; /** @@ -61,7 +91,13 @@ export const useLatestFindingsDataView = (dataView: string) => { throw new Error(`Data view not found [Name: {${dataView}}]`); } - if (dataView === LATEST_FINDINGS_INDEX_PATTERN) { + /** + * TODO: Remove this update logic once https://github.com/elastic/kibana/issues/172615 is resolved + */ + if ( + dataView === LATEST_FINDINGS_INDEX_PATTERN || + dataView === LATEST_VULNERABILITIES_INDEX_PATTERN + ) { let shouldUpdate = false; Object.entries(cloudSecurityFieldLabels).forEach(([field, label]) => { if ( diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index 833f941c95292..bd266c98b8015 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -49,6 +49,9 @@ export const LOCAL_STORAGE_DASHBOARD_BENCHMARK_SORT_KEY = 'cloudPosture:complianceDashboard:benchmarkSort'; export const LOCAL_STORAGE_FINDINGS_LAST_SELECTED_TAB_KEY = 'cloudPosture:findings:lastSelectedTab'; +export const LOCAL_STORAGE_VULNERABILITIES_GROUPING_KEY = 'cspLatestVulnerabilitiesGrouping'; +export const LOCAL_STORAGE_FINDINGS_GROUPING_KEY = 'cspLatestFindingsGrouping'; + export const SESSION_STORAGE_FIELDS_MODAL_SHOW_SELECTED = 'cloudPosture:fieldsModal:showSelected'; export type CloudPostureIntegrations = Record< @@ -225,3 +228,5 @@ export const NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS = 10000; export const DETECTION_ENGINE_RULES_KEY = 'detection_engine_rules'; export const DETECTION_ENGINE_ALERTS_KEY = 'detection_engine_alerts'; + +export const DEFAULT_GROUPING_TABLE_HEIGHT = 512; diff --git a/x-pack/plugins/cloud_security_posture/public/common/contexts/data_view_context.ts b/x-pack/plugins/cloud_security_posture/public/common/contexts/data_view_context.ts new file mode 100644 index 0000000000000..a14928e7133e3 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/common/contexts/data_view_context.ts @@ -0,0 +1,29 @@ +/* + * 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 { createContext, useContext } from 'react'; +import { DataView } from '@kbn/data-views-plugin/common'; + +interface DataViewContextValue { + dataView: DataView; + dataViewRefetch?: () => void; + dataViewIsRefetching?: boolean; +} + +export const DataViewContext = createContext(undefined); + +/** + * Retrieve context's properties + */ +export const useDataViewContext = (): DataViewContextValue => { + const contextValue = useContext(DataViewContext); + + if (!contextValue) { + throw new Error('useDataViewContext can only be used within DataViewContext provider'); + } + + return contextValue; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_base_es_query.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_base_es_query.ts index 4adffa100e48c..9d5f5f2bf268d 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_base_es_query.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_base_es_query.ts @@ -5,10 +5,12 @@ * 2.0. */ +import { DataView } from '@kbn/data-views-plugin/common'; import { buildEsQuery, EsQueryConfig } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import { useEffect, useMemo } from 'react'; -import { FindingsBaseESQueryConfig, FindingsBaseProps, FindingsBaseURLQuery } from '../../types'; +import { useDataViewContext } from '../../contexts/data_view_context'; +import { FindingsBaseESQueryConfig, FindingsBaseURLQuery } from '../../types'; import { useKibana } from '../use_kibana'; const getBaseQuery = ({ @@ -16,7 +18,10 @@ const getBaseQuery = ({ query, filters, config, -}: FindingsBaseURLQuery & FindingsBaseProps & FindingsBaseESQueryConfig) => { +}: FindingsBaseURLQuery & + FindingsBaseESQueryConfig & { + dataView: DataView; + }) => { try { return { query: buildEsQuery(dataView, query, filters, config), // will throw for malformed query @@ -30,11 +35,10 @@ const getBaseQuery = ({ }; export const useBaseEsQuery = ({ - dataView, filters = [], query, nonPersistedFilters, -}: FindingsBaseURLQuery & FindingsBaseProps) => { +}: FindingsBaseURLQuery) => { const { notifications: { toasts }, data: { @@ -42,6 +46,7 @@ export const useBaseEsQuery = ({ }, uiSettings, } = useKibana().services; + const { dataView } = useDataViewContext(); const allowLeadingWildcards = uiSettings.get('query:allowLeadingWildcards'); const config: EsQueryConfig = useMemo(() => ({ allowLeadingWildcards }), [allowLeadingWildcards]); const baseEsQuery = useMemo( diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_cloud_posture_data_table.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_cloud_posture_data_table.ts index ae21f45c7a4e8..03517383ecc3f 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_cloud_posture_data_table.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_data_table/use_cloud_posture_data_table.ts @@ -5,7 +5,6 @@ * 2.0. */ import { Dispatch, SetStateAction, useCallback } from 'react'; -import { type DataView } from '@kbn/data-views-plugin/common'; import { BoolQuery, Filter } from '@kbn/es-query'; import { CriteriaWithPagination } from '@elastic/eui'; import { DataTableRecord } from '@kbn/discover-utils/types'; @@ -46,13 +45,11 @@ export interface CloudPostureDataTableResult { */ export const useCloudPostureDataTable = ({ defaultQuery = getDefaultQuery, - dataView, paginationLocalStorageKey, columnsLocalStorageKey, nonPersistedFilters, }: { defaultQuery?: (params: FindingsBaseURLQuery) => FindingsBaseURLQuery; - dataView: DataView; paginationLocalStorageKey: string; columnsLocalStorageKey?: string; nonPersistedFilters?: Filter[]; @@ -116,7 +113,6 @@ export const useCloudPostureDataTable = ({ * Page URL query to ES query */ const baseEsQuery = useBaseEsQuery({ - dataView, filters: urlQuery.filters, query: urlQuery.query, ...(nonPersistedFilters ? { nonPersistedFilters } : {}), diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/index.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/index.ts deleted file mode 100644 index 06ad2776fb305..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/index.ts +++ /dev/null @@ -1,8 +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 * from './use_cloud_posture_table'; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/use_cloud_posture_table.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/use_cloud_posture_table.ts deleted file mode 100644 index d06e29a95e46d..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/use_cloud_posture_table.ts +++ /dev/null @@ -1,155 +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 { Dispatch, SetStateAction, useCallback } from 'react'; -import { type DataView } from '@kbn/data-views-plugin/common'; -import { BoolQuery } from '@kbn/es-query'; -import { CriteriaWithPagination } from '@elastic/eui'; -import { DataTableRecord } from '@kbn/discover-utils/types'; -import { useUrlQuery } from '../use_url_query'; -import { usePageSize } from '../use_page_size'; -import { getDefaultQuery, useBaseEsQuery, usePersistedQuery } from './utils'; -import { LOCAL_STORAGE_DATA_TABLE_COLUMNS_KEY } from '../../constants'; - -export interface CloudPostureTableResult { - // TODO: Remove any when all finding tables are converted to CloudSecurityDataTable - setUrlQuery: (query: any) => void; - // TODO: Remove any when all finding tables are converted to CloudSecurityDataTable - sort: any; - // TODO: Remove any when all finding tables are converted to CloudSecurityDataTable - filters: any[]; - query?: { bool: BoolQuery }; - queryError?: Error; - pageIndex: number; - // TODO: remove any, urlQuery is an object with query fields but we also add custom fields to it, need to assert usages - urlQuery: any; - setTableOptions: (options: CriteriaWithPagination) => void; - // TODO: Remove any when all finding tables are converted to CloudSecurityDataTable - handleUpdateQuery: (query: any) => void; - pageSize: number; - setPageSize: Dispatch>; - onChangeItemsPerPage: (newPageSize: number) => void; - onChangePage: (newPageIndex: number) => void; - // TODO: Remove any when all finding tables are converted to CloudSecurityDataTable - onSort: (sort: any) => void; - onResetFilters: () => void; - columnsLocalStorageKey: string; - getRowsFromPages: (data: Array<{ page: DataTableRecord[] }> | undefined) => DataTableRecord[]; -} - -/** - * @deprecated will be replaced by useCloudPostureDataTable - */ -export const useCloudPostureTable = ({ - defaultQuery = getDefaultQuery, - dataView, - paginationLocalStorageKey, - columnsLocalStorageKey, -}: { - // TODO: Remove any when all finding tables are converted to CloudSecurityDataTable - defaultQuery?: (params: any) => any; - dataView: DataView; - paginationLocalStorageKey: string; - columnsLocalStorageKey?: string; -}): CloudPostureTableResult => { - const getPersistedDefaultQuery = usePersistedQuery(defaultQuery); - const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); - const { pageSize, setPageSize } = usePageSize(paginationLocalStorageKey); - - const onChangeItemsPerPage = useCallback( - (newPageSize) => { - setPageSize(newPageSize); - setUrlQuery({ - pageIndex: 0, - pageSize: newPageSize, - }); - }, - [setPageSize, setUrlQuery] - ); - - const onResetFilters = useCallback(() => { - setUrlQuery({ - pageIndex: 0, - filters: [], - query: { - query: '', - language: 'kuery', - }, - }); - }, [setUrlQuery]); - - const onChangePage = useCallback( - (newPageIndex) => { - setUrlQuery({ - pageIndex: newPageIndex, - }); - }, - [setUrlQuery] - ); - - const onSort = useCallback( - (sort) => { - setUrlQuery({ - sort, - }); - }, - [setUrlQuery] - ); - - const setTableOptions = useCallback( - ({ page, sort }) => { - setPageSize(page.size); - setUrlQuery({ - sort, - pageIndex: page.index, - }); - }, - [setUrlQuery, setPageSize] - ); - - /** - * Page URL query to ES query - */ - const baseEsQuery = useBaseEsQuery({ - dataView, - filters: urlQuery.filters, - query: urlQuery.query, - }); - - const handleUpdateQuery = useCallback( - (query) => { - setUrlQuery({ ...query, pageIndex: 0 }); - }, - [setUrlQuery] - ); - - const getRowsFromPages = (data: Array<{ page: DataTableRecord[] }> | undefined) => - data - ?.map(({ page }: { page: DataTableRecord[] }) => { - return page; - }) - .flat() || []; - - return { - setUrlQuery, - sort: urlQuery.sort, - filters: urlQuery.filters, - query: baseEsQuery.query, - queryError: baseEsQuery.error, - pageIndex: urlQuery.pageIndex, - urlQuery, - setTableOptions, - handleUpdateQuery, - pageSize, - setPageSize, - onChangeItemsPerPage, - onChangePage, - onSort, - onResetFilters, - columnsLocalStorageKey: columnsLocalStorageKey || LOCAL_STORAGE_DATA_TABLE_COLUMNS_KEY, - getRowsFromPages, - }; -}; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/utils.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/utils.ts deleted file mode 100644 index a74abccba1e18..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_cloud_posture_table/utils.ts +++ /dev/null @@ -1,124 +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 { useEffect, useCallback, useMemo } from 'react'; -import { buildEsQuery, EsQueryConfig } from '@kbn/es-query'; -import type { EuiBasicTableProps, Pagination } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { type Query } from '@kbn/es-query'; -import { useKibana } from '../use_kibana'; -import type { - FindingsBaseESQueryConfig, - FindingsBaseProps, - FindingsBaseURLQuery, -} from '../../types'; - -const getBaseQuery = ({ - dataView, - query, - filters, - config, -}: FindingsBaseURLQuery & FindingsBaseProps & FindingsBaseESQueryConfig) => { - try { - return { - query: buildEsQuery(dataView, query, filters, config), // will throw for malformed query - }; - } catch (error) { - return { - query: undefined, - error: error instanceof Error ? error : new Error('Unknown Error'), - }; - } -}; - -type TablePagination = NonNullable['pagination']>; - -export const getPaginationTableParams = ( - params: TablePagination & Pick, 'pageIndex' | 'pageSize'>, - pageSizeOptions = [10, 25, 100], - showPerPageOptions = true -): Required => ({ - ...params, - pageSizeOptions, - showPerPageOptions, -}); - -export const getPaginationQuery = ({ - pageIndex, - pageSize, -}: Required>) => ({ - from: pageIndex * pageSize, - size: pageSize, -}); - -export const useBaseEsQuery = ({ - dataView, - filters, - query, -}: FindingsBaseURLQuery & FindingsBaseProps) => { - const { - notifications: { toasts }, - data: { - query: { filterManager, queryString }, - }, - uiSettings, - } = useKibana().services; - const allowLeadingWildcards = uiSettings.get('query:allowLeadingWildcards'); - const config: EsQueryConfig = useMemo(() => ({ allowLeadingWildcards }), [allowLeadingWildcards]); - const baseEsQuery = useMemo( - () => getBaseQuery({ dataView, filters, query, config }), - [dataView, filters, query, config] - ); - - /** - * Sync filters with the URL query - */ - useEffect(() => { - filterManager.setAppFilters(filters); - queryString.setQuery(query); - }, [filters, filterManager, queryString, query]); - - const handleMalformedQueryError = () => { - const error = baseEsQuery.error; - if (error) { - toasts.addError(error, { - title: i18n.translate('xpack.csp.findings.search.queryErrorToastMessage', { - defaultMessage: 'Query Error', - }), - toastLifeTimeMs: 1000 * 5, - }); - } - }; - - useEffect(handleMalformedQueryError, [baseEsQuery.error, toasts]); - - return baseEsQuery; -}; - -export const usePersistedQuery = (getter: ({ filters, query }: FindingsBaseURLQuery) => T) => { - const { - data: { - query: { filterManager, queryString }, - }, - } = useKibana().services; - - return useCallback( - () => - getter({ - filters: filterManager.getAppFilters(), - query: queryString.getQuery() as Query, - }), - [getter, filterManager, queryString] - ); -}; - -export const getDefaultQuery = ({ query, filters }: any): any => ({ - query, - filters, - sort: { field: '@timestamp', direction: 'desc' }, - pageIndex: 0, -}); diff --git a/x-pack/plugins/cloud_security_posture/public/common/types.ts b/x-pack/plugins/cloud_security_posture/public/common/types.ts index ac483445407e4..d402ea2939062 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/types.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/types.ts @@ -5,7 +5,6 @@ * 2.0. */ import type { Criteria } from '@elastic/eui'; -import type { DataView } from '@kbn/data-views-plugin/common'; import type { BoolQuery, Filter, Query, EsQueryConfig } from '@kbn/es-query'; import { CspFinding } from '../../common/schemas/csp_finding'; @@ -20,12 +19,6 @@ export interface FindingsBaseURLQuery { nonPersistedFilters?: Filter[]; } -export interface FindingsBaseProps { - dataView: DataView; - dataViewRefetch?: () => void; - dataViewIsRefetching?: boolean; -} - export interface FindingsBaseESQueryConfig { config: EsQueryConfig; } diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.test.tsx index 7ddbe28a7da07..0fba4f27ed23a 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.test.tsx @@ -6,6 +6,7 @@ */ import { render } from '@testing-library/react'; import React from 'react'; +import { DataViewContext } from '../../common/contexts/data_view_context'; import { TestProvider } from '../../test/test_provider'; import { CloudSecurityDataTable, CloudSecurityDataTableProps } from './cloud_security_data_table'; @@ -47,7 +48,6 @@ const mockCloudPostureDataTable = { const renderDataTable = (props: Partial = {}) => { const defaultProps: CloudSecurityDataTableProps = { - dataView: mockDataView, isLoading: false, defaultColumns: mockDefaultColumns, rows: [], @@ -60,7 +60,9 @@ const renderDataTable = (props: Partial = {}) => { return render( - + + + ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx index 3f0c3da73a986..53ed78b6e9b78 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx @@ -6,7 +6,6 @@ */ import React, { useState, useMemo } from 'react'; import { UnifiedDataTableSettings, useColumns } from '@kbn/unified-data-table'; -import { type DataView } from '@kbn/data-views-plugin/common'; import { UnifiedDataTable, DataLoadingState } from '@kbn/unified-data-table'; import { CellActionsProvider } from '@kbn/cell-actions'; import { SHOW_MULTIFIELDS, SORT_DEFAULT_ORDER_SETTING } from '@kbn/discover-utils'; @@ -22,6 +21,7 @@ import { EmptyState } from '../empty_state'; import { MAX_FINDINGS_TO_LOAD } from '../../common/constants'; import { useStyles } from './use_styles'; import { AdditionalControls } from './additional_controls'; +import { useDataViewContext } from '../../common/contexts/data_view_context'; export interface CloudSecurityDefaultColumn { id: string; @@ -41,7 +41,6 @@ const useNewFieldsApi = true; const controlColumnIds = ['openDetails']; export interface CloudSecurityDataTableProps { - dataView: DataView; isLoading: boolean; defaultColumns: CloudSecurityDefaultColumn[]; rows: DataTableRecord[]; @@ -77,21 +76,10 @@ export interface CloudSecurityDataTableProps { /** * Height override for the data grid. */ - height?: number; - /** - * Callback Function when the DataView field is edited. - * Required to enable editing of the field in the data grid. - */ - dataViewRefetch?: () => void; - /** - * Flag to indicate if the data view is refetching. - * Required for smoothing re-rendering the DataTable columns. - */ - dataViewIsRefetching?: boolean; + height?: number | string; } export const CloudSecurityDataTable = ({ - dataView, isLoading, defaultColumns, rows, @@ -103,8 +91,6 @@ export const CloudSecurityDataTable = ({ customCellRenderer, groupSelectorComponent, height, - dataViewRefetch, - dataViewIsRefetching, ...rest }: CloudSecurityDataTableProps) => { const { @@ -133,6 +119,8 @@ export const CloudSecurityDataTable = ({ } ); + const { dataView, dataViewIsRefetching, dataViewRefetch } = useDataViewContext(); + const [expandedDoc, setExpandedDoc] = useState(undefined); const renderDocumentView = (hit: DataTableRecord) => @@ -245,7 +233,7 @@ export const CloudSecurityDataTable = ({ // Change the height of the grid to fit the page // If there are filters, leave space for the filter bar // Todo: Replace this component with EuiAutoSizer - height: height ?? `calc(100vh - ${filters?.length > 0 ? 443 : 403}px)`, + height: height ?? `calc(100vh - ${filters?.length > 0 ? 454 : 414}px)`, }; const rowHeightState = 0; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/fields_selector/fields_selector_table.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/fields_selector/fields_selector_table.tsx index bae971749bc78..0afd4332c41db 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/fields_selector/fields_selector_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/fields_selector/fields_selector_table.tsx @@ -73,7 +73,7 @@ export const FieldsSelectorTable = ({ return dataView.fields .getAll() .filter((field) => { - return field.name !== '@timestamp' && field.name !== '_index' && field.visualizable; + return field.name !== '_index' && field.visualizable; }) .map((field) => ({ id: field.name, diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/index.ts b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/index.ts index 35a321d06119d..84353541e8ad8 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/index.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/index.ts @@ -7,3 +7,6 @@ export { useCloudSecurityGrouping } from './use_cloud_security_grouping'; export { CloudSecurityGrouping } from './cloud_security_grouping'; +export { firstNonNullValue } from './utils/first_non_null_value'; +export { NullGroup } from './null_group'; +export { LoadingGroup } from './loading_group'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/loading_group.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/loading_group.tsx new file mode 100644 index 0000000000000..8774095be6755 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/loading_group.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiSkeletonTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; + +export const LoadingGroup = () => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/null_group.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/null_group.tsx new file mode 100644 index 0000000000000..bf06d15e61a2a --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/null_group.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFlexGroup, EuiIconTip } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; + +export const NullGroup = ({ + title, + field, + unit, +}: { + title: string; + field: string; + unit: string; +}) => { + return ( + + {title} + + + + + ), + field: {field}, + unit, + }} + /> + + } + position="right" + /> + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/use_cloud_security_grouping.ts b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/use_cloud_security_grouping.ts index c59d382144524..23fd8267e5d76 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/use_cloud_security_grouping.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/use_cloud_security_grouping.ts @@ -19,7 +19,6 @@ import { FindingsBaseURLQuery } from '../../common/types'; import { useBaseEsQuery, usePersistedQuery } from '../../common/hooks/use_cloud_posture_data_table'; const DEFAULT_PAGE_SIZE = 10; -const GROUPING_ID = 'cspLatestFindings'; const MAX_GROUPING_LEVELS = 1; /* @@ -33,6 +32,7 @@ export const useCloudSecurityGrouping = ({ unit, groupPanelRenderer, groupStatsRenderer, + groupingLocalStorageKey, }: { dataView: DataView; groupingTitle: string; @@ -41,6 +41,7 @@ export const useCloudSecurityGrouping = ({ unit: (count: number) => string; groupPanelRenderer?: GroupPanelRenderer; groupStatsRenderer?: GroupStatsRenderer; + groupingLocalStorageKey: string; }) => { const getPersistedDefaultQuery = usePersistedQuery(getDefaultQuery); const { urlQuery, setUrlQuery } = useUrlQuery(getPersistedDefaultQuery); @@ -48,7 +49,6 @@ export const useCloudSecurityGrouping = ({ const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE); const { query, error } = useBaseEsQuery({ - dataView, filters: urlQuery.filters, query: urlQuery.query, }); @@ -69,7 +69,7 @@ export const useCloudSecurityGrouping = ({ }, defaultGroupingOptions, fields: dataView.fields, - groupingId: GROUPING_ID, + groupingId: groupingLocalStorageKey, maxGroupingLevels: MAX_GROUPING_LEVELS, title: groupingTitle, onGroupChange: () => { diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/utils/first_non_null_value.test.ts b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/utils/first_non_null_value.test.ts new file mode 100644 index 0000000000000..5c332e6924ca1 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/utils/first_non_null_value.test.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 { firstNonNullValue } from './first_non_null_value'; + +describe('firstNonNullValue', () => { + it('returns the value itself for non-null single value', () => { + expect(firstNonNullValue(5)).toBe(5); + }); + + it('returns undefined for a null single value', () => { + expect(firstNonNullValue(null)).toBeUndefined(); + }); + + it('returns undefined for an array of all null values', () => { + expect(firstNonNullValue([null, null, null])).toBeUndefined(); + }); + + it('returns the first non-null value in an array of mixed values', () => { + expect(firstNonNullValue([null, 7, 8])).toBe(7); + }); + + it('returns the first value in an array of all non-null values', () => { + expect(firstNonNullValue([3, 4, 5])).toBe(3); + }); + + it('returns undefined for an empty array', () => { + expect(firstNonNullValue([])).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/utils/first_non_null_value.ts b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/utils/first_non_null_value.ts new file mode 100644 index 0000000000000..a8c5da0500e8a --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_grouping/utils/first_non_null_value.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 { ECSField } from '@kbn/securitysolution-grouping/src'; + +/** + * Return first non-null value. If the field contains an array, this will return the first value that isn't null. If the field isn't an array it'll be returned unless it's null. + */ +export function firstNonNullValue(valueOrCollection: ECSField): T | undefined { + if (valueOrCollection === null) { + return undefined; + } else if (Array.isArray(valueOrCollection)) { + for (const value of valueOrCollection) { + if (value !== null) { + return value; + } + } + } else { + return valueOrCollection; + } +} diff --git a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx b/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx index 20b1326d65526..ff8924833a294 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx @@ -14,15 +14,16 @@ import { VulnSeverity } from '../../common/types_old'; import { VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ } from './test_subjects'; interface CVSScoreBadgeProps { - score: float; + score?: float; version?: string; } interface SeverityStatusBadgeProps { - severity: VulnSeverity; + severity?: VulnSeverity; } export const CVSScoreBadge = ({ score, version }: CVSScoreBadgeProps) => { + if (!score) return null; const color = getCvsScoreColor(score); const versionDisplay = version ? `v${version.split('.')[0]}` : null; return ( @@ -56,6 +57,7 @@ export const CVSScoreBadge = ({ score, version }: CVSScoreBadgeProps) => { }; export const SeverityStatusBadge = ({ severity }: SeverityStatusBadgeProps) => { + if (!severity) return null; const color = getSeverityStatusColor(severity); return ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx index 7e8bbfeedb832..60de443228281 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.tsx @@ -14,8 +14,8 @@ import { NoFindingsStates } from '../../components/no_findings_states'; import { CloudPosturePage } from '../../components/cloud_posture_page'; import { useLatestFindingsDataView } from '../../common/api/use_latest_findings_data_view'; import { cloudPosturePages, findingsNavigation } from '../../common/navigation/constants'; -import { FindingsByResourceContainer } from './latest_findings_by_resource/findings_by_resource_container'; import { LatestFindingsContainer } from './latest_findings/latest_findings_container'; +import { DataViewContext } from '../../common/contexts/data_view_context'; export const Configurations = () => { const location = useLocation(); @@ -31,6 +31,12 @@ export const Configurations = () => { if (!hasConfigurationFindings) return ; + const dataViewContextValue = { + dataView: dataViewQuery.data!, + dataViewRefetch: dataViewQuery.refetch, + dataViewIsRefetching: dataViewQuery.isRefetching, + }; + return ( @@ -50,18 +56,12 @@ export const Configurations = () => { path={findingsNavigation.findings_default.path} render={() => ( - + + + )} /> - } - /> } /> diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts index e2e4585906bae..3d8200a144bd5 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/constants.ts @@ -77,8 +77,6 @@ export const groupingTitle = i18n.translate('xpack.csp.findings.latestFindings.g defaultMessage: 'Group findings by', }); -export const DEFAULT_TABLE_HEIGHT = 512; - export const getDefaultQuery = ({ query, filters, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx index e070847b6df55..11c60718b29f8 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_container.tsx @@ -4,40 +4,29 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useCallback } from 'react'; +import React from 'react'; import { Filter } from '@kbn/es-query'; import { EuiSpacer } from '@elastic/eui'; +import { DEFAULT_GROUPING_TABLE_HEIGHT } from '../../../common/constants'; import { EmptyState } from '../../../components/empty_state'; import { CloudSecurityGrouping } from '../../../components/cloud_security_grouping'; -import type { FindingsBaseProps } from '../../../common/types'; import { FindingsSearchBar } from '../layout/findings_search_bar'; -import { DEFAULT_TABLE_HEIGHT } from './constants'; import { useLatestFindingsGrouping } from './use_latest_findings_grouping'; import { LatestFindingsTable } from './latest_findings_table'; import { groupPanelRenderer, groupStatsRenderer } from './latest_findings_group_renderer'; import { FindingsDistributionBar } from '../layout/findings_distribution_bar'; import { ErrorCallout } from '../layout/error_callout'; -export const LatestFindingsContainer = ({ - dataView, - dataViewRefetch, - dataViewIsRefetching, -}: FindingsBaseProps) => { - const renderChildComponent = useCallback( - (groupFilters: Filter[]) => { - return ( - - ); - }, - [dataView, dataViewIsRefetching, dataViewRefetch] - ); +export const LatestFindingsContainer = () => { + const renderChildComponent = (groupFilters: Filter[]) => { + return ( + + ); + }; const { isGroupSelected, @@ -57,12 +46,12 @@ export const LatestFindingsContainer = ({ onDistributionBarClick, totalFailedFindings, isEmptyResults, - } = useLatestFindingsGrouping({ dataView, groupPanelRenderer, groupStatsRenderer }); + } = useLatestFindingsGrouping({ groupPanelRenderer, groupStatsRenderer }); if (error || isEmptyResults) { return ( <> - + {error && } {isEmptyResults && } @@ -72,7 +61,7 @@ export const LatestFindingsContainer = ({ if (isGroupSelected) { return ( <> - +
- - + + ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx index d0684452fb23a..fe8536eaf0f69 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx @@ -8,23 +8,20 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem, - EuiIconTip, - EuiSkeletonTitle, EuiText, EuiTextBlockTruncate, EuiToolTip, useEuiTheme, } from '@elastic/eui'; import { css } from '@emotion/react'; -import { - ECSField, - GroupPanelRenderer, - RawBucket, - StatRenderer, -} from '@kbn/securitysolution-grouping/src'; +import { GroupPanelRenderer, RawBucket, StatRenderer } from '@kbn/securitysolution-grouping/src'; import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { + NullGroup, + LoadingGroup, + firstNonNullValue, +} from '../../../components/cloud_security_grouping'; import { getAbbreviatedNumber } from '../../../common/utils/get_abbreviated_number'; import { CISBenchmarkIcon } from '../../../components/cis_benchmark_icon'; import { ComplianceScoreBar } from '../../../components/compliance_score_bar'; @@ -32,67 +29,6 @@ import { FindingsGroupingAggregation } from './use_grouped_findings'; import { GROUPING_OPTIONS, NULL_GROUPING_MESSAGES, NULL_GROUPING_UNIT } from './constants'; import { FINDINGS_GROUPING_COUNTER } from '../test_subjects'; -/** - * Return first non-null value. If the field contains an array, this will return the first value that isn't null. If the field isn't an array it'll be returned unless it's null. - */ -export function firstNonNullValue(valueOrCollection: ECSField): T | undefined { - if (valueOrCollection === null) { - return undefined; - } else if (Array.isArray(valueOrCollection)) { - for (const value of valueOrCollection) { - if (value !== null) { - return value; - } - } - } else { - return valueOrCollection; - } -} - -const NullGroupComponent = ({ - title, - field, - unit = NULL_GROUPING_UNIT, -}: { - title: string; - field: string; - unit?: string; -}) => { - return ( - - {title} - - - - - ), - field: {field}, - unit, - }} - /> - - } - position="right" - /> - - ); -}; - export const groupPanelRenderer: GroupPanelRenderer = ( selectedGroup, bucket, @@ -100,20 +36,18 @@ export const groupPanelRenderer: GroupPanelRenderer isLoading ) => { if (isLoading) { - return ( - - - - ); + return ; } const benchmarkId = firstNonNullValue(bucket.benchmarkId?.buckets?.[0]?.key); + + const renderNullGroup = (title: string) => ( + + ); + switch (selectedGroup) { case GROUPING_OPTIONS.RESOURCE_NAME: return nullGroupMessage ? ( - + renderNullGroup(NULL_GROUPING_MESSAGES.RESOURCE_NAME) ) : ( @@ -146,7 +80,7 @@ export const groupPanelRenderer: GroupPanelRenderer ); case GROUPING_OPTIONS.RULE_NAME: return nullGroupMessage ? ( - + renderNullGroup(NULL_GROUPING_MESSAGES.RULE_NAME) ) : ( @@ -168,10 +102,7 @@ export const groupPanelRenderer: GroupPanelRenderer ); case GROUPING_OPTIONS.CLOUD_ACCOUNT_NAME: return nullGroupMessage ? ( - + renderNullGroup(NULL_GROUPING_MESSAGES.CLOUD_ACCOUNT_NAME) ) : ( {benchmarkId && ( @@ -200,10 +131,7 @@ export const groupPanelRenderer: GroupPanelRenderer ); case GROUPING_OPTIONS.ORCHESTRATOR_CLUSTER_NAME: return nullGroupMessage ? ( - + renderNullGroup(NULL_GROUPING_MESSAGES.ORCHESTRATOR_CLUSTER_NAME) ) : ( {benchmarkId && ( @@ -232,7 +160,7 @@ export const groupPanelRenderer: GroupPanelRenderer ); default: return nullGroupMessage ? ( - + renderNullGroup(NULL_GROUPING_MESSAGES.DEFAULT) ) : ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx index 3adb10259871d..7f215c4d49f99 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx @@ -10,7 +10,6 @@ import { DataTableRecord } from '@kbn/discover-utils/types'; import { i18n } from '@kbn/i18n'; import { EuiDataGridCellValueElementProps, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React from 'react'; -import { FindingsBaseProps } from '../../../common/types'; import * as TEST_SUBJECTS from '../test_subjects'; import { FindingsDistributionBar } from '../layout/findings_distribution_bar'; import { ErrorCallout } from '../layout/error_callout'; @@ -22,14 +21,12 @@ import { CspEvaluationBadge } from '../../../components/csp_evaluation_badge'; import { CspFinding } from '../../../../common/schemas/csp_finding'; import { FindingsRuleFlyout } from '../findings_flyout/findings_flyout'; -type LatestFindingsTableProps = FindingsBaseProps & { +interface LatestFindingsTableProps { groupSelectorComponent?: JSX.Element; height?: number; showDistributionBar?: boolean; nonPersistedFilters?: Filter[]; - dataViewRefetch?: () => void; - dataViewIsRefetching?: boolean; -}; +} /** * Type Guard for checking if the given source is a CspFinding @@ -84,13 +81,10 @@ const customCellRenderer = (rows: DataTableRecord[]) => ({ }); export const LatestFindingsTable = ({ - dataView, groupSelectorComponent, height, showDistributionBar = true, nonPersistedFilters, - dataViewRefetch, - dataViewIsRefetching, }: LatestFindingsTableProps) => { const { cloudPostureDataTable, @@ -104,7 +98,6 @@ export const LatestFindingsTable = ({ canShowDistributionBar, onDistributionBarClick, } = useLatestFindingsTable({ - dataView, getDefaultQuery, nonPersistedFilters, showDistributionBar, @@ -132,7 +125,6 @@ export const LatestFindingsTable = ({ )} )} diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts index 5584b1eae08a6..9968bb9c414bf 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts @@ -29,6 +29,7 @@ import { buildMutedRulesFilter } from '../../../../common/utils/rules_states'; interface UseFindingsOptions extends FindingsBaseEsQuery { sort: string[][]; enabled: boolean; + pageSize: number; } export interface FindingsGroupByNoneQuery { @@ -76,7 +77,7 @@ export const getFindingsQuery = ( must_not: mutedRulesFilterQuery, }, }, - ...(pageParam ? { search_after: pageParam } : {}), + ...(pageParam ? { from: pageParam } : {}), }; }; @@ -125,6 +126,12 @@ export const useLatestFindings = (options: UseFindingsOptions) => { } = useKibana().services; const { data: rulesStates } = useGetCspBenchmarkRulesStatesApi(); + /** + * We're using useInfiniteQuery in this case to allow the user to fetch more data (if available and up to 10k) + * useInfiniteQuery differs from useQuery because it accumulates and caches a chunk of data from the previous fetches into an array + * it uses the getNextPageParam to know if there are more pages to load and retrieve the position of + * the last loaded record to be used as a from parameter to fetch the next chunk of data. + */ return useInfiniteQuery( ['csp_findings', { params: options }], async ({ pageParam }) => { @@ -149,9 +156,11 @@ export const useLatestFindings = (options: UseFindingsOptions) => { enabled: options.enabled && !!rulesStates, keepPreviousData: true, onError: (err: Error) => showErrorToast(toasts, err), - getNextPageParam: (lastPage) => { - if (lastPage.page.length === 0) return undefined; - return lastPage.page[lastPage.page.length - 1].raw.sort; + getNextPageParam: (lastPage, allPages) => { + if (lastPage.page.length < options.pageSize) { + return undefined; + } + return allPages.length * options.pageSize; }, } ); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx index 7b1f10c406e15..d2386bbdd3493 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx @@ -14,7 +14,8 @@ import { parseGroupingQuery, } from '@kbn/securitysolution-grouping/src'; import { useMemo } from 'react'; -import { DataView } from '@kbn/data-views-plugin/common'; +import { LOCAL_STORAGE_FINDINGS_GROUPING_KEY } from '../../../common/constants'; +import { useDataViewContext } from '../../../common/contexts/data_view_context'; import { Evaluation } from '../../../../common/types_old'; import { LATEST_FINDINGS_RETENTION_POLICY } from '../../../../common/constants'; import { @@ -124,14 +125,14 @@ export const isFindingsRootGroupingAggregation = ( * for the findings page */ export const useLatestFindingsGrouping = ({ - dataView, groupPanelRenderer, groupStatsRenderer, }: { - dataView: DataView; groupPanelRenderer?: GroupPanelRenderer; groupStatsRenderer?: GroupStatsRenderer; }) => { + const { dataView } = useDataViewContext(); + const { activePageIndex, grouping, @@ -154,6 +155,7 @@ export const useLatestFindingsGrouping = ({ unit: FINDINGS_UNIT, groupPanelRenderer, groupStatsRenderer, + groupingLocalStorageKey: LOCAL_STORAGE_FINDINGS_GROUPING_KEY, }); const { data: rulesStates } = useGetCspBenchmarkRulesStatesApi(); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_table.tsx index b60eefac2ac81..a2c5ad544dadb 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_table.tsx @@ -5,9 +5,9 @@ * 2.0. */ -import { DataView } from '@kbn/data-views-plugin/common'; import { Filter } from '@kbn/es-query'; import { useMemo } from 'react'; +import { useDataViewContext } from '../../../common/contexts/data_view_context'; import { FindingsBaseURLQuery } from '../../../common/types'; import { Evaluation } from '../../../../common/types_old'; import { LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY } from '../../../common/constants'; @@ -18,25 +18,25 @@ import { useLatestFindings } from './use_latest_findings'; const columnsLocalStorageKey = 'cloudPosture:latestFindings:columns'; export const useLatestFindingsTable = ({ - dataView, getDefaultQuery, nonPersistedFilters, showDistributionBar, }: { - dataView: DataView; getDefaultQuery: (params: FindingsBaseURLQuery) => FindingsBaseURLQuery; nonPersistedFilters?: Filter[]; showDistributionBar?: boolean; }) => { + const { dataView } = useDataViewContext(); + const cloudPostureDataTable = useCloudPostureDataTable({ - dataView, paginationLocalStorageKey: LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY, columnsLocalStorageKey, defaultQuery: getDefaultQuery, nonPersistedFilters, }); - const { query, sort, queryError, setUrlQuery, filters, getRowsFromPages } = cloudPostureDataTable; + const { query, sort, queryError, setUrlQuery, filters, getRowsFromPages, pageSize } = + cloudPostureDataTable; const { data, @@ -47,6 +47,7 @@ export const useLatestFindingsTable = ({ query, sort, enabled: !queryError, + pageSize, }); const rows = useMemo(() => getRowsFromPages(data?.pages), [data?.pages, getRowsFromPages]); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_container.tsx deleted file mode 100644 index 85095b149bce4..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_container.tsx +++ /dev/null @@ -1,189 +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 { Routes, Route } from '@kbn/shared-ux-router'; -import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; -import type { Evaluation } from '../../../../common/types_old'; -import { FindingsSearchBar } from '../layout/findings_search_bar'; -import * as TEST_SUBJECTS from '../test_subjects'; -import { usePageSlice } from '../../../common/hooks/use_page_slice'; -import { FindingsByResourceQuery, useFindingsByResource } from './use_findings_by_resource'; -import { FindingsByResourceTable } from './findings_by_resource_table'; -import { getFilters } from '../utils/utils'; -import { LimitedResultsBar } from '../layout/findings_layout'; -import { FindingsGroupBySelector } from '../layout/findings_group_by_selector'; -import { findingsNavigation } from '../../../common/navigation/constants'; -import { ResourceFindings } from './resource_findings/resource_findings_container'; -import { ErrorCallout } from '../layout/error_callout'; -import { CurrentPageOfTotal, FindingsDistributionBar } from '../layout/findings_distribution_bar'; -import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../../common/constants'; -import type { FindingsBaseURLQuery, FindingsBaseProps } from '../../../common/types'; -import { useCloudPostureTable } from '../../../common/hooks/use_cloud_posture_table'; -import { useLimitProperties } from '../../../common/utils/get_limit_properties'; -import { getPaginationTableParams } from '../../../common/hooks/use_cloud_posture_table/utils'; - -const getDefaultQuery = ({ - query, - filters, -}: FindingsBaseURLQuery): FindingsBaseURLQuery & FindingsByResourceQuery => ({ - query, - filters, - pageIndex: 0, - sort: { field: 'compliance_score' as keyof CspFinding, direction: 'asc' }, -}); - -/** - * @deprecated: This component is deprecated and will be removed in the next release. - */ -export const FindingsByResourceContainer = ({ dataView }: FindingsBaseProps) => ( - - ( - - - - )} - /> - ( - - - - )} - /> - -); - -/** - * @deprecated: This component is deprecated and will be removed in the next release. - */ -const LatestFindingsByResource = ({ dataView }: FindingsBaseProps) => { - const { queryError, query, pageSize, setTableOptions, urlQuery, setUrlQuery, onResetFilters } = - useCloudPostureTable({ - dataView, - defaultQuery: getDefaultQuery, - paginationLocalStorageKey: LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY, - }); - - /** - * Page ES query result - */ - const findingsGroupByResource = useFindingsByResource({ - sortDirection: urlQuery.sort.direction, - query, - enabled: !queryError, - }); - - const error = findingsGroupByResource.error || queryError; - - const slicedPage = usePageSlice(findingsGroupByResource.data?.page, urlQuery.pageIndex, pageSize); - - const { isLastLimitedPage, limitedTotalItemCount } = useLimitProperties({ - total: findingsGroupByResource.data?.total, - pageIndex: urlQuery.pageIndex, - pageSize, - }); - - const handleDistributionClick = (evaluation: Evaluation) => { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field: 'result.evaluation', - value: evaluation, - negate: false, - }), - }); - }; - - return ( -
- { - setUrlQuery({ ...newQuery, pageIndex: 0 }); - }} - loading={findingsGroupByResource.isFetching} - /> - - - {error && } - {!error && ( - <> - {findingsGroupByResource.isSuccess && !!findingsGroupByResource.data.page.length && ( - <> - - - - - - - - - - - - )} - - - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field, - value, - negate, - }), - }) - } - /> - - )} - {isLastLimitedPage && } -
- ); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.test.tsx deleted file mode 100644 index f0a6375a66178..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.test.tsx +++ /dev/null @@ -1,113 +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 { render, screen, within } from '@testing-library/react'; -import * as TEST_SUBJECTS from '../test_subjects'; -import { FindingsByResourceTable, getResourceId } from './findings_by_resource_table'; -import type { PropsOf } from '@elastic/eui'; -import Chance from 'chance'; -import { TestProvider } from '../../../test/test_provider'; -import type { FindingsByResourcePage } from './use_findings_by_resource'; -import { calculatePostureScore } from '../../../../common/utils/helpers'; -import { EMPTY_STATE_TEST_SUBJ } from '../../../components/test_subjects'; - -const chance = new Chance(); - -const getFakeFindingsByResource = (): FindingsByResourcePage => { - const failed = chance.natural(); - const passed = chance.natural(); - const total = failed + passed; - const [resourceName, resourceSubtype, ruleBenchmarkName, ...cisSections] = chance.unique( - chance.word, - 5 - ); - - return { - belongs_to: chance.guid(), - resource_id: chance.guid(), - 'resource.name': resourceName, - 'resource.sub_type': resourceSubtype, - 'rule.section': cisSections, - 'rule.benchmark.name': ruleBenchmarkName, - compliance_score: passed / total, - findings: { - failed_findings: failed, - passed_findings: passed, - normalized: passed / total, - total_findings: total, - }, - }; -}; - -type TableProps = PropsOf; - -describe('', () => { - it('renders the zero state when status success and data has a length of zero ', async () => { - const props: TableProps = { - loading: false, - items: [], - pagination: { pageIndex: 0, pageSize: 10, totalItemCount: 0 }, - sorting: { - sort: { field: 'compliance_score', direction: 'desc' }, - }, - setTableOptions: jest.fn(), - onAddFilter: jest.fn(), - onResetFilters: jest.fn(), - }; - - render( - - - - ); - - expect(screen.getByTestId(EMPTY_STATE_TEST_SUBJ)).toBeInTheDocument(); - }); - - it('renders the table with provided items', () => { - const data = Array.from({ length: 10 }, getFakeFindingsByResource); - - const props: TableProps = { - loading: false, - items: data, - pagination: { pageIndex: 0, pageSize: 10, totalItemCount: 0 }, - sorting: { - sort: { field: 'compliance_score', direction: 'desc' }, - }, - setTableOptions: jest.fn(), - onAddFilter: jest.fn(), - onResetFilters: jest.fn(), - }; - - render( - - - - ); - - data.forEach((item) => { - const row = screen.getByTestId( - TEST_SUBJECTS.getFindingsByResourceTableRowTestId(getResourceId(item)) - ); - expect(row).toBeInTheDocument(); - expect(within(row).getByText(item.resource_id || '')).toBeInTheDocument(); - if (item['resource.name']) - expect(within(row).getByText(item['resource.name'])).toBeInTheDocument(); - if (item['resource.sub_type']) - expect(within(row).getByText(item['resource.sub_type'])).toBeInTheDocument(); - expect( - within(row).getByText( - `${calculatePostureScore( - item.findings.passed_findings, - item.findings.failed_findings - ).toFixed(0)}%` - ) - ).toBeInTheDocument(); - }); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.tsx deleted file mode 100644 index 71c4219d3b852..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/findings_by_resource_table.tsx +++ /dev/null @@ -1,212 +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, { useMemo } from 'react'; -import { - EuiBasicTable, - type EuiTableFieldDataColumnType, - type CriteriaWithPagination, - type Pagination, - EuiToolTip, - EuiBasicTableProps, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import numeral from '@elastic/numeral'; -import { generatePath, Link } from 'react-router-dom'; -import { i18n } from '@kbn/i18n'; -import { ColumnNameWithTooltip } from '../../../components/column_name_with_tooltip'; -import { ComplianceScoreBar } from '../../../components/compliance_score_bar'; -import * as TEST_SUBJECTS from '../test_subjects'; -import type { FindingsByResourcePage } from './use_findings_by_resource'; -import { findingsNavigation } from '../../../common/navigation/constants'; -import { - createColumnWithFilters, - type OnAddFilter, - baseFindingsColumns, -} from '../layout/findings_layout'; -import { EmptyState } from '../../../components/empty_state'; - -/** - * @deprecated: This function is deprecated and will be removed in the next release. - * use getAbbreviatedNumber from x-pack/plugins/cloud_security_posture/public/common/utils/get_abbreviated_number.ts - */ -export const formatNumber = (value: number) => - value < 1000 ? value : numeral(value).format('0.0a'); - -type Sorting = Required>['sorting']; - -interface Props { - items: FindingsByResourcePage[]; - loading: boolean; - pagination: Pagination; - sorting: Sorting; - setTableOptions(options: CriteriaWithPagination): void; - onAddFilter: OnAddFilter; - onResetFilters: () => void; -} - -/** - * @deprecated: This function is deprecated and will be removed in the next release. - */ -export const getResourceId = (resource: FindingsByResourcePage) => { - const sections = resource['rule.section'] || []; - return [resource.resource_id, ...sections].join('/'); -}; - -/** - * @deprecated: This component is deprecated and will be removed in the next release. - */ -const FindingsByResourceTableComponent = ({ - items, - loading, - pagination, - sorting, - setTableOptions, - onAddFilter, - onResetFilters, -}: Props) => { - const getRowProps = (row: FindingsByResourcePage) => ({ - 'data-test-subj': TEST_SUBJECTS.getFindingsByResourceTableRowTestId(getResourceId(row)), - }); - - const getNonSortableColumn = (column: EuiTableFieldDataColumnType) => ({ - ...column, - sortable: false, - }); - - const columns = useMemo( - () => [ - { - ...getNonSortableColumn(findingsByResourceColumns.resource_id), - ['data-test-subj']: TEST_SUBJECTS.FINDINGS_BY_RESOURCE_TABLE_RESOURCE_ID_COLUMN, - }, - createColumnWithFilters( - getNonSortableColumn(findingsByResourceColumns['resource.sub_type']), - { onAddFilter } - ), - createColumnWithFilters(getNonSortableColumn(findingsByResourceColumns['resource.name']), { - onAddFilter, - }), - createColumnWithFilters( - getNonSortableColumn(findingsByResourceColumns['rule.benchmark.name']), - { onAddFilter } - ), - getNonSortableColumn(findingsByResourceColumns.belongs_to), - findingsByResourceColumns.compliance_score, - ], - [onAddFilter] - ); - - if (!loading && !items.length) { - return ; - } - - return ( - - ); -}; - -const baseColumns: Array> = [ - { - ...baseFindingsColumns['resource.id'], - field: 'resource_id', - width: '15%', - render: (resourceId: FindingsByResourcePage['resource_id']) => { - if (!resourceId) return; - - return ( - - {resourceId} - - ); - }, - }, - baseFindingsColumns['resource.sub_type'], - baseFindingsColumns['resource.name'], - baseFindingsColumns['rule.benchmark.name'], - { - field: 'rule.section', - truncateText: true, - name: ( - - ), - render: (sections: string[]) => { - const items = sections.join(', '); - return ( - - <>{items} - - ); - }, - }, - { - field: 'belongs_to', - name: ( - - ), - truncateText: true, - }, - { - field: 'compliance_score', - width: '150px', - truncateText: true, - sortable: true, - name: ( - - ), - render: (complianceScore: FindingsByResourcePage['compliance_score'], data) => ( - - ), - dataType: 'number', - }, -]; - -type BaseFindingColumnName = typeof baseColumns[number]['field']; - -/** - * @deprecated: This function is deprecated and will be removed in the next release. - */ -export const findingsByResourceColumns = Object.fromEntries( - baseColumns.map((column) => [column.field, column]) -) as Record; - -/** - * @deprecated: This component is deprecated and will be removed in the next release. - */ -export const FindingsByResourceTable = React.memo(FindingsByResourceTableComponent); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.test.tsx deleted file mode 100644 index 95eb978f8e1ca..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.test.tsx +++ /dev/null @@ -1,50 +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 { render } from '@testing-library/react'; -import { TestProvider } from '../../../../test/test_provider'; -import { useResourceFindings } from './use_resource_findings'; -import { FindingsBaseProps } from '../../../../common/types'; -import { ResourceFindings } from './resource_findings_container'; - -jest.mock('./use_resource_findings', () => ({ - useResourceFindings: jest.fn().mockReturnValue({ - data: undefined, - error: false, - }), -})); - -describe('', () => { - it('should fetch resources with the correct parameters', async () => { - const props: FindingsBaseProps = { - dataView: {} as any, - }; - - render( - - - - ); - - expect(useResourceFindings).toHaveBeenNthCalledWith(1, { - enabled: true, - query: { - bool: { - filter: [], - must: [], - must_not: [], - should: [], - }, - }, - resourceId: 'undefined', - sort: { - direction: 'asc', - field: 'result.evaluation', - }, - }); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx deleted file mode 100644 index bc6e67b887096..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx +++ /dev/null @@ -1,301 +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, { useCallback } from 'react'; -import { - EuiSpacer, - EuiButtonEmpty, - type EuiDescriptionListProps, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; -import { Link, useParams } from 'react-router-dom'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { generatePath } from 'react-router-dom'; -import { i18n } from '@kbn/i18n'; -import { CspInlineDescriptionList } from '../../../../components/csp_inline_description_list'; -import type { Evaluation } from '../../../../../common/types_old'; -import { CspFinding } from '../../../../../common/schemas/csp_finding'; -import { CloudPosturePageTitle } from '../../../../components/cloud_posture_page_title'; -import * as TEST_SUBJECTS from '../../test_subjects'; -import { LimitedResultsBar, PageTitle, PageTitleText } from '../../layout/findings_layout'; -import { findingsNavigation } from '../../../../common/navigation/constants'; -import { ResourceFindingsQuery, useResourceFindings } from './use_resource_findings'; -import { usePageSlice } from '../../../../common/hooks/use_page_slice'; -import { getFilters } from '../../utils/utils'; -import { ResourceFindingsTable } from './resource_findings_table'; -import { FindingsSearchBar } from '../../layout/findings_search_bar'; -import { ErrorCallout } from '../../layout/error_callout'; -import { - CurrentPageOfTotal, - FindingsDistributionBar, -} from '../../layout/findings_distribution_bar'; -import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../../../common/constants'; -import type { FindingsBaseURLQuery, FindingsBaseProps } from '../../../../common/types'; -import { useCloudPostureTable } from '../../../../common/hooks/use_cloud_posture_table'; -import { useLimitProperties } from '../../../../common/utils/get_limit_properties'; -import { getPaginationTableParams } from '../../../../common/hooks/use_cloud_posture_table/utils'; - -const getDefaultQuery = ({ - query, - filters, -}: FindingsBaseURLQuery): FindingsBaseURLQuery & - ResourceFindingsQuery & { findingIndex: number } => ({ - query, - filters, - sort: { field: 'result.evaluation' as keyof CspFinding, direction: 'asc' }, - pageIndex: 0, - findingIndex: -1, -}); - -const BackToResourcesButton = () => ( - - - - - -); - -const getResourceFindingSharedValues = (sharedValues: { - resourceId: string; - resourceSubType: string; - resourceName: string; - clusterId: string; - cloudAccountName: string; -}): EuiDescriptionListProps['listItems'] => [ - { - title: i18n.translate('xpack.csp.findings.resourceFindingsSharedValues.resourceTypeTitle', { - defaultMessage: 'Resource Type', - }), - description: sharedValues.resourceSubType, - }, - { - title: i18n.translate('xpack.csp.findings.resourceFindingsSharedValues.resourceIdTitle', { - defaultMessage: 'Resource ID', - }), - description: sharedValues.resourceId, - }, - { - title: i18n.translate('xpack.csp.findings.resourceFindingsSharedValues.clusterIdTitle', { - defaultMessage: 'Cluster ID', - }), - description: sharedValues.clusterId, - }, - { - title: i18n.translate('xpack.csp.findings.resourceFindingsSharedValues.cloudAccountName', { - defaultMessage: 'Cloud Account Name', - }), - description: sharedValues.cloudAccountName, - }, -]; - -/** - * @deprecated: This component is deprecated and will be removed in the next release. - */ -export const ResourceFindings = ({ dataView }: FindingsBaseProps) => { - const params = useParams<{ resourceId: string }>(); - const decodedResourceId = decodeURIComponent(params.resourceId); - - const { - pageIndex, - sort, - query, - queryError, - pageSize, - setTableOptions, - urlQuery, - setUrlQuery, - onResetFilters, - } = useCloudPostureTable({ - dataView, - defaultQuery: getDefaultQuery, - paginationLocalStorageKey: LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY, - }); - - /** - * Page ES query result - */ - const resourceFindings = useResourceFindings({ - sort, - resourceId: decodedResourceId, - enabled: !queryError, - query, - }); - - const error = resourceFindings.error || queryError; - - const slicedPage = usePageSlice(resourceFindings.data?.page, urlQuery.pageIndex, pageSize); - - const { isLastLimitedPage, limitedTotalItemCount } = useLimitProperties({ - total: resourceFindings.data?.total, - pageIndex: urlQuery.pageIndex, - pageSize, - }); - - const handleDistributionClick = (evaluation: Evaluation) => { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field: 'result.evaluation', - value: evaluation, - negate: false, - }), - }); - }; - - const flyoutFindingIndex = urlQuery?.findingIndex; - - const pagination = getPaginationTableParams({ - pageSize, - pageIndex, - totalItemCount: limitedTotalItemCount, - }); - - const onOpenFlyout = useCallback( - (flyoutFinding: CspFinding) => { - setUrlQuery({ - findingIndex: slicedPage.findIndex( - (finding) => - finding.resource.id === flyoutFinding?.resource.id && - finding.rule.id === flyoutFinding?.rule.id - ), - }); - }, - [slicedPage, setUrlQuery] - ); - - const onCloseFlyout = () => - setUrlQuery({ - findingIndex: -1, - }); - - const onPaginateFlyout = useCallback( - (nextFindingIndex: number) => { - // the index of the finding in the current page - const newFindingIndex = nextFindingIndex % pageSize; - - // if the finding is not in the current page, we need to change the page - const flyoutPageIndex = Math.floor(nextFindingIndex / pageSize); - - setUrlQuery({ - pageIndex: flyoutPageIndex, - findingIndex: newFindingIndex, - }); - }, - [pageSize, setUrlQuery] - ); - - return ( -
- { - setUrlQuery({ ...newQuery, pageIndex: 0 }); - }} - loading={resourceFindings.isFetching} - /> - - - - - } - /> - - - {resourceFindings.data && ( - - )} - - - {error && } - {!error && ( - <> - {resourceFindings.isSuccess && !!resourceFindings.data.page.length && ( - <> - - - - - - - - - )} - - - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field, - value, - negate, - }), - }) - } - /> - - )} - {isLastLimitedPage && } -
- ); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.test.tsx deleted file mode 100644 index b47366938db8d..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.test.tsx +++ /dev/null @@ -1,86 +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 { render, screen, within } from '@testing-library/react'; -import * as TEST_SUBJECTS from '../../test_subjects'; -import { ResourceFindingsTable, ResourceFindingsTableProps } from './resource_findings_table'; -import { TestProvider } from '../../../../test/test_provider'; - -import { capitalize } from 'lodash'; -import moment from 'moment'; -import { getFindingsFixture } from '../../../../test/fixtures/findings_fixture'; -import { EMPTY_STATE_TEST_SUBJ } from '../../../../components/test_subjects'; - -describe('', () => { - it('should render no findings empty state when status success and data has a length of zero ', async () => { - const resourceFindingsProps: ResourceFindingsTableProps = { - loading: false, - items: [], - pagination: { pageIndex: 0, pageSize: 10, totalItemCount: 0 }, - sorting: { - sort: { field: '@timestamp', direction: 'desc' }, - }, - setTableOptions: jest.fn(), - onAddFilter: jest.fn(), - flyoutFindingIndex: -1, - onOpenFlyout: jest.fn(), - onCloseFlyout: jest.fn(), - onPaginateFlyout: jest.fn(), - onResetFilters: jest.fn(), - }; - - render( - - - - ); - - expect(screen.getByTestId(EMPTY_STATE_TEST_SUBJ)).toBeInTheDocument(); - }); - - it('should render resource finding table content when data has a non zero length', () => { - const data = Array.from({ length: 10 }, getFindingsFixture); - - const props: ResourceFindingsTableProps = { - loading: false, - items: data, - pagination: { pageIndex: 0, pageSize: 10, totalItemCount: 0 }, - sorting: { - sort: { field: 'cluster_id', direction: 'desc' }, - }, - setTableOptions: jest.fn(), - onAddFilter: jest.fn(), - flyoutFindingIndex: -1, - onOpenFlyout: jest.fn(), - onCloseFlyout: jest.fn(), - onPaginateFlyout: jest.fn(), - onResetFilters: jest.fn(), - }; - - render( - - - - ); - - data.forEach((item, i) => { - const row = screen.getByTestId( - TEST_SUBJECTS.getResourceFindingsTableRowTestId(item.resource.id) - ); - const { evaluation } = item.result; - const evaluationStatusText = capitalize( - item.result.evaluation.slice(0, evaluation.length - 2) - ); - - expect(row).toBeInTheDocument(); - expect(within(row).queryByText(item.rule.name)).toBeInTheDocument(); - expect(within(row).queryByText(evaluationStatusText)).toBeInTheDocument(); - expect(within(row).queryByText(moment(item['@timestamp']).fromNow())).toBeInTheDocument(); - expect(within(row).queryByText(item.rule.section)).toBeInTheDocument(); - }); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.tsx deleted file mode 100644 index 4dd7070af88f1..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_table.tsx +++ /dev/null @@ -1,112 +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, { useMemo } from 'react'; -import { - EuiBasicTable, - type CriteriaWithPagination, - type Pagination, - type EuiBasicTableColumn, - type EuiTableActionsColumnType, - type EuiBasicTableProps, - useEuiTheme, -} from '@elastic/eui'; -import { CspFinding } from '../../../../../common/schemas/csp_finding'; -import { - baseFindingsColumns, - createColumnWithFilters, - getExpandColumn, - type OnAddFilter, -} from '../../layout/findings_layout'; -import { FindingsRuleFlyout } from '../../findings_flyout/findings_flyout'; -import { getSelectedRowStyle } from '../../utils/utils'; -import * as TEST_SUBJECTS from '../../test_subjects'; -import { EmptyState } from '../../../../components/empty_state'; - -export interface ResourceFindingsTableProps { - items: CspFinding[]; - loading: boolean; - pagination: Pagination & { pageSize: number }; - sorting: Required>['sorting']; - setTableOptions(options: CriteriaWithPagination): void; - onAddFilter: OnAddFilter; - onPaginateFlyout: (pageIndex: number) => void; - onCloseFlyout: () => void; - onOpenFlyout: (finding: CspFinding) => void; - flyoutFindingIndex: number; - onResetFilters: () => void; -} - -const ResourceFindingsTableComponent = ({ - items, - loading, - pagination, - sorting, - setTableOptions, - onAddFilter, - onOpenFlyout, - flyoutFindingIndex, - onPaginateFlyout, - onCloseFlyout, - onResetFilters, -}: ResourceFindingsTableProps) => { - const { euiTheme } = useEuiTheme(); - - const selectedFinding = items[flyoutFindingIndex]; - - const getRowProps = (row: CspFinding) => ({ - style: getSelectedRowStyle(euiTheme, row, selectedFinding), - 'data-test-subj': TEST_SUBJECTS.getResourceFindingsTableRowTestId(row.resource.id), - }); - - const columns: [ - EuiTableActionsColumnType, - ...Array> - ] = useMemo( - () => [ - getExpandColumn({ onClick: onOpenFlyout }), - createColumnWithFilters(baseFindingsColumns['result.evaluation'], { onAddFilter }), - baseFindingsColumns['rule.benchmark.rule_number'], - createColumnWithFilters(baseFindingsColumns['rule.name'], { onAddFilter }), - createColumnWithFilters(baseFindingsColumns['rule.section'], { onAddFilter }), - baseFindingsColumns['@timestamp'], - ], - [onAddFilter, onOpenFlyout] - ); - - if (!loading && !items.length) { - return ; - } - - return ( - <> - - {selectedFinding && ( - - )} - - ); -}; - -/** - * @deprecated: This component is deprecated and will be removed in the next release. - */ -export const ResourceFindingsTable = React.memo(ResourceFindingsTableComponent); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/use_resource_findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/use_resource_findings.ts deleted file mode 100644 index 46a5e12665660..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/use_resource_findings.ts +++ /dev/null @@ -1,136 +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 { useQuery } from '@tanstack/react-query'; -import { lastValueFrom } from 'rxjs'; -import { IKibanaSearchRequest, IKibanaSearchResponse } from '@kbn/data-plugin/common'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { Pagination } from '@elastic/eui'; -import { number } from 'io-ts'; -import { getSafeKspmClusterIdRuntimeMapping } from '../../../../../common/runtime_mappings/get_safe_kspm_cluster_id_runtime_mapping'; -import { CspFinding } from '../../../../../common/schemas/csp_finding'; -import { getAggregationCount, getFindingsCountAggQuery } from '../../utils/utils'; -import { useKibana } from '../../../../common/hooks/use_kibana'; -import type { FindingsBaseEsQuery, Sort } from '../../../../common/types'; -import { CSP_LATEST_FINDINGS_DATA_VIEW } from '../../../../../common/constants'; -import { MAX_FINDINGS_TO_LOAD } from '../../../../common/constants'; -import { showErrorToast } from '../../../../common/utils/show_error_toast'; - -interface UseResourceFindingsOptions extends FindingsBaseEsQuery { - resourceId: string; - sort: Sort; - enabled: boolean; -} - -export interface ResourceFindingsQuery { - pageIndex: Pagination['pageIndex']; - sort: Sort; -} - -type ResourceFindingsRequest = IKibanaSearchRequest; -type ResourceFindingsResponse = IKibanaSearchResponse< - estypes.SearchResponse ->; - -export type ResourceFindingsResponseAggs = Record< - 'count' | 'clusterId' | 'resourceSubType' | 'resourceName' | 'cloudAccountName', - estypes.AggregationsMultiBucketAggregateBase< - estypes.AggregationsStringRareTermsBucketKeys | undefined - > ->; - -const getResourceFindingsQuery = ({ - query, - resourceId, - sort, -}: UseResourceFindingsOptions): estypes.SearchRequest => ({ - index: CSP_LATEST_FINDINGS_DATA_VIEW, - body: { - size: MAX_FINDINGS_TO_LOAD, - runtime_mappings: { - ...getSafeKspmClusterIdRuntimeMapping(), - }, - query: { - ...query, - bool: { - ...query?.bool, - filter: [...(query?.bool?.filter || []), { term: { 'resource.id': resourceId } }], - }, - }, - sort: [{ [sort.field]: sort.direction }], - aggs: { - ...getFindingsCountAggQuery(), - cloudAccountName: { - terms: { field: 'cloud.account.name' }, - }, - clusterId: { - terms: { field: 'safe_kspm_cluster_id' }, - }, - resourceSubType: { - terms: { field: 'resource.sub_type' }, - }, - resourceName: { - terms: { field: 'resource.name' }, - }, - }, - }, - ignore_unavailable: false, -}); - -/** - * @deprecated: This hook is deprecated and will be removed in the next release. - */ -export const useResourceFindings = (options: UseResourceFindingsOptions) => { - const { - data, - notifications: { toasts }, - } = useKibana().services; - - const params = { ...options }; - - return useQuery( - ['csp_resource_findings', { params }], - () => - lastValueFrom( - data.search.search({ - params: getResourceFindingsQuery(params), - }) - ), - { - enabled: options.enabled, - keepPreviousData: true, - select: ({ rawResponse: { hits, aggregations } }: ResourceFindingsResponse) => { - if (!aggregations) throw new Error('expected aggregations to exists'); - assertNonBucketsArray(aggregations.count?.buckets); - assertNonBucketsArray(aggregations.clusterId?.buckets); - assertNonBucketsArray(aggregations.resourceSubType?.buckets); - assertNonBucketsArray(aggregations.resourceName?.buckets); - assertNonBucketsArray(aggregations.cloudAccountName?.buckets); - - return { - page: hits.hits.map((hit) => hit._source!), - total: number.is(hits.total) ? hits.total : 0, - count: getAggregationCount(aggregations.count?.buckets), - clusterId: getFirstBucketKey(aggregations.clusterId?.buckets), - resourceSubType: getFirstBucketKey(aggregations.resourceSubType?.buckets), - resourceName: getFirstBucketKey(aggregations.resourceName?.buckets), - cloudAccountName: getFirstBucketKey(aggregations.cloudAccountName?.buckets), - }; - }, - onError: (err: Error) => showErrorToast(toasts, err), - } - ); -}; - -function assertNonBucketsArray(arr: unknown): asserts arr is T[] { - if (!Array.isArray(arr)) { - throw new Error('expected buckets to be an array'); - } -} - -const getFirstBucketKey = ( - buckets: Array -): string | undefined => buckets[0]?.key; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/use_findings_by_resource.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/use_findings_by_resource.ts deleted file mode 100644 index e4bbd955f6092..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/use_findings_by_resource.ts +++ /dev/null @@ -1,218 +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 { useQuery } from '@tanstack/react-query'; -import { lastValueFrom } from 'rxjs'; -import { IKibanaSearchRequest, IKibanaSearchResponse } from '@kbn/data-plugin/common'; -import type { Pagination } from '@elastic/eui'; -import { - AggregationsCardinalityAggregate, - AggregationsMultiBucketAggregateBase, - AggregationsMultiBucketBase, - AggregationsScriptedMetricAggregate, - AggregationsStringRareTermsBucketKeys, - AggregationsStringTermsBucketKeys, - SearchRequest, - SearchResponse, -} from '@elastic/elasticsearch/lib/api/types'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; -import { getBelongsToRuntimeMapping } from '../../../../common/runtime_mappings/get_belongs_to_runtime_mapping'; -import { MAX_FINDINGS_TO_LOAD } from '../../../common/constants'; -import { useKibana } from '../../../common/hooks/use_kibana'; -import { showErrorToast } from '../../../common/utils/show_error_toast'; -import type { FindingsBaseEsQuery, Sort } from '../../../common/types'; -import { getAggregationCount, getFindingsCountAggQuery } from '../utils/utils'; -import { CSP_LATEST_FINDINGS_DATA_VIEW } from '../../../../common/constants'; - -interface UseFindingsByResourceOptions extends FindingsBaseEsQuery { - enabled: boolean; - sortDirection: Sort['direction']; -} - -// Maximum number of grouped findings, default limit in elasticsearch is set to 65,536 (ref: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-settings.html#search-settings-max-buckets) -const MAX_BUCKETS = 60 * 1000; - -export interface FindingsByResourceQuery { - pageIndex: Pagination['pageIndex']; - sort: Sort; -} - -type FindingsAggRequest = IKibanaSearchRequest; -type FindingsAggResponse = IKibanaSearchResponse>; - -export interface FindingsByResourcePage { - findings: { - failed_findings: number; - passed_findings: number; - normalized: number; - total_findings: number; - }; - compliance_score: number; - resource_id?: string; - belongs_to?: string; - 'resource.name'?: string; - 'resource.sub_type'?: string; - 'rule.benchmark.name'?: string; - 'rule.section'?: string[]; -} - -interface FindingsByResourceAggs { - resource_total: AggregationsCardinalityAggregate; - resources: AggregationsMultiBucketAggregateBase; - count: AggregationsMultiBucketAggregateBase; -} - -interface FindingsAggBucket extends AggregationsStringRareTermsBucketKeys { - failed_findings: AggregationsMultiBucketBase; - compliance_score: AggregationsScriptedMetricAggregate; - passed_findings: AggregationsMultiBucketBase; - name: AggregationsMultiBucketAggregateBase; - subtype: AggregationsMultiBucketAggregateBase; - belongs_to: AggregationsMultiBucketAggregateBase; - benchmarkName: AggregationsMultiBucketAggregateBase; - cis_sections: AggregationsMultiBucketAggregateBase; -} - -/** - * @deprecated: This hook is deprecated and will be removed in the next release. - */ -export const getFindingsByResourceAggQuery = ({ - query, - sortDirection, -}: UseFindingsByResourceOptions): SearchRequest => ({ - index: CSP_LATEST_FINDINGS_DATA_VIEW, - query, - size: 0, - runtime_mappings: getBelongsToRuntimeMapping(), - aggs: { - ...getFindingsCountAggQuery(), - resource_total: { cardinality: { field: 'resource.id' } }, - resources: { - terms: { field: 'resource.id', size: MAX_BUCKETS }, - aggs: { - name: { - terms: { field: 'resource.name', size: 1 }, - }, - subtype: { - terms: { field: 'resource.sub_type', size: 1 }, - }, - benchmarkName: { - terms: { field: 'rule.benchmark.name' }, - }, - cis_sections: { - terms: { field: 'rule.section' }, - }, - failed_findings: { - filter: { term: { 'result.evaluation': 'failed' } }, - }, - passed_findings: { - filter: { term: { 'result.evaluation': 'passed' } }, - }, - // this field is runtime generated - belongs_to: { - terms: { field: 'belongs_to', size: 1 }, - }, - compliance_score: { - bucket_script: { - buckets_path: { - passed: 'passed_findings>_count', - failed: 'failed_findings>_count', - }, - script: 'params.passed / (params.passed + params.failed)', - }, - }, - sort_by_compliance_score: { - bucket_sort: { - size: MAX_FINDINGS_TO_LOAD, - sort: [ - { - compliance_score: { order: sortDirection }, - _count: { order: 'desc' }, - _key: { order: 'asc' }, - }, - ], - }, - }, - }, - }, - }, - ignore_unavailable: false, -}); - -const getFirstKey = ( - buckets: AggregationsMultiBucketAggregateBase['buckets'] -): undefined | string => { - if (!!Array.isArray(buckets) && !!buckets.length) return buckets[0].key; -}; - -const getKeysList = ( - buckets: AggregationsMultiBucketAggregateBase['buckets'] -): undefined | string[] => { - if (!!Array.isArray(buckets) && !!buckets.length) return buckets.map((v) => v.key); -}; - -const createFindingsByResource = (resource: FindingsAggBucket): FindingsByResourcePage => ({ - resource_id: resource.key, - ['resource.name']: getFirstKey(resource.name.buckets), - ['resource.sub_type']: getFirstKey(resource.subtype.buckets), - ['rule.section']: getKeysList(resource.cis_sections.buckets), - ['rule.benchmark.name']: getFirstKey(resource.benchmarkName.buckets), - belongs_to: getFirstKey(resource.belongs_to.buckets), - compliance_score: resource.compliance_score.value, - findings: { - failed_findings: resource.failed_findings.doc_count, - normalized: - resource.doc_count > 0 ? resource.failed_findings.doc_count / resource.doc_count : 0, - total_findings: resource.doc_count, - passed_findings: resource.passed_findings.doc_count, - }, -}); - -/** - * @deprecated: This hook is deprecated and will be removed in the next release. - */ -export const useFindingsByResource = (options: UseFindingsByResourceOptions) => { - const { - data, - notifications: { toasts }, - } = useKibana().services; - - const params = { ...options }; - - return useQuery( - ['csp_findings_resource', { params }], - async () => { - const { - rawResponse: { aggregations }, - } = await lastValueFrom( - data.search.search({ - params: getFindingsByResourceAggQuery(params), - }) - ); - - if (!aggregations) throw new Error('Failed to aggregate by, missing resource id'); - - if ( - !Array.isArray(aggregations.resources.buckets) || - !Array.isArray(aggregations.count.buckets) - ) - throw new Error('Failed to group by, missing resource id'); - - const page = aggregations.resources.buckets.map(createFindingsByResource); - - return { - page, - total: aggregations.resource_total.value, - count: getAggregationCount(aggregations.count.buckets), - }; - }, - { - enabled: options.enabled, - keepPreviousData: true, - onError: (err: Error) => showErrorToast(toasts, err), - } - ); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_layout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_layout.tsx deleted file mode 100644 index 2a39550a3c7d4..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_layout.tsx +++ /dev/null @@ -1,318 +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 { - EuiBottomBar, - EuiButtonIcon, - EuiSpacer, - EuiTableActionsColumnType, - EuiTableFieldDataColumnType, - EuiText, - EuiTitle, - EuiToolTip, - PropsOf, -} from '@elastic/eui'; -import { css } from '@emotion/react'; -import { i18n } from '@kbn/i18n'; -import { euiThemeVars } from '@kbn/ui-theme'; -import type { Serializable } from '@kbn/utility-types'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { FindingsByResourcePage } from '../latest_findings_by_resource/use_findings_by_resource'; -import { MAX_FINDINGS_TO_LOAD } from '../../../common/constants'; -import { TimestampTableCell } from '../../../components/timestamp_table_cell'; -import { ColumnNameWithTooltip } from '../../../components/column_name_with_tooltip'; -import { CspEvaluationBadge } from '../../../components/csp_evaluation_badge'; -import { - FINDINGS_TABLE_CELL_ADD_FILTER, - FINDINGS_TABLE_CELL_ADD_NEGATED_FILTER, - FINDINGS_TABLE_EXPAND_COLUMN, -} from '../test_subjects'; - -export type OnAddFilter = (key: T, value: Serializable, negate: boolean) => void; - -export const PageTitle: React.FC = ({ children }) => ( - -
{children}
-
-); - -export const PageTitleText = ({ title }: { title: React.ReactNode }) => ( - -

{title}

-
-); - -export const getExpandColumn = ({ - onClick, -}: { - onClick(item: T): void; -}): EuiTableActionsColumnType => ({ - width: '40px', - actions: [ - { - 'data-test-subj': FINDINGS_TABLE_EXPAND_COLUMN, - name: i18n.translate('xpack.csp.expandColumnNameLabel', { defaultMessage: 'Expand' }), - description: i18n.translate('xpack.csp.expandColumnDescriptionLabel', { - defaultMessage: 'Expand', - }), - type: 'icon', - icon: 'expand', - onClick, - }, - ], -}); - -const baseColumns = [ - { - field: 'resource.id', - name: ( - - ), - truncateText: true, - width: '180px', - sortable: true, - render: (filename: string) => ( - - {filename} - - ), - }, - { - field: 'result.evaluation', - name: i18n.translate('xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel', { - defaultMessage: 'Result', - }), - width: '80px', - sortable: true, - render: (type: PropsOf['type']) => ( - - ), - }, - { - field: 'resource.sub_type', - name: i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel', - { defaultMessage: 'Resource Type' } - ), - sortable: true, - truncateText: true, - width: '10%', - }, - { - field: 'resource.name', - name: i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel', - { defaultMessage: 'Resource Name' } - ), - sortable: true, - truncateText: true, - width: '12%', - render: (name: FindingsByResourcePage['resource.name']) => { - if (!name) return; - - return ( - - <>{name} - - ); - }, - }, - { - field: 'rule.name', - name: i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel', - { defaultMessage: 'Rule Name' } - ), - sortable: true, - render: (name: string) => ( - - <>{name} - - ), - }, - { - field: 'rule.benchmark.rule_number', - name: i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel', - { - defaultMessage: 'Rule Number', - } - ), - sortable: true, - width: '120px', - }, - { - field: 'rule.benchmark.name', - name: ( - - ), - sortable: true, - truncateText: true, - }, - { - field: 'rule.section', - name: i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel', - { defaultMessage: 'CIS Section' } - ), - width: '150px', - sortable: true, - truncateText: true, - render: (section: string) => ( - - <>{section} - - ), - }, - { - field: '@timestamp', - align: 'right', - width: '10%', - name: i18n.translate( - 'xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel', - { defaultMessage: 'Last Checked' } - ), - truncateText: true, - sortable: true, - render: (timestamp: number) => , - }, -] as const; - -export const baseFindingsColumns = Object.fromEntries( - baseColumns.map((column) => [column.field, column]) -) as Record; - -export const createColumnWithFilters = ( - column: EuiTableFieldDataColumnType, - { onAddFilter }: { onAddFilter: OnAddFilter } -): EuiTableFieldDataColumnType => ({ - ...column, - render: (cellValue: Serializable, item: T) => ( - onAddFilter(column.field as string, cellValue, false)} - onAddNegateFilter={() => onAddFilter(column.field as string, cellValue, true)} - field={column.field as string} - > - {column.render?.(cellValue, item) || getCellValue(cellValue)} - - ), -}); - -const getCellValue = (value: unknown) => { - if (!value) return; - if (typeof value === 'string' || typeof value === 'number') return value; -}; - -const FilterableCell: React.FC<{ - onAddFilter(): void; - onAddNegateFilter(): void; - field: string; -}> = ({ children, onAddFilter, onAddNegateFilter, field }) => ( -
.__filter_buttons { - opacity: 1; - } - > .__filter_value { - max-width: calc(100% - calc(${euiThemeVars.euiSizeL} * 2)); - } - } - `} - > -
- {children} -
-
- - - - - - - -
-
-); - -export const LimitedResultsBar = () => ( - <> - - - - - - - -); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx index 9b6e7bcb60c53..43077778c4fdf 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx @@ -8,9 +8,9 @@ import React, { useContext } from 'react'; import { css } from '@emotion/react'; import { EuiThemeComputed, useEuiTheme } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import type { DataView } from '@kbn/data-plugin/common'; import { i18n } from '@kbn/i18n'; import type { Filter } from '@kbn/es-query'; +import { useDataViewContext } from '../../../common/contexts/data_view_context'; import { SecuritySolutionContext } from '../../../application/security_solution_context'; import type { FindingsBaseURLQuery } from '../../../common/types'; import type { CspClientPluginStartDeps } from '../../../types'; @@ -25,13 +25,12 @@ interface FindingsSearchBarProps { } export const FindingsSearchBar = ({ - dataView, loading, setQuery, placeholder = i18n.translate('xpack.csp.findings.searchBar.searchPlaceholder', { defaultMessage: 'Search findings (eg. rule.section : "API Server" )', }), -}: FindingsSearchBarProps & { dataView: DataView }) => { +}: FindingsSearchBarProps) => { const { euiTheme } = useEuiTheme(); const { unifiedSearch: { @@ -41,6 +40,8 @@ export const FindingsSearchBar = ({ const securitySolutionContext = useContext(SecuritySolutionContext); + const { dataView } = useDataViewContext(); + let searchBarNode = (
({ + query, + filters, + sort: [ + [VULNERABILITY_FIELDS.SEVERITY, 'asc'], + [VULNERABILITY_FIELDS.SCORE_BASE, 'desc'], + ], +}); + +export const defaultColumns: CloudSecurityDefaultColumn[] = [ + { id: VULNERABILITY_FIELDS.VULNERABILITY_ID, width: 130 }, + { id: VULNERABILITY_FIELDS.SCORE_BASE, width: 80 }, + { id: VULNERABILITY_FIELDS.RESOURCE_NAME }, + { id: VULNERABILITY_FIELDS.RESOURCE_ID }, + { id: VULNERABILITY_FIELDS.SEVERITY, width: 100 }, + { id: VULNERABILITY_FIELDS.PACKAGE_NAME }, + { id: VULNERABILITY_FIELDS.PACKAGE_VERSION }, + { id: VULNERABILITY_FIELDS.PACKAGE_FIXED_VERSION }, +]; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_grouped_vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_grouped_vulnerabilities.tsx new file mode 100644 index 0000000000000..fda12c4b06d41 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_grouped_vulnerabilities.tsx @@ -0,0 +1,85 @@ +/* + * 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 { SearchResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IKibanaSearchResponse } from '@kbn/data-plugin/public'; +import { GenericBuckets, GroupingQuery, RootAggregation } from '@kbn/securitysolution-grouping/src'; +import { useQuery } from '@tanstack/react-query'; +import { lastValueFrom } from 'rxjs'; +import { LATEST_VULNERABILITIES_INDEX_PATTERN } from '../../../../common/constants'; +import { useKibana } from '../../../common/hooks/use_kibana'; +import { showErrorToast } from '../../../common/utils/show_error_toast'; + +// Elasticsearch returns `null` when a sub-aggregation cannot be computed +type NumberOrNull = number | null; + +export interface VulnerabilitiesGroupingAggregation { + unitsCount?: { + value?: NumberOrNull; + }; + groupsCount?: { + value?: NumberOrNull; + }; + groupByFields?: { + buckets?: GenericBuckets[]; + }; + description?: { + buckets?: GenericBuckets[]; + }; + resourceId?: { + buckets?: GenericBuckets[]; + }; + isLoading?: boolean; +} + +export type VulnerabilitiesRootGroupingAggregation = + RootAggregation; + +export const getGroupedVulnerabilitiesQuery = (query: GroupingQuery) => ({ + ...query, + index: LATEST_VULNERABILITIES_INDEX_PATTERN, + size: 0, +}); + +export const useGroupedVulnerabilities = ({ + query, + enabled = true, +}: { + query: GroupingQuery; + enabled: boolean; +}) => { + const { + data, + notifications: { toasts }, + } = useKibana().services; + + return useQuery( + ['csp_grouped_vulnerabilities', { query }], + async () => { + const { + rawResponse: { aggregations }, + } = await lastValueFrom( + data.search.search< + {}, + IKibanaSearchResponse> + >({ + params: getGroupedVulnerabilitiesQuery(query), + }) + ); + + if (!aggregations) throw new Error('Failed to aggregate by, missing resource id'); + + return aggregations; + }, + { + onError: (err: Error) => showErrorToast(toasts, err), + enabled, + // This allows the UI to keep the previous data while the new data is being fetched + keepPreviousData: true, + } + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx index a3ae53a25f4d9..df9d5446ea926 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { useQuery } from '@tanstack/react-query'; +import { useInfiniteQuery } from '@tanstack/react-query'; import { lastValueFrom } from 'rxjs'; import type { IKibanaSearchRequest, IKibanaSearchResponse } from '@kbn/data-plugin/common'; import { number } from 'io-ts'; @@ -13,33 +13,71 @@ import { SearchResponse, AggregationsMultiBucketAggregateBase, AggregationsStringRareTermsBucketKeys, - Sort, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { buildDataTableRecord } from '@kbn/discover-utils'; +import { EsHitRecord } from '@kbn/discover-utils/types'; +import { MAX_FINDINGS_TO_LOAD } from '../../../common/constants'; import { CspVulnerabilityFinding } from '../../../../common/schemas'; -import { LATEST_VULNERABILITIES_INDEX_PATTERN } from '../../../../common/constants'; +import { + LATEST_VULNERABILITIES_INDEX_PATTERN, + LATEST_VULNERABILITIES_RETENTION_POLICY, +} from '../../../../common/constants'; import { useKibana } from '../../../common/hooks/use_kibana'; import { showErrorToast } from '../../../common/utils/show_error_toast'; import { FindingsBaseEsQuery } from '../../../common/types'; +import { VULNERABILITY_FIELDS } from '../constants'; +import { getCaseInsensitiveSortScript } from '../utils/custom_sort_script'; type LatestFindingsRequest = IKibanaSearchRequest; -type LatestFindingsResponse = IKibanaSearchResponse>; +type LatestFindingsResponse = IKibanaSearchResponse< + SearchResponse +>; interface FindingsAggs { count: AggregationsMultiBucketAggregateBase; } - interface VulnerabilitiesQuery extends FindingsBaseEsQuery { - sort: Sort; + sort: string[][]; enabled: boolean; - pageIndex: number; pageSize: number; } -export const getFindingsQuery = ({ query, sort, pageIndex, pageSize }: VulnerabilitiesQuery) => ({ +const getMultiFieldsSort = (sort: string[][]) => { + return sort.map(([id, direction]) => { + if (id === VULNERABILITY_FIELDS.PACKAGE_NAME) { + return getCaseInsensitiveSortScript(id, direction); + } + + return { + [id]: direction, + }; + }); +}; + +export const getVulnerabilitiesQuery = ( + { query, sort }: VulnerabilitiesQuery, + pageParam: number +) => ({ index: LATEST_VULNERABILITIES_INDEX_PATTERN, - query, - from: pageIndex * pageSize, - size: pageSize, - sort, + sort: getMultiFieldsSort(sort), + size: MAX_FINDINGS_TO_LOAD, + query: { + ...query, + bool: { + ...query?.bool, + filter: [ + ...(query?.bool?.filter ?? []), + { + range: { + '@timestamp': { + gte: `now-${LATEST_VULNERABILITIES_RETENTION_POLICY}`, + lte: 'now', + }, + }, + }, + ], + }, + }, + ...(pageParam ? { from: pageParam } : {}), }); export const useLatestVulnerabilities = (options: VulnerabilitiesQuery) => { @@ -47,19 +85,25 @@ export const useLatestVulnerabilities = (options: VulnerabilitiesQuery) => { data, notifications: { toasts }, } = useKibana().services; - return useQuery( + /** + * We're using useInfiniteQuery in this case to allow the user to fetch more data (if available and up to 10k) + * useInfiniteQuery differs from useQuery because it accumulates and caches a chunk of data from the previous fetches into an array + * it uses the getNextPageParam to know if there are more pages to load and retrieve the position of + * the last loaded record to be used as a from parameter to fetch the next chunk of data. + */ + return useInfiniteQuery( [LATEST_VULNERABILITIES_INDEX_PATTERN, options], - async () => { + async ({ pageParam }) => { const { rawResponse: { hits }, } = await lastValueFrom( data.search.search({ - params: getFindingsQuery(options), + params: getVulnerabilitiesQuery(options, pageParam), }) ); return { - page: hits.hits.map((hit) => hit._source!) as CspVulnerabilityFinding[], + page: hits.hits.map((hit) => buildDataTableRecord(hit as EsHitRecord)), total: number.is(hits.total) ? hits.total : 0, }; }, @@ -68,6 +112,12 @@ export const useLatestVulnerabilities = (options: VulnerabilitiesQuery) => { keepPreviousData: true, enabled: options.enabled, onError: (err: Error) => showErrorToast(toasts, err), + getNextPageParam: (lastPage, allPages) => { + if (lastPage.page.length < options.pageSize) { + return undefined; + } + return allPages.length * options.pageSize; + }, } ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx new file mode 100644 index 0000000000000..45fdc5c71a342 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_grouping.tsx @@ -0,0 +1,157 @@ +/* + * 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 { getGroupingQuery } from '@kbn/securitysolution-grouping'; +import { + GroupingAggregation, + GroupPanelRenderer, + GroupStatsRenderer, + isNoneGroup, + NamedAggregation, + parseGroupingQuery, +} from '@kbn/securitysolution-grouping/src'; +import { useMemo } from 'react'; +import { LOCAL_STORAGE_VULNERABILITIES_GROUPING_KEY } from '../../../common/constants'; +import { useDataViewContext } from '../../../common/contexts/data_view_context'; +import { LATEST_VULNERABILITIES_RETENTION_POLICY } from '../../../../common/constants'; +import { + VulnerabilitiesGroupingAggregation, + VulnerabilitiesRootGroupingAggregation, + useGroupedVulnerabilities, +} from './use_grouped_vulnerabilities'; +import { + defaultGroupingOptions, + getDefaultQuery, + GROUPING_OPTIONS, + VULNERABILITY_FIELDS, +} from '../constants'; +import { useCloudSecurityGrouping } from '../../../components/cloud_security_grouping'; +import { VULNERABILITIES_UNIT, groupingTitle } from '../translations'; + +const getTermAggregation = (key: keyof VulnerabilitiesGroupingAggregation, field: string) => ({ + [key]: { + terms: { field, size: 1 }, + }, +}); + +const getAggregationsByGroupField = (field: string): NamedAggregation[] => { + if (isNoneGroup([field])) { + return []; + } + const aggMetrics: NamedAggregation[] = [ + { + groupByField: { + cardinality: { + field, + }, + }, + }, + ]; + + switch (field) { + case GROUPING_OPTIONS.RESOURCE_NAME: + return [...aggMetrics, getTermAggregation('resourceId', VULNERABILITY_FIELDS.RESOURCE_ID)]; + } + return aggMetrics; +}; + +/** + * Type Guard for checking if the given source is a VulnerabilitiesRootGroupingAggregation + */ +export const isVulnerabilitiesRootGroupingAggregation = ( + groupData: Record | undefined +): groupData is VulnerabilitiesRootGroupingAggregation => { + return groupData?.unitsCount?.value !== undefined; +}; + +/** + * Utility hook to get the latest vulnerabilities grouping data + * for the vulnerabilities page + */ +export const useLatestVulnerabilitiesGrouping = ({ + groupPanelRenderer, + groupStatsRenderer, +}: { + groupPanelRenderer?: GroupPanelRenderer; + groupStatsRenderer?: GroupStatsRenderer; +}) => { + const { dataView } = useDataViewContext(); + + const { + activePageIndex, + grouping, + pageSize, + query, + selectedGroup, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + setUrlQuery, + uniqueValue, + isNoneSelected, + onResetFilters, + error, + filters, + } = useCloudSecurityGrouping({ + dataView, + groupingTitle, + defaultGroupingOptions, + getDefaultQuery, + unit: VULNERABILITIES_UNIT, + groupPanelRenderer, + groupStatsRenderer, + groupingLocalStorageKey: LOCAL_STORAGE_VULNERABILITIES_GROUPING_KEY, + }); + + const groupingQuery = getGroupingQuery({ + additionalFilters: query ? [query] : [], + groupByField: selectedGroup, + uniqueValue, + from: `now-${LATEST_VULNERABILITIES_RETENTION_POLICY}`, + to: 'now', + pageNumber: activePageIndex * pageSize, + size: pageSize, + sort: [{ groupByField: { order: 'desc' } }], + statsAggregations: getAggregationsByGroupField(selectedGroup), + }); + + const { data, isFetching } = useGroupedVulnerabilities({ + query: groupingQuery, + enabled: !isNoneSelected, + }); + + const groupData = useMemo( + () => + parseGroupingQuery( + selectedGroup, + uniqueValue, + data as GroupingAggregation + ), + [data, selectedGroup, uniqueValue] + ); + + const isEmptyResults = + !isFetching && + isVulnerabilitiesRootGroupingAggregation(groupData) && + groupData.unitsCount?.value === 0; + + return { + groupData, + grouping, + isFetching, + activePageIndex, + pageSize, + selectedGroup, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + setUrlQuery, + isGroupSelected: !isNoneSelected, + isGroupLoading: !data, + onResetFilters, + filters, + error, + isEmptyResults, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_table.tsx new file mode 100644 index 0000000000000..6c6f9cd112c57 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_table.tsx @@ -0,0 +1,58 @@ +/* + * 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 { useMemo } from 'react'; +import { Filter } from '@kbn/es-query'; +import { LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY } from '../../../common/constants'; +import { FindingsBaseURLQuery } from '../../../common/types'; +import { useCloudPostureDataTable } from '../../../common/hooks/use_cloud_posture_data_table'; +import { useLatestVulnerabilities } from './use_latest_vulnerabilities'; + +const columnsLocalStorageKey = 'cloudPosture:latestVulnerabilities:columns'; + +export const useLatestVulnerabilitiesTable = ({ + getDefaultQuery, + nonPersistedFilters, +}: { + getDefaultQuery: (params: FindingsBaseURLQuery) => FindingsBaseURLQuery; + nonPersistedFilters?: Filter[]; +}) => { + const cloudPostureDataTable = useCloudPostureDataTable({ + paginationLocalStorageKey: LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY, + columnsLocalStorageKey, + defaultQuery: getDefaultQuery, + nonPersistedFilters, + }); + + const { query, sort, queryError, getRowsFromPages, pageSize } = cloudPostureDataTable; + + const { + data, + error: fetchError, + isFetching, + fetchNextPage, + } = useLatestVulnerabilities({ + query, + sort, + enabled: !queryError, + pageSize, + }); + + const rows = useMemo(() => getRowsFromPages(data?.pages), [data?.pages, getRowsFromPages]); + const total = data?.pages[0].total || 0; + + const error = fetchError || queryError; + + return { + cloudPostureDataTable, + rows, + error, + isFetching, + fetchNextPage, + total, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.ts deleted file mode 100644 index c09490d719f1f..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.ts +++ /dev/null @@ -1,86 +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 { useEuiTheme } from '@elastic/eui'; -import { css, keyframes } from '@emotion/css'; - -export const useStyles = () => { - const { euiTheme } = useEuiTheme(); - - const highlight = keyframes` - 0% { background-color: ${euiTheme.colors.warning};} - 50% { background-color: ${euiTheme.colors.emptyShade};} - 75% { background-color: ${euiTheme.colors.warning};} - 100% { background-color: ${euiTheme.colors.emptyShade};} - `; - - const gridStyle = css` - & .euiDataGrid__content { - background: transparent; - } - & .euiDataGridHeaderCell__icon { - display: none; - } - & .euiDataGrid__controls { - border-bottom: none; - margin-bottom: ${euiTheme.size.s}; - - & .euiButtonEmpty { - font-weight: ${euiTheme.font.weight.bold}; - } - } - & .euiDataGrid__leftControls { - > .euiButtonEmpty:hover:not(:disabled), - .euiButtonEmpty:focus { - text-decoration: none; - cursor: default; - } - } - & .euiButtonIcon { - color: ${euiTheme.colors.primary}; - } - & .euiDataGridRowCell { - font-size: ${euiTheme.size.m}; - - // Vertically center content - .euiDataGridRowCell__content { - display: flex; - align-items: center; - } - } - /* EUI QUESTION: Why is this being done via CSS instead of setting isExpandable: false in the columns API? */ - & .euiDataGridRowCell__actions > .euiDataGridRowCell__expandCell { - display: none; - } - & .euiDataGridRowCell.euiDataGridRowCell--numeric { - text-align: left; - } - & .euiDataGridHeaderCell--numeric .euiDataGridHeaderCell__content { - flex-grow: 0; - text-align: left; - } - `; - - const highlightStyle = css` - & [data-test-subj='dataGridColumnSortingButton'] .euiButtonEmpty__text { - animation: ${highlight} 1s ease-out infinite; - color: ${euiTheme.colors.darkestShade}; - } - `; - - const groupBySelector = css` - width: 188px; - display: inline-block; - margin-left: 8px; - `; - - return { - highlightStyle, - gridStyle, - groupBySelector, - }; -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_container.tsx new file mode 100644 index 0000000000000..8ba50c3aac4f1 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_container.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 { Filter } from '@kbn/es-query'; +import React from 'react'; +import { EuiSpacer } from '@elastic/eui'; +import { useLatestVulnerabilitiesGrouping } from './hooks/use_latest_vulnerabilities_grouping'; +import { LatestVulnerabilitiesTable } from './latest_vulnerabilities_table'; +import { groupPanelRenderer, groupStatsRenderer } from './latest_vulnerabilities_group_renderer'; +import { FindingsSearchBar } from '../configurations/layout/findings_search_bar'; +import { ErrorCallout } from '../configurations/layout/error_callout'; +import { EmptyState } from '../../components/empty_state'; +import { CloudSecurityGrouping } from '../../components/cloud_security_grouping'; +import { DEFAULT_GROUPING_TABLE_HEIGHT } from '../../common/constants'; + +export const LatestVulnerabilitiesContainer = () => { + const renderChildComponent = (groupFilters: Filter[]) => { + return ( + + ); + }; + + const { + isGroupSelected, + groupData, + grouping, + isFetching, + activePageIndex, + pageSize, + selectedGroup, + onChangeGroupsItemsPerPage, + onChangeGroupsPage, + setUrlQuery, + isGroupLoading, + onResetFilters, + error, + isEmptyResults, + } = useLatestVulnerabilitiesGrouping({ groupPanelRenderer, groupStatsRenderer }); + + if (error || isEmptyResults) { + return ( + <> + + + {error && } + {isEmptyResults && } + + ); + } + if (isGroupSelected) { + return ( + <> + +
+ + +
+ + ); + } + + return ( + <> + + + + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_group_renderer.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_group_renderer.tsx new file mode 100644 index 0000000000000..82626fd684513 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_group_renderer.tsx @@ -0,0 +1,124 @@ +/* + * 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 { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiTextBlockTruncate, + EuiToolTip, + useEuiTheme, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { GroupPanelRenderer, RawBucket, StatRenderer } from '@kbn/securitysolution-grouping/src'; +import React from 'react'; +import { VulnerabilitiesGroupingAggregation } from './hooks/use_grouped_vulnerabilities'; +import { GROUPING_OPTIONS } from './constants'; +import { VULNERABILITIES_GROUPING_COUNTER } from './test_subjects'; +import { NULL_GROUPING_MESSAGES, NULL_GROUPING_UNIT, VULNERABILITIES } from './translations'; +import { getAbbreviatedNumber } from '../../common/utils/get_abbreviated_number'; +import { LoadingGroup, NullGroup } from '../../components/cloud_security_grouping'; + +export const groupPanelRenderer: GroupPanelRenderer = ( + selectedGroup, + bucket, + nullGroupMessage, + isLoading +) => { + if (isLoading) { + return ; + } + + const renderNullGroup = (title: string) => ( + + ); + + switch (selectedGroup) { + case GROUPING_OPTIONS.RESOURCE_NAME: + return nullGroupMessage ? ( + renderNullGroup(NULL_GROUPING_MESSAGES.RESOURCE_NAME) + ) : ( + + + + + + + {bucket.key_as_string} {bucket.resourceId?.buckets?.[0].key} + + + + + + + ); + default: + return nullGroupMessage ? ( + renderNullGroup(NULL_GROUPING_MESSAGES.DEFAULT) + ) : ( + + + + + + {bucket.key_as_string} + + + + + + ); + } +}; + +const VulnerabilitiesCountComponent = ({ + bucket, +}: { + bucket: RawBucket; +}) => { + const { euiTheme } = useEuiTheme(); + + return ( + + + {getAbbreviatedNumber(bucket.doc_count)} + + + ); +}; + +const VulnerabilitiesCount = React.memo(VulnerabilitiesCountComponent); + +export const groupStatsRenderer = ( + selectedGroup: string, + bucket: RawBucket +): StatRenderer[] => { + const defaultBadges = [ + { + title: VULNERABILITIES, + renderer: , + }, + ]; + + return defaultBadges; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx new file mode 100644 index 0000000000000..b27ebfb459fe4 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/latest_vulnerabilities_table.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { DataTableRecord } from '@kbn/discover-utils/types'; +import { i18n } from '@kbn/i18n'; +import { EuiDataGridCellValueElementProps, EuiSpacer } from '@elastic/eui'; +import { Filter } from '@kbn/es-query'; +import { CspVulnerabilityFinding } from '../../../common/schemas'; +import { CloudSecurityDataTable } from '../../components/cloud_security_data_table'; +import { useLatestVulnerabilitiesTable } from './hooks/use_latest_vulnerabilities_table'; +import { LATEST_VULNERABILITIES_TABLE } from './test_subjects'; +import { getDefaultQuery, defaultColumns } from './constants'; +import { VulnerabilityFindingFlyout } from './vulnerabilities_finding_flyout/vulnerability_finding_flyout'; +import { ErrorCallout } from '../configurations/layout/error_callout'; +import { CVSScoreBadge, SeverityStatusBadge } from '../../components/vulnerability_badges'; + +interface LatestVulnerabilitiesTableProps { + groupSelectorComponent?: JSX.Element; + height?: number; + nonPersistedFilters?: Filter[]; +} +/** + * Type Guard for checking if the given source is a CspVulnerabilityFinding + */ +const isCspVulnerabilityFinding = ( + source: Record | undefined +): source is CspVulnerabilityFinding => { + return source?.vulnerability?.id !== undefined; +}; + +/** + * This Wrapper component renders the children if the given row is a CspVulnerabilityFinding + * it uses React's Render Props pattern + */ +const CspVulnerabilityFindingRenderer = ({ + row, + children, +}: { + row: DataTableRecord; + children: ({ finding }: { finding: CspVulnerabilityFinding }) => JSX.Element; +}) => { + const source = row.raw._source; + const finding = isCspVulnerabilityFinding(source) && (source as CspVulnerabilityFinding); + if (!finding) return <>; + return children({ finding }); +}; + +const flyoutComponent = (row: DataTableRecord, onCloseFlyout: () => void): JSX.Element => { + return ( + + {({ finding }) => ( + + )} + + ); +}; + +const title = i18n.translate('xpack.csp.findings.latestVulnerabilities.tableRowTypeLabel', { + defaultMessage: 'Vulnerabilities', +}); + +const customCellRenderer = (rows: DataTableRecord[]) => ({ + 'vulnerability.score.base': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( + + {({ finding }) => ( + + )} + + ), + 'vulnerability.severity': ({ rowIndex }: EuiDataGridCellValueElementProps) => ( + + {({ finding }) => } + + ), +}); + +export const LatestVulnerabilitiesTable = ({ + groupSelectorComponent, + height, + nonPersistedFilters, +}: LatestVulnerabilitiesTableProps) => { + const { cloudPostureDataTable, rows, total, error, isFetching, fetchNextPage } = + useLatestVulnerabilitiesTable({ + getDefaultQuery, + nonPersistedFilters, + }); + + const { filters } = cloudPostureDataTable; + + return ( + <> + {error ? ( + <> + + + + ) : ( + 0 ? 404 : 364}px)`} + /> + )} + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts index 72211cc778431..8ad512f8a41ee 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts @@ -13,3 +13,7 @@ export const OVERVIEW_TAB_VULNERABILITY_FLYOUT = 'vulnerability_overview_tab_fly export const SEVERITY_STATUS_VULNERABILITY_FLYOUT = 'vulnerability_severity_status_flyout'; export const TAB_ID_VULNERABILITY_FLYOUT = (tabId: string) => `vulnerability-finding-flyout-tab-${tabId}`; + +export const LATEST_VULNERABILITIES_TABLE = 'latest_vulnerabilities_table'; + +export const VULNERABILITIES_GROUPING_COUNTER = 'vulnerabilities_grouping_counter'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts index b2c0ca0ca8366..65ca61056f612 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/translations.ts @@ -22,3 +22,35 @@ export const SEARCH_BAR_PLACEHOLDER = i18n.translate( export const VULNERABILITIES = i18n.translate('xpack.csp.vulnerabilities', { defaultMessage: 'Vulnerabilities', }); + +export const VULNERABILITIES_UNIT = (totalCount: number) => + i18n.translate('xpack.csp.vulnerabilities.unit', { + values: { totalCount }, + defaultMessage: `{totalCount, plural, =1 {vulnerability} other {vulnerabilities}}`, + }); + +export const NULL_GROUPING_UNIT = i18n.translate( + 'xpack.csp.vulnerabilities.grouping.nullGroupUnit', + { + defaultMessage: 'vulnerabilities', + } +); + +export const NULL_GROUPING_MESSAGES = { + RESOURCE_NAME: i18n.translate('xpack.csp.vulnerabilities.grouping.resource.nullGroupTitle', { + defaultMessage: 'No resource', + }), + DEFAULT: i18n.translate('xpack.csp.vulnerabilities.grouping.default.nullGroupTitle', { + defaultMessage: 'No grouping', + }), +}; + +export const GROUPING_LABELS = { + RESOURCE_NAME: i18n.translate('xpack.csp.findings.latestFindings.groupByResource', { + defaultMessage: 'Resource', + }), +}; + +export const groupingTitle = i18n.translate('xpack.csp.vulnerabilities.latestFindings.groupBy', { + defaultMessage: 'Group vulnerabilities by', +}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_filters.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_filters.ts deleted file mode 100644 index 7f7d9ff544c62..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_filters.ts +++ /dev/null @@ -1,65 +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 { - type Filter, - buildFilter, - FILTERS, - FilterStateStore, - compareFilters, - FilterCompareOptions, -} from '@kbn/es-query'; -import type { Serializable } from '@kbn/utility-types'; -import type { FindingsBaseProps } from '../../../common/types'; - -const compareOptions: FilterCompareOptions = { - negate: false, -}; - -/** - * adds a new filter to a new filters array - * removes existing filter if negated filter is added - * - * @returns {Filter[]} a new array of filters to be added back to filterManager - */ -export const getFilters = ({ - filters: existingFilters, - dataView, - field, - value, - negate, -}: { - filters: Filter[]; - dataView: FindingsBaseProps['dataView']; - field: string; - value: Serializable; - negate: boolean; -}): Filter[] => { - const dataViewField = dataView.fields.find((f) => f.spec.name === field); - if (!dataViewField) return existingFilters; - - const phraseFilter = buildFilter( - dataView, - dataViewField, - FILTERS.PHRASE, - negate, - false, - value, - null, - FilterStateStore.APP_STATE - ); - - const nextFilters = [ - ...existingFilters.filter( - // Exclude existing filters that match the newly added 'phraseFilter' - (filter) => !compareFilters(filter, phraseFilter, compareOptions) - ), - phraseFilter, - ]; - - return nextFilters; -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.test.tsx deleted file mode 100644 index 1f84f294d8be1..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.test.tsx +++ /dev/null @@ -1,189 +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 { getRowValueByColumnId } from './get_vulnerabilities_grid_cell_actions'; -import { vulnerabilitiesColumns } from '../vulnerabilities_table_columns'; -import { vulnerabilitiesByResourceColumns } from '../vulnerabilities_by_resource/vulnerabilities_by_resource_table_columns'; -import { CspVulnerabilityFinding } from '../../../../common/schemas'; - -describe('getRowValueByColumnId', () => { - it('should return vulnerability id', () => { - const vulnerabilityRow = { - vulnerability: { - id: 'CVE-2017-1000117', - }, - }; - const columns = vulnerabilitiesColumns; - const columnId = columns.vulnerability; - - expect( - getRowValueByColumnId(vulnerabilityRow as Partial, columns, columnId) - ).toEqual('CVE-2017-1000117'); - }); - - it('should return base as a vulnerability score', () => { - const vulnerabilityRow = { - vulnerability: { - score: { - base: 5, - version: 'v1', - }, - }, - }; - const columns = vulnerabilitiesColumns; - const columnId = columns.cvss; - - expect( - getRowValueByColumnId(vulnerabilityRow as Partial, columns, columnId) - ).toEqual(5); - }); - - it('should return undefined when no base score is available', () => { - const vulnerabilityRow = { - vulnerability: {}, - }; - const columns = vulnerabilitiesColumns; - const columnId = columns.cvss; - - expect( - getRowValueByColumnId(vulnerabilityRow as Partial, columns, columnId) - ).toEqual(undefined); - - const vulnerabilityRow2 = { - vulnerability: { - score: { - version: 'v1', - }, - }, - }; - - expect( - getRowValueByColumnId( - vulnerabilityRow2 as Partial, - columns, - columnId - ) - ).toEqual(undefined); - }); - - it('should return resource id', () => { - const vulnerabilityRow = { - resource: { - id: 'i-1234567890abcdef0', - }, - }; - const columns = vulnerabilitiesByResourceColumns; - const columnId = columns.resourceId; - - expect( - getRowValueByColumnId(vulnerabilityRow as Partial, columns, columnId) - ).toEqual('i-1234567890abcdef0'); - }); - - it('should return resource name', () => { - const vulnerabilityRow = { - resource: { - name: 'test', - }, - }; - const columns1 = vulnerabilitiesByResourceColumns; - const columns2 = vulnerabilitiesColumns; - const columnId1 = columns1.resourceName; - const columnId2 = columns2.resourceName; - - expect( - getRowValueByColumnId( - vulnerabilityRow as Partial, - columns1, - columnId1 - ) - ).toEqual('test'); - expect( - getRowValueByColumnId( - vulnerabilityRow as Partial, - columns2, - columnId2 - ) - ).toEqual('test'); - }); - - it('should return vulnerability severity', () => { - const vulnerabilityRow = { - vulnerability: { - severity: 'high', - }, - }; - const columns = vulnerabilitiesColumns; - const columnId = columns.severity; - - expect( - getRowValueByColumnId(vulnerabilityRow as Partial, columns, columnId) - ).toEqual('high'); - }); - - it('should return package fields', () => { - const vulnerabilityRow = { - package: { - name: 'test', - version: '1.0.0', - fixed_version: '1.0.1', - }, - }; - const columns1 = vulnerabilitiesColumns; - const columnId1 = columns1.package; - const columnId2 = columns1.version; - const columnId3 = columns1.fixedVersion; - - expect( - getRowValueByColumnId( - vulnerabilityRow as Partial, - columns1, - columnId1 - ) - ).toEqual('test'); - expect( - getRowValueByColumnId( - vulnerabilityRow as Partial, - columns1, - columnId2 - ) - ).toEqual('1.0.0'); - expect( - getRowValueByColumnId( - vulnerabilityRow as Partial, - columns1, - columnId3 - ) - ).toEqual('1.0.1'); - }); - - it('should return undefined is package is missing', () => { - const vulnerabilityRow = { - vulnerability: {}, - }; - const columns = vulnerabilitiesColumns; - const columnId = columns.package; - - expect( - getRowValueByColumnId(vulnerabilityRow as Partial, columns, columnId) - ).toEqual(undefined); - }); - - it('should return cloud region', () => { - const vulnerabilityRow = { - cloud: { - region: 'us-east-1', - }, - }; - const columns = vulnerabilitiesByResourceColumns; - const columnId = columns.region; - - expect( - getRowValueByColumnId(vulnerabilityRow as Partial, columns, columnId) - ).toEqual('us-east-1'); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.tsx deleted file mode 100644 index dbde094d6f43b..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.tsx +++ /dev/null @@ -1,166 +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 { EuiDataGridColumn, EuiDataGridColumnCellAction, EuiToolTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { CspVulnerabilityFinding } from '../../../../common/schemas'; -import { getFilters } from './get_filters'; -import { FILTER_IN, FILTER_OUT } from '../translations'; - -export const getRowValueByColumnId = ( - vulnerabilityRow: Partial, - columns: Record, - columnId: string -) => { - if (columnId === columns.vulnerability) { - return vulnerabilityRow.vulnerability?.id; - } - if (columnId === columns.cvss) { - return vulnerabilityRow.vulnerability?.score?.base; - } - if (columnId === columns.resourceId) { - return vulnerabilityRow.resource?.id; - } - if (columnId === columns.resourceName) { - return vulnerabilityRow.resource?.name; - } - if (columnId === columns.severity) { - return vulnerabilityRow.vulnerability?.severity; - } - if (columnId === columns.package) { - return vulnerabilityRow.package?.name; - } - if (columnId === columns.version) { - return vulnerabilityRow.package?.version; - } - if (columnId === columns.fixedVersion) { - return vulnerabilityRow.package?.fixed_version; - } - if (columnId === columns.region) { - return vulnerabilityRow.cloud?.region; - } -}; - -export const getVulnerabilitiesGridCellActions = < - T extends Array> ->({ - data, - columns, - columnGridFn, - pageSize, - setUrlQuery, - filters, - dataView, -}: { - data: T; - columns: Record; - columnGridFn: (cellActions: EuiDataGridColumnCellAction[]) => EuiDataGridColumn[]; - pageSize: number; - setUrlQuery: (query: any) => void; - filters: any; - dataView: any; -}) => { - const getColumnIdValue = (rowIndex: number, columnId: string) => { - const vulnerabilityRow = data[rowIndex]; - if (!vulnerabilityRow) return null; - - return getRowValueByColumnId(vulnerabilityRow, columns, columnId); - }; - - const cellActions: EuiDataGridColumnCellAction[] = [ - ({ Component, rowIndex, columnId }) => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const value = getColumnIdValue(rowIndexFromPage, columnId); - - if (!value) return null; - return ( - - { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters, - dataView, - field: columnId, - value, - negate: false, - }), - }); - }} - > - {FILTER_IN} - - - ); - }, - ({ Component, rowIndex, columnId }) => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const value = getColumnIdValue(rowIndexFromPage, columnId); - - if (!value) return null; - return ( - - { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters, - dataView, - field: columnId, - value, - negate: true, - }), - }); - }} - > - {FILTER_OUT} - - - ); - }, - ]; - - return columnGridFn(cellActions); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx index 9c74d7640beac..aca54e19bfccf 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx @@ -4,486 +4,42 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { - EuiButtonEmpty, - EuiButtonIcon, - EuiDataGrid, - EuiDataGridCellValueElementProps, - EuiFlexItem, - EuiProgress, - EuiSpacer, - useEuiTheme, -} from '@elastic/eui'; -import { cx } from '@emotion/css'; -import { DataView } from '@kbn/data-views-plugin/common'; -import React, { useCallback, useMemo, useState, useEffect } from 'react'; -import { i18n } from '@kbn/i18n'; +import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../common/constants'; -import { - CloudPostureTableResult, - useCloudPostureTable, -} from '../../common/hooks/use_cloud_posture_table'; -import { useLatestVulnerabilities } from './hooks/use_latest_vulnerabilities'; -import type { VulnerabilitiesQueryData } from './types'; import { LATEST_VULNERABILITIES_INDEX_PATTERN } from '../../../common/constants'; -import { ErrorCallout } from '../configurations/layout/error_callout'; -import { FindingsSearchBar } from '../configurations/layout/findings_search_bar'; -import { CVSScoreBadge, SeverityStatusBadge } from '../../components/vulnerability_badges'; -import { EmptyState } from '../../components/empty_state'; -import { VulnerabilityFindingFlyout } from './vulnerabilities_finding_flyout/vulnerability_finding_flyout'; import { NoVulnerabilitiesStates } from '../../components/no_vulnerabilities_states'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; -import { useLimitProperties } from '../../common/utils/get_limit_properties'; -import { LimitedResultsBar } from '../configurations/layout/findings_layout'; -import { - getVulnerabilitiesColumnsGrid, - vulnerabilitiesColumns, -} from './vulnerabilities_table_columns'; -import { defaultLoadingRenderer, defaultNoDataRenderer } from '../../components/cloud_posture_page'; -import { SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from './translations'; -import { - severitySchemaConfig, - severitySortScript, - getCaseInsensitiveSortScript, -} from './utils/custom_sort_script'; -import { useStyles } from './hooks/use_styles'; -import { FindingsGroupBySelector } from '../configurations/layout/findings_group_by_selector'; -import { vulnerabilitiesPathnameHandler } from './utils/vulnerabilities_pathname_handler'; +import { CloudPosturePage } from '../../components/cloud_posture_page'; import { findingsNavigation } from '../../common/navigation/constants'; -import { VulnerabilitiesByResource } from './vulnerabilities_by_resource/vulnerabilities_by_resource'; -import { ResourceVulnerabilities } from './vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities'; -import { getVulnerabilitiesGridCellActions } from './utils/get_vulnerabilities_grid_cell_actions'; import { useLatestFindingsDataView } from '../../common/api/use_latest_findings_data_view'; - -const getDefaultQuery = ({ query, filters }: any): any => ({ - query, - filters, - sort: [ - { id: vulnerabilitiesColumns.severity, direction: 'desc' }, - { id: vulnerabilitiesColumns.cvss, direction: 'desc' }, - ], - pageIndex: 0, -}); - -const VulnerabilitiesDataGrid = ({ - dataView, - data, - isFetching, - onChangeItemsPerPage, - onChangePage, - onSort, - urlQuery, - onResetFilters, - pageSize, - setUrlQuery, - pageIndex, - sort, -}: { - dataView: DataView; - data: VulnerabilitiesQueryData | undefined; - isFetching: boolean; -} & Pick< - CloudPostureTableResult, - | 'pageIndex' - | 'sort' - | 'pageSize' - | 'onChangeItemsPerPage' - | 'onChangePage' - | 'onSort' - | 'urlQuery' - | 'setUrlQuery' - | 'onResetFilters' ->) => { - const { euiTheme } = useEuiTheme(); - const styles = useStyles(); - const [showHighlight, setHighlight] = useState(false); - - const invalidIndex = -1; - - const selectedVulnerability = useMemo(() => { - if (urlQuery.vulnerabilityIndex !== undefined) { - return data?.page[urlQuery.vulnerabilityIndex]; - } - }, [data?.page, urlQuery.vulnerabilityIndex]); - - const onCloseFlyout = () => { - setUrlQuery({ - vulnerabilityIndex: invalidIndex, - }); - }; - - const onSortHandler = useCallback( - (newSort: any) => { - onSort(newSort); - if (newSort.length !== sort.length) { - setHighlight(true); - setTimeout(() => { - setHighlight(false); - }, 2000); - } - }, - [onSort, sort] - ); - - const { isLastLimitedPage, limitedTotalItemCount } = useLimitProperties({ - total: data?.total, - pageIndex, - pageSize, - }); - - const onOpenFlyout = useCallback( - (vulnerabilityRow: VulnerabilitiesQueryData['page'][number]) => { - const vulnerabilityIndex = data?.page.findIndex( - (vulnerabilityRecord: VulnerabilitiesQueryData['page'][number]) => - vulnerabilityRecord.vulnerability?.id === vulnerabilityRow.vulnerability?.id && - vulnerabilityRecord.resource?.id === vulnerabilityRow.resource?.id && - vulnerabilityRecord.package.name === vulnerabilityRow.package.name && - vulnerabilityRecord.package.version === vulnerabilityRow.package.version - ); - setUrlQuery({ - vulnerabilityIndex, - }); - }, - [setUrlQuery, data?.page] - ); - - const columns = useMemo(() => { - if (!data?.page) { - return []; - } - return getVulnerabilitiesGridCellActions({ - columnGridFn: getVulnerabilitiesColumnsGrid, - columns: vulnerabilitiesColumns, - dataView, - pageSize, - data: data.page, - setUrlQuery, - filters: urlQuery.filters, - }); - }, [data?.page, dataView, pageSize, setUrlQuery, urlQuery.filters]); - - // Column visibility - const [visibleColumns, setVisibleColumns] = useState( - columns.map(({ id }) => id) // initialize to the full set of columns - ); - - const flyoutVulnerabilityIndex = urlQuery?.vulnerabilityIndex; - - const selectedVulnerabilityIndex = flyoutVulnerabilityIndex - ? flyoutVulnerabilityIndex + pageIndex * pageSize - : undefined; - - const renderCellValue = useMemo(() => { - const Cell: React.FC = ({ - columnId, - rowIndex, - setCellProps, - }): React.ReactElement | null => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const vulnerabilityRow = data?.page[rowIndexFromPage]; - - useEffect(() => { - if (selectedVulnerabilityIndex === rowIndex) { - setCellProps({ - style: { - backgroundColor: euiTheme.colors.highlight, - }, - }); - } else { - setCellProps({ - style: { - backgroundColor: 'inherit', - }, - }); - } - }, [rowIndex, setCellProps]); - - if (isFetching) return null; - if (!vulnerabilityRow) return null; - if (!vulnerabilityRow.vulnerability?.id) return null; - - if (columnId === vulnerabilitiesColumns.actions) { - return ( - { - onOpenFlyout(vulnerabilityRow); - }} - /> - ); - } - if (columnId === vulnerabilitiesColumns.vulnerability) { - return <>{vulnerabilityRow.vulnerability?.id}; - } - if (columnId === vulnerabilitiesColumns.cvss) { - if ( - !vulnerabilityRow.vulnerability.score?.base || - !vulnerabilityRow.vulnerability.score?.version - ) { - return null; - } - return ( - - ); - } - if (columnId === vulnerabilitiesColumns.resourceName) { - return <>{vulnerabilityRow.resource?.name}; - } - if (columnId === vulnerabilitiesColumns.resourceId) { - return <>{vulnerabilityRow.resource?.id}; - } - if (columnId === vulnerabilitiesColumns.severity) { - if (!vulnerabilityRow.vulnerability.severity) { - return null; - } - return ; - } - - if (columnId === vulnerabilitiesColumns.package) { - return <>{vulnerabilityRow?.package?.name}; - } - if (columnId === vulnerabilitiesColumns.version) { - return <>{vulnerabilityRow?.package?.version}; - } - if (columnId === vulnerabilitiesColumns.fixedVersion) { - return <>{vulnerabilityRow?.package?.fixed_version}; - } - - return null; - }; - - return Cell; - }, [ - data?.page, - euiTheme.colors.highlight, - onOpenFlyout, - pageSize, - selectedVulnerabilityIndex, - isFetching, - ]); - - const showVulnerabilityFlyout = flyoutVulnerabilityIndex > invalidIndex; - - if (data?.page.length === 0) { - return ; - } - - const dataTableStyle = { - // Change the height of the grid to fit the page - // If there are filters, leave space for the filter bar - // Todo: Replace this component with EuiAutoSizer - height: `calc(100vh - ${urlQuery.filters.length > 0 ? 403 : 363}px)`, - minHeight: 400, - }; - - return ( - <> - -
- - - {i18n.translate('xpack.csp.vulnerabilities.totalVulnerabilities', { - defaultMessage: - '{total, plural, one {# Vulnerability} other {# Vulnerabilities}}', - values: { total: data?.total }, - })} - - - ), - }, - right: ( - - - - ), - }, - }} - gridStyle={{ - border: 'horizontal', - cellPadding: 'l', - stripes: false, - rowHover: 'none', - header: 'underline', - }} - renderCellValue={renderCellValue} - inMemory={{ level: 'enhancements' }} - sorting={{ columns: sort, onSort: onSortHandler }} - pagination={{ - pageIndex, - pageSize, - pageSizeOptions: [10, 25, 100], - onChangeItemsPerPage, - onChangePage, - }} - virtualizationOptions={{ - overscanRowCount: 20, - }} - /> - {isLastLimitedPage && } -
- {showVulnerabilityFlyout && selectedVulnerability && ( - - )} - - ); -}; - -const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { - const { - sort, - query, - queryError, - pageSize, - pageIndex, - onChangeItemsPerPage, - onChangePage, - onSort, - urlQuery, - setUrlQuery, - onResetFilters, - } = useCloudPostureTable({ - dataView, - defaultQuery: getDefaultQuery, - paginationLocalStorageKey: LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY, - }); - - const multiFieldsSort = useMemo(() => { - return sort.map(({ id, direction }: { id: string; direction: string }) => { - if (id === vulnerabilitiesColumns.severity) { - return severitySortScript(direction); - } - if (id === vulnerabilitiesColumns.package) { - return getCaseInsensitiveSortScript(id, direction); - } - - return { - [id]: direction, - }; - }); - }, [sort]); - - const { data, isLoading, isFetching } = useLatestVulnerabilities({ - query, - sort: multiFieldsSort, - enabled: !queryError, - pageIndex, - pageSize, - }); - - const error = queryError || null; - - if (isLoading && !error) { - return defaultLoadingRenderer(); - } - - if (!data?.page && !error) { - return defaultNoDataRenderer(); - } - - return ( - <> - { - setUrlQuery({ ...newQuery, pageIndex: 0 }); - }} - loading={isFetching} - placeholder={SEARCH_BAR_PLACEHOLDER} - /> - - {error && } - {!error && ( - - )} - - ); -}; +import { LatestVulnerabilitiesContainer } from './latest_vulnerabilities_container'; +import { DataViewContext } from '../../common/contexts/data_view_context'; export const Vulnerabilities = () => { - const { data, isLoading, error } = useLatestFindingsDataView( - LATEST_VULNERABILITIES_INDEX_PATTERN - ); + const dataViewQuery = useLatestFindingsDataView(LATEST_VULNERABILITIES_INDEX_PATTERN); const getSetupStatus = useCspSetupStatusApi(); if (getSetupStatus?.data?.vuln_mgmt?.status !== 'indexed') return ; - if (error) { - return ; - } - if (isLoading) { - return defaultLoadingRenderer(); - } - - if (!data) { - return defaultNoDataRenderer(); - } + const dataViewContextValue = { + dataView: dataViewQuery.data!, + dataViewRefetch: dataViewQuery.refetch, + dataViewIsRefetching: dataViewQuery.isRefetching, + }; return ( - - } - /> - } - /> - } - /> - + + + ( + + + + )} + /> + + ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/__mocks__/vulnerabilities_by_resource.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/__mocks__/vulnerabilities_by_resource.mock.ts deleted file mode 100644 index 4ad13e2d215a1..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/__mocks__/vulnerabilities_by_resource.mock.ts +++ /dev/null @@ -1,35 +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 getVulnerabilitiesByResourceData = () => ({ - total: 2, - total_vulnerabilities: 8, - page: [ - { - resource: { id: 'resource-id-1', name: 'resource-test-1' }, - cloud: { region: 'us-test-1' }, - vulnerabilities_count: 4, - severity_map: { - critical: 1, - high: 1, - medium: 1, - low: 1, - }, - }, - { - resource: { id: 'resource-id-2', name: 'resource-test-2' }, - cloud: { region: 'us-test-1' }, - vulnerabilities_count: 4, - severity_map: { - critical: 1, - high: 1, - medium: 1, - low: 1, - }, - }, - ], -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/__mocks__/resource_vulnerabilities.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/__mocks__/resource_vulnerabilities.mock.ts deleted file mode 100644 index 8328192062cc0..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/__mocks__/resource_vulnerabilities.mock.ts +++ /dev/null @@ -1,122 +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 getResourceVulnerabilitiesMockData = () => ({ - page: [ - { - agent: { - name: 'ip-172-31-15-210', - id: '2d262db5-b637-4e46-a2a0-db409825ff46', - ephemeral_id: '2af1be77-0bdf-4313-b375-592848fe60d7', - type: 'cloudbeat', - version: '8.8.0', - }, - package: { - path: 'usr/lib/snapd/snapd', - fixed_version: '3.0.0-20220521103104-8f96da9f5d5e', - name: 'gopkg.in/yaml.v3', - type: 'gobinary', - version: 'v3.0.0-20210107192922-496545a6307b', - }, - resource: { - name: 'elastic-agent-instance-a6c683d0-0977-11ee-bb0b-0af2059ffbbf', - id: '0d103e99f17f355ba', - }, - elastic_agent: { - id: '2d262db5-b637-4e46-a2a0-db409825ff46', - version: '8.8.0', - snapshot: false, - }, - vulnerability: { - severity: 'HIGH', - package: { - fixed_version: '3.0.0-20220521103104-8f96da9f5d5e', - name: 'gopkg.in/yaml.v3', - version: 'v3.0.0-20210107192922-496545a6307b', - }, - description: - 'An issue in the Unmarshal function in Go-Yaml v3 causes the program to crash when attempting to deserialize invalid input.', - title: 'crash when attempting to deserialize invalid input', - classification: 'CVSS', - data_source: { - ID: 'go-vulndb', - URL: 'https://github.com/golang/vulndb', - Name: 'The Go Vulnerability Database', - }, - cwe: ['CWE-502'], - reference: 'https://avd.aquasec.com/nvd/cve-2022-28948', - score: { - version: '3.1', - base: 7.5, - }, - report_id: 1686633719, - scanner: { - vendor: 'Trivy', - version: 'v0.35.0', - }, - id: 'CVE-2022-28948', - enumeration: 'CVE', - published_date: '2022-05-19T20:15:00Z', - class: 'lang-pkgs', - cvss: { - redhat: { - V3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H', - V3Score: 7.5, - }, - nvd: { - V3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H', - V2Vector: 'AV:N/AC:L/Au:N/C:N/I:N/A:P', - V3Score: 7.5, - V2Score: 5, - }, - ghsa: { - V3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H', - V3Score: 7.5, - }, - }, - }, - cloud: { - provider: 'aws', - region: 'us-east-1', - account: { - name: 'elastic-security-cloud-security-dev', - id: '704479110758', - }, - }, - '@timestamp': '2023-06-13T06:15:16.182Z', - cloudbeat: { - commit_sha: '8497f3a4b4744c645233c5a13b45400367411c2f', - commit_time: '2023-05-09T16:07:58Z', - version: '8.8.0', - }, - ecs: { - version: '8.6.0', - }, - data_stream: { - namespace: 'default', - type: 'logs', - dataset: 'cloud_security_posture.vulnerabilities', - }, - host: { - name: 'ip-172-31-15-210', - }, - event: { - agent_id_status: 'auth_metadata_missing', - sequence: 1686633719, - ingested: '2023-06-15T18:37:56Z', - created: '2023-06-13T06:15:16.18250081Z', - kind: 'state', - id: '5cad2983-4a74-455d-ab39-6c584acd3994', - type: ['info'], - category: ['vulnerability'], - dataset: 'cloud_security_posture.vulnerabilities', - outcome: 'success', - }, - }, - ], - total: 1, -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.test.tsx deleted file mode 100644 index 9de1a61bebe38..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.test.tsx +++ /dev/null @@ -1,123 +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 { render, screen } from '@testing-library/react'; -import { useParams } from 'react-router-dom'; -import { ResourceVulnerabilities } from './resource_vulnerabilities'; -import { TestProvider } from '../../../../test/test_provider'; -import { useLatestVulnerabilities } from '../../hooks/use_latest_vulnerabilities'; -import { getResourceVulnerabilitiesMockData } from './__mocks__/resource_vulnerabilities.mock'; -import { VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ } from '../../../../components/test_subjects'; - -jest.mock('../../hooks/use_latest_vulnerabilities', () => ({ - useLatestVulnerabilities: jest.fn(), -})); -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: jest.fn().mockReturnValue({ - integration: undefined, - }), -})); - -beforeEach(() => { - jest.clearAllMocks(); -}); - -describe('ResourceVulnerabilities', () => { - const dataView: any = {}; - - const renderVulnerabilityByResource = () => { - return render( - - - - ); - }; - - it('renders the loading state', () => { - (useLatestVulnerabilities as jest.Mock).mockReturnValue({ - data: undefined, - isLoading: true, - isFetching: true, - }); - renderVulnerabilityByResource(); - expect(screen.getByText(/loading/i)).toBeInTheDocument(); - }); - it('renders the no data state', () => { - (useLatestVulnerabilities as jest.Mock).mockReturnValue({ - data: undefined, - isLoading: false, - isFetching: false, - }); - - renderVulnerabilityByResource(); - expect(screen.getByText(/no data/i)).toBeInTheDocument(); - }); - - it('applies the correct filter on fetch', () => { - const resourceId = 'test'; - (useParams as jest.Mock).mockReturnValue({ - resourceId, - }); - renderVulnerabilityByResource(); - expect(useLatestVulnerabilities).toHaveBeenCalledWith( - expect.objectContaining({ - query: { - bool: { - filter: [ - { - term: { - 'resource.id': resourceId, - }, - }, - ], - must: [], - must_not: [], - should: [], - }, - }, - }) - ); - }); - - it('renders the empty state component', () => { - (useLatestVulnerabilities as jest.Mock).mockReturnValue({ - data: { total: 0, total_vulnerabilities: 0, page: [] }, - isLoading: false, - isFetching: false, - }); - - renderVulnerabilityByResource(); - expect(screen.getByText(/no results/i)).toBeInTheDocument(); - }); - - it('renders the Table', () => { - (useLatestVulnerabilities as jest.Mock).mockReturnValue({ - data: getResourceVulnerabilitiesMockData(), - isLoading: false, - isFetching: false, - }); - - renderVulnerabilityByResource(); - - // Header - expect(screen.getByText(/0d103e99f17f355ba/i)).toBeInTheDocument(); - expect(screen.getByText(/us-east-1/i)).toBeInTheDocument(); - expect( - screen.getByText(/elastic-agent-instance-a6c683d0-0977-11ee-bb0b-0af2059ffbbf/i) - ).toBeInTheDocument(); - - // Table - expect(screen.getByText(/CVE-2022-28948/i)).toBeInTheDocument(); - expect(screen.getByTestId(VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ)).toHaveTextContent(/7.5/i); - expect(screen.getByTestId(VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ)).toHaveTextContent(/v3/i); - expect(screen.getByText(/high/i)).toBeInTheDocument(); - expect(screen.getByText(/gopkg.in\/yaml.v3/i)).toBeInTheDocument(); - expect(screen.getByText(/v3.0.0-20210107192922-496545a6307b/i)).toBeInTheDocument(); - expect(screen.getByText(/3.0.0-20220521103104-8f96da9f5d5e/i)).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.tsx deleted file mode 100644 index 673dd2e8130e4..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.tsx +++ /dev/null @@ -1,497 +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 { - EuiButtonEmpty, - EuiButtonIcon, - EuiDataGrid, - EuiDataGridCellValueElementProps, - EuiProgress, - EuiSpacer, - useEuiTheme, -} from '@elastic/eui'; -import { cx } from '@emotion/css'; -import { DataView } from '@kbn/data-views-plugin/common'; -import React, { useCallback, useMemo, useState, useEffect } from 'react'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { Link, useParams, generatePath } from 'react-router-dom'; -import type { BoolQuery } from '@kbn/es-query'; -import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../../../common/constants'; -import { - CloudPostureTableResult, - useCloudPostureTable, -} from '../../../../common/hooks/use_cloud_posture_table'; -import { useLatestVulnerabilities } from '../../hooks/use_latest_vulnerabilities'; -import type { VulnerabilitiesQueryData } from '../../types'; -import { ErrorCallout } from '../../../configurations/layout/error_callout'; -import { FindingsSearchBar } from '../../../configurations/layout/findings_search_bar'; -import { CVSScoreBadge, SeverityStatusBadge } from '../../../../components/vulnerability_badges'; -import { EmptyState } from '../../../../components/empty_state'; -import { VulnerabilityFindingFlyout } from '../../vulnerabilities_finding_flyout/vulnerability_finding_flyout'; -import { useLimitProperties } from '../../../../common/utils/get_limit_properties'; -import { - LimitedResultsBar, - PageTitle, - PageTitleText, -} from '../../../configurations/layout/findings_layout'; -import { - getVulnerabilitiesColumnsGrid, - vulnerabilitiesColumns, -} from '../../vulnerabilities_table_columns'; -import { - defaultLoadingRenderer, - defaultNoDataRenderer, -} from '../../../../components/cloud_posture_page'; -import { SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from '../../translations'; -import { - severitySchemaConfig, - severitySortScript, - getCaseInsensitiveSortScript, -} from '../../utils/custom_sort_script'; -import { useStyles } from '../../hooks/use_styles'; -import { findingsNavigation } from '../../../../common/navigation/constants'; -import { CspInlineDescriptionList } from '../../../../components/csp_inline_description_list'; -import { getVulnerabilitiesGridCellActions } from '../../utils/get_vulnerabilities_grid_cell_actions'; - -const getDefaultQuery = ({ query, filters }: any) => ({ - query, - filters, - sort: [ - { id: vulnerabilitiesColumns.severity, direction: 'desc' }, - { id: vulnerabilitiesColumns.cvss, direction: 'desc' }, - ], - pageIndex: 0, -}); - -const ResourceVulnerabilitiesDataGrid = ({ - dataView, - data, - isFetching, - pageIndex, - sort, - pageSize, - onChangeItemsPerPage, - onChangePage, - onSort, - urlQuery, - setUrlQuery, - onResetFilters, -}: { - dataView: DataView; - data: VulnerabilitiesQueryData; - isFetching: boolean; -} & Pick< - CloudPostureTableResult, - | 'pageIndex' - | 'sort' - | 'pageSize' - | 'onChangeItemsPerPage' - | 'onChangePage' - | 'onSort' - | 'urlQuery' - | 'setUrlQuery' - | 'onResetFilters' ->) => { - const { euiTheme } = useEuiTheme(); - const styles = useStyles(); - - const [showHighlight, setHighlight] = useState(false); - - const onSortHandler = useCallback( - (newSort: any) => { - onSort(newSort); - if (newSort.length !== sort.length) { - setHighlight(true); - setTimeout(() => { - setHighlight(false); - }, 2000); - } - }, - [onSort, sort] - ); - - const invalidIndex = -1; - - const selectedVulnerability = useMemo(() => { - return data?.page[urlQuery.vulnerabilityIndex]; - }, [data?.page, urlQuery.vulnerabilityIndex]); - - const onCloseFlyout = () => { - setUrlQuery({ - vulnerabilityIndex: invalidIndex, - }); - }; - - const onOpenFlyout = useCallback( - (vulnerabilityRow: VulnerabilitiesQueryData['page'][number]) => { - const vulnerabilityIndex = data?.page.findIndex( - (vulnerabilityRecord: VulnerabilitiesQueryData['page'][number]) => - vulnerabilityRecord.vulnerability?.id === vulnerabilityRow.vulnerability?.id && - vulnerabilityRecord.resource?.id === vulnerabilityRow.resource?.id && - vulnerabilityRecord.package.name === vulnerabilityRow.package.name && - vulnerabilityRecord.package.version === vulnerabilityRow.package.version - ); - setUrlQuery({ - vulnerabilityIndex, - }); - }, - [setUrlQuery, data?.page] - ); - - const { isLastLimitedPage, limitedTotalItemCount } = useLimitProperties({ - total: data?.total, - pageIndex, - pageSize, - }); - - const columns = useMemo(() => { - if (!data?.page) { - return []; - } - - return getVulnerabilitiesGridCellActions({ - columnGridFn: getVulnerabilitiesColumnsGrid, - columns: vulnerabilitiesColumns, - dataView, - pageSize, - data: data.page, - setUrlQuery, - filters: urlQuery.filters, - }).filter( - (column) => - column.id !== vulnerabilitiesColumns.resourceName && - column.id !== vulnerabilitiesColumns.resourceId - ); - }, [data?.page, dataView, pageSize, setUrlQuery, urlQuery.filters]); - - const flyoutVulnerabilityIndex = urlQuery?.vulnerabilityIndex; - - const selectedVulnerabilityIndex = flyoutVulnerabilityIndex + pageIndex * pageSize; - - const renderCellValue = useMemo(() => { - const Cell: React.FC = ({ - columnId, - rowIndex, - setCellProps, - }): React.ReactElement | null => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const vulnerabilityRow = data?.page[rowIndexFromPage]; - - useEffect(() => { - if (selectedVulnerabilityIndex === rowIndex) { - setCellProps({ - style: { - backgroundColor: euiTheme.colors.highlight, - }, - }); - } else { - setCellProps({ - style: { - backgroundColor: 'inherit', - }, - }); - } - }, [rowIndex, setCellProps]); - - if (isFetching) return null; - if (!vulnerabilityRow) return null; - if (!vulnerabilityRow.vulnerability?.id) return null; - - if (columnId === vulnerabilitiesColumns.actions) { - return ( - { - onOpenFlyout(vulnerabilityRow); - }} - /> - ); - } - if (columnId === vulnerabilitiesColumns.vulnerability) { - return <>{vulnerabilityRow.vulnerability?.id}; - } - if (columnId === vulnerabilitiesColumns.cvss) { - if ( - !vulnerabilityRow.vulnerability.score?.base || - !vulnerabilityRow.vulnerability.score?.version - ) { - return null; - } - return ( - - ); - } - if (columnId === vulnerabilitiesColumns.severity) { - if (!vulnerabilityRow.vulnerability.severity) { - return null; - } - return ; - } - - if (columnId === vulnerabilitiesColumns.package) { - return <>{vulnerabilityRow?.package?.name}; - } - if (columnId === vulnerabilitiesColumns.version) { - return <>{vulnerabilityRow?.package?.version}; - } - if (columnId === vulnerabilitiesColumns.fixedVersion) { - return <>{vulnerabilityRow?.package?.fixed_version}; - } - - return null; - }; - - return Cell; - }, [ - data?.page, - euiTheme.colors.highlight, - onOpenFlyout, - pageSize, - selectedVulnerabilityIndex, - isFetching, - ]); - - const onPaginateFlyout = useCallback( - (nextVulnerabilityIndex: number) => { - // the index of the vulnerability in the current page - const newVulnerabilityIndex = nextVulnerabilityIndex % pageSize; - - // if the vulnerability is not in the current page, we need to change the page - const flyoutPageIndex = Math.floor(nextVulnerabilityIndex / pageSize); - - setUrlQuery({ - pageIndex: flyoutPageIndex, - vulnerabilityIndex: newVulnerabilityIndex, - }); - }, - [pageSize, setUrlQuery] - ); - - const showVulnerabilityFlyout = flyoutVulnerabilityIndex > invalidIndex; - - if (data.page.length === 0) { - return ; - } - - return ( - <> - - id), - setVisibleColumns: () => {}, - }} - height={undefined} - width={undefined} - schemaDetectors={[severitySchemaConfig]} - rowCount={limitedTotalItemCount} - rowHeightsOptions={{ - defaultHeight: 40, - }} - toolbarVisibility={{ - showColumnSelector: false, - showDisplaySelector: false, - showKeyboardShortcuts: false, - showFullScreenSelector: false, - additionalControls: { - left: { - prepend: ( - <> - - {i18n.translate('xpack.csp.vulnerabilities.totalVulnerabilities', { - defaultMessage: - '{total, plural, one {# Vulnerability} other {# Vulnerabilities}}', - values: { total: data?.total }, - })} - - - ), - }, - }, - }} - gridStyle={{ - border: 'horizontal', - cellPadding: 'l', - stripes: false, - rowHover: 'none', - header: 'underline', - }} - renderCellValue={renderCellValue} - inMemory={{ level: 'enhancements' }} - sorting={{ columns: sort, onSort: onSortHandler }} - pagination={{ - pageIndex, - pageSize, - pageSizeOptions: [10, 25, 100], - onChangeItemsPerPage, - onChangePage, - }} - /> - {isLastLimitedPage && } - {showVulnerabilityFlyout && selectedVulnerability && ( - - )} - - ); -}; -export const ResourceVulnerabilities = ({ dataView }: { dataView: DataView }) => { - const params = useParams<{ resourceId: string }>(); - const resourceId = decodeURIComponent(params.resourceId); - - const { - pageIndex, - pageSize, - onChangeItemsPerPage, - onChangePage, - query, - sort, - onSort, - queryError, - urlQuery, - setUrlQuery, - onResetFilters, - } = useCloudPostureTable({ - dataView, - defaultQuery: getDefaultQuery, - paginationLocalStorageKey: LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY, - }); - - const multiFieldsSort = useMemo(() => { - return sort.map(({ id, direction }: { id: string; direction: string }) => { - if (id === vulnerabilitiesColumns.severity) { - return severitySortScript(direction); - } - if (id === vulnerabilitiesColumns.package) { - return getCaseInsensitiveSortScript(id, direction); - } - - return { - [id]: direction, - }; - }); - }, [sort]); - - const { data, isLoading, isFetching } = useLatestVulnerabilities({ - query: { - ...query, - bool: { - ...(query?.bool as BoolQuery), - filter: [...(query?.bool?.filter || []), { term: { 'resource.id': resourceId } }], - }, - }, - sort: multiFieldsSort, - enabled: !queryError, - pageIndex, - pageSize, - }); - - const error = queryError || null; - - if (isLoading) { - return defaultLoadingRenderer(); - } - - if (!data?.page) { - return defaultNoDataRenderer(); - } - - return ( - <> - { - setUrlQuery({ ...newQuery, pageIndex: 0 }); - }} - loading={isFetching} - placeholder={SEARCH_BAR_PLACEHOLDER} - /> - - - - - - - - - - - - - - {error && } - {!error && ( - - )} - - ); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/test_subjects.ts deleted file mode 100644 index 027b0b1cdb2ed..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/test_subjects.ts +++ /dev/null @@ -1,8 +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 VULNERABILITY_RESOURCE_COUNT = 'vulnerability_resource_count'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.test.tsx deleted file mode 100644 index bd3fb0913bc3e..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.test.tsx +++ /dev/null @@ -1,83 +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 { render, screen } from '@testing-library/react'; -import { VulnerabilitiesByResource } from './vulnerabilities_by_resource'; -import { TestProvider } from '../../../test/test_provider'; -import { useLatestVulnerabilitiesByResource } from '../hooks/use_latest_vulnerabilities_by_resource'; -import { VULNERABILITY_RESOURCE_COUNT } from './test_subjects'; -import { getVulnerabilitiesByResourceData } from './__mocks__/vulnerabilities_by_resource.mock'; - -jest.mock('../hooks/use_latest_vulnerabilities_by_resource', () => ({ - useLatestVulnerabilitiesByResource: jest.fn(), -})); - -beforeEach(() => { - jest.clearAllMocks(); -}); - -describe('VulnerabilitiesByResource', () => { - const dataView: any = {}; - - const renderVulnerabilityByResource = () => { - return render( - - - - ); - }; - - it('renders the loading state', () => { - (useLatestVulnerabilitiesByResource as jest.Mock).mockReturnValue({ - data: undefined, - isLoading: true, - isFetching: true, - }); - renderVulnerabilityByResource(); - expect(screen.getByText(/loading/i)).toBeInTheDocument(); - }); - it('renders the no data state', () => { - (useLatestVulnerabilitiesByResource as jest.Mock).mockReturnValue({ - data: undefined, - isLoading: false, - isFetching: false, - }); - - renderVulnerabilityByResource(); - expect(screen.getByText(/no data/i)).toBeInTheDocument(); - }); - - it('renders the empty state component', () => { - (useLatestVulnerabilitiesByResource as jest.Mock).mockReturnValue({ - data: { total: 0, total_vulnerabilities: 0, page: [] }, - isLoading: false, - isFetching: false, - }); - - renderVulnerabilityByResource(); - expect(screen.getByText(/no results/i)).toBeInTheDocument(); - }); - - it('renders the Table', () => { - (useLatestVulnerabilitiesByResource as jest.Mock).mockReturnValue({ - data: getVulnerabilitiesByResourceData(), - isLoading: false, - isFetching: false, - }); - - renderVulnerabilityByResource(); - expect(screen.getByText(/2 resources/i)).toBeInTheDocument(); - expect(screen.getByText(/8 vulnerabilities/i)).toBeInTheDocument(); - expect(screen.getByText(/resource-id-1/i)).toBeInTheDocument(); - expect(screen.getByText(/resource-id-2/i)).toBeInTheDocument(); - expect(screen.getByText(/resource-test-1/i)).toBeInTheDocument(); - expect(screen.getAllByText(/us-test-1/i)).toHaveLength(2); - expect(screen.getAllByTestId(VULNERABILITY_RESOURCE_COUNT)).toHaveLength(2); - expect(screen.getAllByTestId(VULNERABILITY_RESOURCE_COUNT)[0]).toHaveTextContent('4'); - expect(screen.getAllByTestId(VULNERABILITY_RESOURCE_COUNT)[1]).toHaveTextContent('4'); - }); -}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.tsx deleted file mode 100644 index 89488bf52046b..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.tsx +++ /dev/null @@ -1,309 +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 { - EuiBadge, - EuiButtonEmpty, - EuiDataGrid, - EuiDataGridCellValueElementProps, - EuiFlexItem, - EuiProgress, - EuiSpacer, -} from '@elastic/eui'; -import { DataView } from '@kbn/data-views-plugin/common'; -import React, { useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; -import { Link, generatePath } from 'react-router-dom'; -import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../../common/constants'; -import { findingsNavigation } from '../../../common/navigation/constants'; -import { - CloudPostureTableResult, - useCloudPostureTable, -} from '../../../common/hooks/use_cloud_posture_table'; -import { ErrorCallout } from '../../configurations/layout/error_callout'; -import { FindingsSearchBar } from '../../configurations/layout/findings_search_bar'; -import { useLimitProperties } from '../../../common/utils/get_limit_properties'; -import { LimitedResultsBar } from '../../configurations/layout/findings_layout'; -import { - getVulnerabilitiesByResourceColumnsGrid, - vulnerabilitiesByResourceColumns, -} from './vulnerabilities_by_resource_table_columns'; -import { - defaultLoadingRenderer, - defaultNoDataRenderer, -} from '../../../components/cloud_posture_page'; -import { SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from '../translations'; -import { useStyles } from '../hooks/use_styles'; -import { FindingsGroupBySelector } from '../../configurations/layout/findings_group_by_selector'; -import { vulnerabilitiesPathnameHandler } from '../utils/vulnerabilities_pathname_handler'; -import { useLatestVulnerabilitiesByResource } from '../hooks/use_latest_vulnerabilities_by_resource'; -import { EmptyState } from '../../../components/empty_state'; -import { SeverityMap } from './severity_map'; -import { VULNERABILITY_RESOURCE_COUNT } from './test_subjects'; -import { getVulnerabilitiesGridCellActions } from '../utils/get_vulnerabilities_grid_cell_actions'; -import type { VulnerabilitiesByResourceQueryData } from '../types'; - -const getDefaultQuery = ({ query, filters }: any): any => ({ - query, - filters, - sort: [{ id: vulnerabilitiesByResourceColumns.vulnerabilities_count, direction: 'desc' }], - pageIndex: 0, -}); - -const VulnerabilitiesByResourceDataGrid = ({ - dataView, - data, - isFetching, - pageIndex, - sort, - pageSize, - onChangeItemsPerPage, - onChangePage, - onSort, - urlQuery, - setUrlQuery, - onResetFilters, -}: { - dataView: DataView; - data: VulnerabilitiesByResourceQueryData | undefined; - isFetching: boolean; -} & Pick< - CloudPostureTableResult, - | 'pageIndex' - | 'sort' - | 'pageSize' - | 'onChangeItemsPerPage' - | 'onChangePage' - | 'onSort' - | 'urlQuery' - | 'setUrlQuery' - | 'onResetFilters' ->) => { - const styles = useStyles(); - - const { isLastLimitedPage, limitedTotalItemCount } = useLimitProperties({ - total: data?.total, - pageIndex, - pageSize, - }); - - const columns = useMemo(() => { - if (!data?.page) { - return []; - } - return getVulnerabilitiesGridCellActions({ - columnGridFn: getVulnerabilitiesByResourceColumnsGrid, - columns: vulnerabilitiesByResourceColumns, - dataView, - pageSize, - data: data.page, - setUrlQuery, - filters: urlQuery.filters, - }); - }, [data, dataView, pageSize, setUrlQuery, urlQuery.filters]); - - const renderCellValue = useMemo(() => { - const Cell: React.FC = ({ - columnId, - rowIndex, - }): React.ReactElement | null => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const resourceVulnerabilityRow = data?.page[rowIndexFromPage]; - - if (isFetching) return null; - if (!resourceVulnerabilityRow?.resource?.id) return null; - - if (columnId === vulnerabilitiesByResourceColumns.resourceId) { - return ( - - {resourceVulnerabilityRow?.resource?.id} - - ); - } - if (columnId === vulnerabilitiesByResourceColumns.resourceName) { - return <>{resourceVulnerabilityRow?.resource?.name}; - } - if (columnId === vulnerabilitiesByResourceColumns.region) { - return <>{resourceVulnerabilityRow?.cloud?.region}; - } - if (columnId === vulnerabilitiesByResourceColumns.vulnerabilities_count) { - return ( - - {resourceVulnerabilityRow.vulnerabilities_count} - - ); - } - - if (columnId === vulnerabilitiesByResourceColumns.severity_map) { - return ( - - ); - } - return null; - }; - - return Cell; - }, [data?.page, pageSize, isFetching]); - - if (data?.page.length === 0) { - return ; - } - - return ( - <> - - id), - setVisibleColumns: () => {}, - }} - rowCount={limitedTotalItemCount} - toolbarVisibility={{ - showColumnSelector: false, - showDisplaySelector: false, - showKeyboardShortcuts: false, - showSortSelector: false, - showFullScreenSelector: false, - additionalControls: { - left: { - prepend: ( - <> - - {i18n.translate('xpack.csp.vulnerabilitiesByResource.totalResources', { - defaultMessage: '{total, plural, one {# Resource} other {# Resources}}', - values: { total: data?.total }, - })} - - - {i18n.translate('xpack.csp.vulnerabilitiesByResource.totalVulnerabilities', { - defaultMessage: - '{total, plural, one {# Vulnerability} other {# Vulnerabilities}}', - values: { total: data?.total_vulnerabilities }, - })} - - - ), - }, - right: ( - - - - ), - }, - }} - gridStyle={{ - border: 'horizontal', - cellPadding: 'l', - stripes: false, - rowHover: 'none', - header: 'underline', - }} - renderCellValue={renderCellValue} - inMemory={{ level: 'enhancements' }} - sorting={{ columns: sort, onSort }} - pagination={{ - pageIndex, - pageSize, - pageSizeOptions: [10, 25, 100], - onChangeItemsPerPage, - onChangePage, - }} - /> - {isLastLimitedPage && } - - ); -}; - -export const VulnerabilitiesByResource = ({ dataView }: { dataView: DataView }) => { - const { - pageIndex, - onChangeItemsPerPage, - onChangePage, - pageSize, - query, - sort, - onSort, - queryError, - urlQuery, - setUrlQuery, - onResetFilters, - } = useCloudPostureTable({ - dataView, - defaultQuery: getDefaultQuery, - paginationLocalStorageKey: LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY, - }); - - const { data, isLoading, isFetching } = useLatestVulnerabilitiesByResource({ - query, - sortOrder: sort[0]?.direction, - enabled: !queryError, - pageIndex, - pageSize, - }); - - const error = queryError || null; - - if (isLoading && !error) { - return defaultLoadingRenderer(); - } - - if (!data?.page && !error) { - return defaultNoDataRenderer(); - } - - return ( - <> - { - setUrlQuery({ ...newQuery, pageIndex: 0 }); - }} - loading={isFetching} - placeholder={SEARCH_BAR_PLACEHOLDER} - /> - - {error && } - {!error && ( - - )} - - ); -}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource_table_columns.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource_table_columns.ts deleted file mode 100644 index 42196f151bd07..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource_table_columns.ts +++ /dev/null @@ -1,86 +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 { EuiDataGridColumn, EuiDataGridColumnCellAction } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -export const vulnerabilitiesByResourceColumns = { - resourceId: 'resource.id', - resourceName: 'resource.name', - region: 'cloud.region', - vulnerabilities_count: 'vulnerabilities_count', - severity_map: 'severity_map', -}; - -const defaultColumnProps = (): Partial => ({ - isExpandable: false, - actions: { - showHide: false, - showMoveLeft: false, - showMoveRight: false, - showSortAsc: false, - showSortDesc: false, - }, - isSortable: false, -}); - -export const getVulnerabilitiesByResourceColumnsGrid = ( - cellActions: EuiDataGridColumnCellAction[] -): EuiDataGridColumn[] => [ - { - ...defaultColumnProps(), - id: vulnerabilitiesByResourceColumns.resourceId, - displayAsText: i18n.translate('xpack.csp.vulnerabilityByResourceTable.column.resourceId', { - defaultMessage: 'Resource ID', - }), - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesByResourceColumns.resourceName, - displayAsText: i18n.translate('xpack.csp.vulnerabilityByResourceTable.column.resourceName', { - defaultMessage: 'Resource Name', - }), - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesByResourceColumns.region, - displayAsText: i18n.translate('xpack.csp.vulnerabilityByResourceTable.column.region', { - defaultMessage: 'Region', - }), - cellActions, - initialWidth: 150, - }, - { - ...defaultColumnProps(), - actions: { - showHide: false, - showMoveLeft: false, - showMoveRight: false, - showSortAsc: true, - showSortDesc: true, - }, - id: vulnerabilitiesByResourceColumns.vulnerabilities_count, - displayAsText: i18n.translate('xpack.csp.vulnerabilityByResourceTable.column.vulnerabilities', { - defaultMessage: 'Vulnerabilities', - }), - initialWidth: 140, - isResizable: false, - isSortable: true, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesByResourceColumns.severity_map, - displayAsText: i18n.translate('xpack.csp.vulnerabilityByResourceTable.column.severityMap', { - defaultMessage: 'Severity Map', - }), - cellActions, - initialWidth: 110, - isResizable: false, - }, -]; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx index c1ffdfeb41914..da7587cfc8ad0 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx @@ -42,7 +42,7 @@ describe('', () => { expect(descriptionList.textContent).toEqual( `Resource ID:${mockVulnerabilityHit.resource?.id}Resource Name:${mockVulnerabilityHit.resource?.name}Package:${mockVulnerabilityHit.package.name}Version:${mockVulnerabilityHit.package.version}` ); - getByText(mockVulnerabilityHit.vulnerability.severity); + getByText(mockVulnerabilityHit.vulnerability.severity!); }); }); @@ -93,19 +93,24 @@ describe('', () => { }); }); - it('should allow pagination with next', async () => { - const { getByTestId } = render(); + /** + * TODO: Enable this test once https://github.com/elastic/kibana/issues/168619 is resolved + */ + describe.skip('Flyout Pagination', () => { + it('should allow pagination with next', async () => { + const { getByTestId } = render(); - userEvent.click(getByTestId('pagination-button-next')); + userEvent.click(getByTestId('pagination-button-next')); - expect(onPaginate).toHaveBeenCalledWith(1); - }); + expect(onPaginate).toHaveBeenCalledWith(1); + }); - it('should allow pagination with previous', async () => { - const { getByTestId } = render(); + it('should allow pagination with previous', async () => { + const { getByTestId } = render(); - userEvent.click(getByTestId('pagination-button-previous')); + userEvent.click(getByTestId('pagination-button-previous')); - expect(onPaginate).toHaveBeenCalledWith(0); + expect(onPaginate).toHaveBeenCalledWith(0); + }); }); }); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx index ac8c98e87f411..06b8fdc2ad941 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx @@ -81,18 +81,18 @@ const getFlyoutDescriptionList = ( export const VulnerabilityFindingFlyout = ({ closeFlyout, + vulnerabilityRecord, onPaginate, totalVulnerabilitiesCount, flyoutIndex, - vulnerabilityRecord, - isLoading, + isLoading = false, }: { closeFlyout: () => void; + vulnerabilityRecord: CspVulnerabilityFinding; onPaginate?: (pageIndex: number) => void; - totalVulnerabilitiesCount: number; + totalVulnerabilitiesCount?: number; flyoutIndex?: number; - vulnerabilityRecord: CspVulnerabilityFinding; - isLoading: boolean; + isLoading?: boolean; }) => { const [selectedTabId, setSelectedTabId] = useState(overviewTabId); const vulnerability = vulnerabilityRecord?.vulnerability; @@ -241,7 +241,7 @@ export const VulnerabilityFindingFlyout = ({ alignItems="center" justifyContent={onPaginate ? 'spaceBetween' : 'flexEnd'} > - {onPaginate && ( + {onPaginate && totalVulnerabilitiesCount && flyoutIndex && ( ({ - isExpandable: false, - actions: { - showHide: false, - showMoveLeft: false, - showMoveRight: false, - }, -}); - -export const getVulnerabilitiesColumnsGrid = ( - cellActions: EuiDataGridColumnCellAction[] -): EuiDataGridColumn[] => [ - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.actions, - initialWidth: 40, - display: [], - actions: false, - isSortable: false, - isResizable: false, - cellActions: [], - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.vulnerability, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.vulnerability', { - defaultMessage: 'Vulnerability', - }), - initialWidth: 130, - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.cvss, - displayAsText: 'CVSS', - initialWidth: 80, - isResizable: false, - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.resourceId, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.resourceId', { - defaultMessage: 'Resource ID', - }), - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.resourceName, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.resourceName', { - defaultMessage: 'Resource Name', - }), - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.severity, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.severity', { - defaultMessage: 'Severity', - }), - initialWidth: 100, - cellActions, - schema: severitySchemaConfig.type, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.package, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.package', { - defaultMessage: 'Package', - }), - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.version, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.version', { - defaultMessage: 'Version', - }), - cellActions, - }, - { - ...defaultColumnProps(), - id: vulnerabilitiesColumns.fixedVersion, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.fixVersion', { - defaultMessage: 'Fix Version', - }), - cellActions, - }, -]; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/accounts_stats_collector.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/accounts_stats_collector.ts index d144343807a06..51b64b8664867 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/accounts_stats_collector.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/accounts_stats_collector.ts @@ -224,7 +224,6 @@ const getCspmAccountsStats = ( nodes_count: account.nodes_count.value, pods_count: account.resources.pods_count.value, })); - logger.info('CSPM telemetry: accounts stats was sent'); return cspmAccountsStats; }; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts index 82de2d010a35e..fac84a5d8a7a2 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts @@ -345,8 +345,6 @@ export const getCloudAccountsStats = ( }; }); - logger.info('Cloud Account Stats telemetry: accounts stats was sent'); - return cloudAccountsStats; }; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/muted_rules_stats_collector.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/muted_rules_stats_collector.ts new file mode 100644 index 0000000000000..63fc68caff47b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/muted_rules_stats_collector.ts @@ -0,0 +1,60 @@ +/* + * 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 { + ISavedObjectsRepository, + SavedObjectsClientContract, +} from '@kbn/core-saved-objects-api-server'; +import type { Logger } from '@kbn/core/server'; +import { CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE } from '../../../../common/constants'; +import { CspBenchmarkRule } from '../../../../common/types/latest'; +import { getCspBenchmarkRulesStatesHandler } from '../../../routes/benchmark_rules/get_states/v1'; +import { MutedRulesStats } from './types'; + +export const getMutedRulesStats = async ( + soClient: SavedObjectsClientContract, + encryptedSoClient: ISavedObjectsRepository, + logger: Logger +): Promise => { + try { + const benchmarkRulesStates = await getCspBenchmarkRulesStatesHandler(encryptedSoClient); + const mutedBenchmarkRules = Object.fromEntries( + Object.entries(benchmarkRulesStates).filter(([_, value]) => value.muted === true) + ); + + const mutedRulesStats = await Promise.all( + Object.values(mutedBenchmarkRules).map(async (mutedBenchmarkRule) => { + const cspBenchmarkRulesSo = await soClient.get( + CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE, + mutedBenchmarkRule.rule_id + ); + const ruleMetadata = cspBenchmarkRulesSo.attributes.metadata; + if (ruleMetadata) { + return { + id: ruleMetadata.id, + name: ruleMetadata.name, + benchmark_id: ruleMetadata.benchmark.id, + benchmark_name: ruleMetadata.benchmark.name, + benchmark_version: mutedBenchmarkRule.benchmark_version, // The state object may include different benchmark version then the latest one. + rule_number: ruleMetadata.benchmark.rule_number, + posture_type: ruleMetadata.benchmark.posture_type, + section: ruleMetadata.section, + version: ruleMetadata.version, + }; + } + return null; + }) + ); + + return mutedRulesStats.filter( + (filteredMetadata) => filteredMetadata !== null + ) as MutedRulesStats[]; + } catch (e) { + logger.error(`Failed to get rules states stats ${e}`); + return []; + } +}; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts index 919adae18446c..3d283eed41834 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts @@ -17,6 +17,8 @@ import { getRulesStats } from './rules_stats_collector'; import { getInstallationStats } from './installation_stats_collector'; import { getAlertsStats } from './alert_stats_collector'; import { getAllCloudAccountsStats } from './cloud_accounts_stats_collector'; +import { getMutedRulesStats } from './muted_rules_stats_collector'; +import { INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE } from '../../../../common/constants'; export function registerCspmUsageCollector( logger: Logger, @@ -42,6 +44,7 @@ export function registerCspmUsageCollector( ) => { try { const val = await promise; + logger.info(`Cloud Security telemetry: ${taskName} payload was sent successfully`); return val; } catch (error) { logger.error(`${taskName} task failed: ${error.message}`); @@ -52,6 +55,10 @@ export function registerCspmUsageCollector( const esClient = collectorFetchContext.esClient; const soClient = collectorFetchContext.soClient; + const encryptedSoClient = (await coreServices)[0].savedObjects.createInternalRepository([ + INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE, + ]); + const [ indicesStats, accountsStats, @@ -60,6 +67,7 @@ export function registerCspmUsageCollector( installationStats, alertsStats, cloudAccountStats, + mutedRulesStats, ] = await Promise.all([ awaitPromiseSafe('Indices', getIndicesStats(esClient, soClient, coreServices, logger)), awaitPromiseSafe('Accounts', getAccountsStats(esClient, logger)), @@ -71,6 +79,7 @@ export function registerCspmUsageCollector( ), awaitPromiseSafe('Alerts', getAlertsStats(esClient, logger)), awaitPromiseSafe('Cloud Accounts', getAllCloudAccountsStats(esClient, logger)), + awaitPromiseSafe('Muted Rules', getMutedRulesStats(soClient, encryptedSoClient, logger)), ]); return { indices: indicesStats, @@ -80,6 +89,7 @@ export function registerCspmUsageCollector( installation_stats: installationStats, alerts_stats: alertsStats, cloud_account_stats: cloudAccountStats, + muted_rules_stats: mutedRulesStats, }; }, schema: cspmUsageSchema, diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/resources_stats_collector.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/resources_stats_collector.ts index bccb92035a3bb..9dce3468c8114 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/resources_stats_collector.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/resources_stats_collector.ts @@ -134,7 +134,6 @@ const getCspmResourcesStats = ( }); }); }); - logger.info('CSPM telemetry: resources stats was sent'); return resourcesStats.flat(2); }; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts index 498566b7cb082..0b0be13ba3a1f 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts @@ -193,4 +193,18 @@ export const cspmUsageSchema: MakeSchemaFrom = { }, }, }, + muted_rules_stats: { + type: 'array', + items: { + id: { type: 'keyword' }, + name: { type: 'keyword' }, + section: { type: 'keyword' }, + benchmark_id: { type: 'keyword' }, + benchmark_name: { type: 'keyword' }, + benchmark_version: { type: 'keyword' }, + rule_number: { type: 'keyword' }, + posture_type: { type: 'keyword' }, + version: { type: 'keyword' }, + }, + }, }; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts index f9eb6094277a4..f078b35e25ee6 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts @@ -15,7 +15,8 @@ export type CloudSecurityUsageCollectorType = | 'Rules' | 'Installation' | 'Alerts' - | 'Cloud Accounts'; + | 'Cloud Accounts' + | 'Muted Rules'; export type CloudProviderKey = 'cis_eks' | 'cis_gke' | 'cis_k8s' | 'cis_ake'; export type CloudbeatConfigKeyType = @@ -32,6 +33,7 @@ export interface CspmUsage { installation_stats: CloudSecurityInstallationStats[]; alerts_stats: CloudSecurityAlertsStats[]; cloud_account_stats: CloudSecurityAccountsStats[]; + muted_rules_stats: MutedRulesStats[]; } export interface PackageSetupStatus { @@ -214,3 +216,15 @@ export interface AccountEntity { pods_count: Value; }; } + +export interface MutedRulesStats { + id: string; + name: string; + section: string; + version: string; + benchmark_id: string; + benchmark_name: string; + benchmark_version: string; + posture_type: string; + rule_number: string; +} diff --git a/x-pack/plugins/fleet/common/types/index.ts b/x-pack/plugins/fleet/common/types/index.ts index e822b1e8e579d..b2c66a01dfcaa 100644 --- a/x-pack/plugins/fleet/common/types/index.ts +++ b/x-pack/plugins/fleet/common/types/index.ts @@ -40,6 +40,7 @@ export interface FleetConfigType { }; setup?: { agentPolicySchemaUpgradeBatchSize?: number; + uninstallTokenVerificationBatchSize?: number; }; developer?: { maxAgentPoliciesWithInactivityTimeout?: number; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx index 94414965183f0..0a723bab1b969 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_list_table.tsx @@ -215,7 +215,7 @@ export const AgentListTable: React.FC = (props: Props) => { content={ } > diff --git a/x-pack/plugins/fleet/server/config.ts b/x-pack/plugins/fleet/server/config.ts index 0ab1320650920..a47058a80c828 100644 --- a/x-pack/plugins/fleet/server/config.ts +++ b/x-pack/plugins/fleet/server/config.ts @@ -151,6 +151,7 @@ export const config: PluginConfigDescriptor = { setup: schema.maybe( schema.object({ agentPolicySchemaUpgradeBatchSize: schema.maybe(schema.number()), + uninstallTokenVerificationBatchSize: schema.maybe(schema.number()), }) ), developer: schema.object({ diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts index 670ba36ed6a8d..375770028488d 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts @@ -1611,7 +1611,14 @@ describe('EPM template', () => { }, ]); - expect(esClient.indices.rollover).toHaveBeenCalled(); + expect(esClient.transport.request).toHaveBeenCalledWith( + expect.objectContaining({ + path: '/test.prefix1-default/_rollover', + querystring: { + lazy: true, + }, + }) + ); }); it('should skip rollover on expected error when flag is on', async () => { const esClient = elasticsearchServiceMock.createElasticsearchClient(); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index a60e9dc0c7ced..750a8ef860491 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -933,8 +933,12 @@ const getDataStreams = async ( const rolloverDataStream = (dataStreamName: string, esClient: ElasticsearchClient) => { try { // Do no wrap rollovers in retryTransientEsErrors since it is not idempotent - return esClient.indices.rollover({ - alias: dataStreamName, + return esClient.transport.request({ + method: 'POST', + path: `/${dataStreamName}/_rollover`, + querystring: { + lazy: true, + }, }); } catch (error) { throw new PackageESError( diff --git a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts index a782fc605ccf5..5dfd1e5c951f0 100644 --- a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts +++ b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.test.ts @@ -13,6 +13,8 @@ import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; +import { errors } from '@elastic/elasticsearch'; + import { UninstallTokenError } from '../../../../common/errors'; import { SO_SEARCH_LIMIT } from '../../../../common'; @@ -527,6 +529,48 @@ describe('UninstallTokenService', () => { ).resolves.toBeNull(); }); + describe('avoiding `too_many_nested_clauses` error', () => { + it('performs one query if number of policies is smaller than batch size', async () => { + mockCreatePointInTimeFinderAsInternalUser(); + await uninstallTokenService.checkTokenValidityForAllPolicies(); + + expect(esoClientMock.createPointInTimeFinderDecryptedAsInternalUser).toBeCalledTimes(1); + expect(esoClientMock.createPointInTimeFinderDecryptedAsInternalUser).toBeCalledWith({ + filter: + 'fleet-uninstall-tokens.id: "test-so-id" or fleet-uninstall-tokens.id: "test-so-id-two"', + perPage: 10000, + type: 'fleet-uninstall-tokens', + }); + }); + + it('performs multiple queries if number of policies is larger than batch size', async () => { + // @ts-ignore + appContextService.getConfig().setup = { uninstallTokenVerificationBatchSize: 1 }; + + mockCreatePointInTimeFinderAsInternalUser(); + + await uninstallTokenService.checkTokenValidityForAllPolicies(); + + expect(esoClientMock.createPointInTimeFinderDecryptedAsInternalUser).toBeCalledTimes(2); + + expect( + esoClientMock.createPointInTimeFinderDecryptedAsInternalUser + ).toHaveBeenNthCalledWith(1, { + filter: 'fleet-uninstall-tokens.id: "test-so-id"', + perPage: 10000, + type: 'fleet-uninstall-tokens', + }); + + expect( + esoClientMock.createPointInTimeFinderDecryptedAsInternalUser + ).toHaveBeenNthCalledWith(2, { + filter: 'fleet-uninstall-tokens.id: "test-so-id-two"', + perPage: 10000, + type: 'fleet-uninstall-tokens', + }); + }); + }); + it('returns error if any of the tokens is missing', async () => { mockCreatePointInTimeFinderAsInternalUser([okaySO, missingTokenSO2]); @@ -597,6 +641,26 @@ describe('UninstallTokenService', () => { }); }); + it('returns error on `too_many_nested_clauses` error', async () => { + // @ts-ignore + const responseError = new errors.ResponseError({}); + responseError.message = 'this is a too_many_nested_clauses error'; + + esoClientMock.createPointInTimeFinderDecryptedAsInternalUser = jest + .fn() + .mockRejectedValueOnce(responseError); + + await expect( + uninstallTokenService.checkTokenValidityForAllPolicies() + ).resolves.toStrictEqual({ + error: new UninstallTokenError( + 'Failed to validate uninstall tokens: `too_many_nested_clauses` error received. ' + + 'Setting/decreasing the value of `xpack.fleet.setup.uninstallTokenVerificationBatchSize` in your kibana.yml should help. ' + + `Current value is 500.` + ), + }); + }); + it('throws error in case of unknown error', async () => { esoClientMock.createPointInTimeFinderDecryptedAsInternalUser = jest .fn() diff --git a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts index 511c3928f81fe..2215035684c67 100644 --- a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts +++ b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts @@ -23,13 +23,15 @@ import type { import type { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; import type { KibanaRequest } from '@kbn/core-http-server'; import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server'; -import { asyncForEach } from '@kbn/std'; +import { asyncForEach, asyncMap } from '@kbn/std'; import type { AggregationsTermsInclude, AggregationsTermsExclude, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { isResponseError } from '@kbn/es-errors'; + import { UninstallTokenError } from '../../../../common/errors'; import type { GetUninstallTokensMetadataResponse } from '../../../../common/types/rest_spec/uninstall_token'; @@ -205,15 +207,31 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { return []; } - const filter: string = tokenObjectHits - .map(({ _id }) => { - return `${UNINSTALL_TOKENS_SAVED_OBJECT_TYPE}.id: "${_id}"`; - }) - .join(' or '); + const filterEntries: string[] = tokenObjectHits.map( + ({ _id }) => `${UNINSTALL_TOKENS_SAVED_OBJECT_TYPE}.id: "${_id}"` + ); + + const uninstallTokenChunks: UninstallToken[][] = await asyncMap( + chunk(filterEntries, this.getUninstallTokenVerificationBatchSize()), + (entries) => { + const filter = entries.join(' or '); + return this.getDecryptedTokens({ filter }); + } + ); - return this.getDecryptedTokens({ filter }); + return uninstallTokenChunks.flat(); } + private getUninstallTokenVerificationBatchSize = () => { + /** If `uninstallTokenVerificationBatchSize` is too large, we get an error of `too_many_nested_clauses`. + * Assuming that `max_clause_count` >= 1024, and experiencing that batch size should be less than half + * than `max_clause_count` with our current query, batch size below 512 should be okay on every env. + */ + const config = appContextService.getConfig(); + + return config?.setup?.uninstallTokenVerificationBatchSize ?? 500; + }; + private getDecryptedTokens = async ( options: Partial ): Promise => { @@ -520,6 +538,16 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { if (error instanceof UninstallTokenError) { // known errors are considered non-fatal return { error }; + } else if (isResponseError(error) && error.message.includes('too_many_nested_clauses')) { + // `too_many_nested_clauses` is considered non-fatal + const errorMessage = + 'Failed to validate uninstall tokens: `too_many_nested_clauses` error received. ' + + 'Setting/decreasing the value of `xpack.fleet.setup.uninstallTokenVerificationBatchSize` in your kibana.yml should help. ' + + `Current value is ${this.getUninstallTokenVerificationBatchSize()}.`; + + appContextService.getLogger().warn(`${errorMessage}: '${error}'`); + + return { error: new UninstallTokenError(errorMessage) }; } else { const errorMessage = 'Unknown error happened while checking Uninstall Tokens validity'; appContextService.getLogger().error(`${errorMessage}: '${error}'`); diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index cc4be9bab0bcc..a9af93e70f7ab 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -369,6 +369,7 @@ export async function ensureFleetDirectories() { try { await fs.stat(bundledPackageLocation); + logger.debug(`Bundled package directory ${bundledPackageLocation} exists`); } catch (error) { logger.warn( `Bundled package directory ${bundledPackageLocation} does not exist. All packages will be sourced from ${registryUrl}.` diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx index 1123e47a60ede..d4e5876761c36 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx @@ -528,7 +528,6 @@ describe('', () => { await actions.completeStepOne({ name: TEMPLATE_NAME, indexPatterns: DEFAULT_INDEX_PATTERNS, - dataStream: {}, allowAutoCreate: true, }); // Component templates @@ -618,7 +617,6 @@ describe('', () => { await testBed.actions.completeStepOne({ name: TEMPLATE_NAME, indexPatterns: DEFAULT_INDEX_PATTERNS, - dataStream: {}, lifecycle: { enabled: true, value: 1, diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts index 88cee63b0e693..745b2a69b9498 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts @@ -145,10 +145,10 @@ export const formSetup = async (initTestBed: SetupFunc) => { order, priority, version, - dataStream, + enableDataStream, lifecycle, allowAutoCreate, - }: Partial = {}) => { + }: Partial & { enableDataStream?: boolean } = {}) => { const { component, form, find } = testBed; if (name) { @@ -174,7 +174,12 @@ export const formSetup = async (initTestBed: SetupFunc) => { form.setInputValue('orderField.input', JSON.stringify(order)); } - if (dataStream) { + // Deal with toggling the data stream switch + const isDataStreamEnabled = find('dataStreamField.input').props().checked; + + if (enableDataStream && !isDataStreamEnabled) { + form.toggleEuiSwitch('dataStreamField.input'); + } else if (!enableDataStream && isDataStreamEnabled) { form.toggleEuiSwitch('dataStreamField.input'); } diff --git a/x-pack/plugins/index_management/public/application/components/template_form/template_form.tsx b/x-pack/plugins/index_management/public/application/components/template_form/template_form.tsx index 9d494e0a558d9..4eab54356eabf 100644 --- a/x-pack/plugins/index_management/public/application/components/template_form/template_form.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/template_form.tsx @@ -116,6 +116,7 @@ export const TemplateForm = ({ const indexTemplate = defaultValue ?? { name: '', indexPatterns: [], + dataStream: {}, template: {}, _kbnMeta: { type: 'default', diff --git a/x-pack/plugins/index_management/public/application/constants/index.ts b/x-pack/plugins/index_management/public/application/constants/index.ts index 8ced3a40a80e9..f72e56310a9c7 100644 --- a/x-pack/plugins/index_management/public/application/constants/index.ts +++ b/x-pack/plugins/index_management/public/application/constants/index.ts @@ -5,8 +5,6 @@ * 2.0. */ -export { REFRESH_RATE_INDEX_LIST } from './refresh_intervals'; - export const REACT_ROOT_ID = 'indexManagementReactRoot'; export const ENRICH_POLICIES_REQUIRED_PRIVILEGES = ['manage_enrich']; diff --git a/x-pack/plugins/index_management/public/application/constants/refresh_intervals.ts b/x-pack/plugins/index_management/public/application/constants/refresh_intervals.ts deleted file mode 100644 index 1e7ce89ea2d87..0000000000000 --- a/x-pack/plugins/index_management/public/application/constants/refresh_intervals.ts +++ /dev/null @@ -1,8 +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 REFRESH_RATE_INDEX_LIST = 30000; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx index f028dee3d8eee..7872f2eacda78 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page.tsx @@ -11,7 +11,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiPageTemplate, EuiText, EuiCode } from '@elastic/eui'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; -import { IndexDetailsSection, IndexDetailsTabId } from '../../../../../../common/constants'; +import { + IndexDetailsSection, + IndexDetailsTabId, + Section, +} from '../../../../../../common/constants'; import { Index } from '../../../../../../common'; import { Error } from '../../../../../shared_imports'; import { loadIndex } from '../../../../services'; @@ -29,6 +33,10 @@ export const DetailsPage: FunctionComponent< const [error, setError] = useState(null); const [index, setIndex] = useState(); + const navigateToIndicesList = useCallback(() => { + history.push(`/${Section.Indices}`); + }, [history]); + const fetchIndexDetails = useCallback(async () => { if (indexName) { setIsLoading(true); @@ -87,7 +95,13 @@ export const DetailsPage: FunctionComponent< ); } if (error || !index) { - return ; + return ( + + ); } return ( ); }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx index adeadee6132c0..9b2beafd31cf5 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_content.tsx @@ -24,7 +24,6 @@ import { IndexDetailsSection, IndexDetailsTab, IndexDetailsTabId, - Section, } from '../../../../../../common/constants'; import { getIndexDetailsLink } from '../../../../services/routing'; import { useAppContext } from '../../../../app_context'; @@ -79,12 +78,14 @@ interface Props { tab: IndexDetailsTabId; history: RouteComponentProps['history']; fetchIndexDetails: () => Promise; + navigateToIndicesList: () => void; } export const DetailsPageContent: FunctionComponent = ({ index, tab, history, fetchIndexDetails, + navigateToIndicesList, }) => { const { config: { enableIndexStats }, @@ -115,10 +116,6 @@ export const DetailsPageContent: FunctionComponent = ({ [history, index] ); - const navigateToAllIndices = useCallback(() => { - history.push(`/${Section.Indices}`); - }, [history]); - const headerTabs = useMemo(() => { return tabs.map((tabConfig) => ({ onClick: () => onSectionChange(tabConfig.id), @@ -143,11 +140,11 @@ export const DetailsPageContent: FunctionComponent = ({ data-test-subj="indexDetailsBackToIndicesButton" color="text" iconType="arrowLeft" - onClick={navigateToAllIndices} + onClick={navigateToIndicesList} > @@ -161,7 +158,7 @@ export const DetailsPageContent: FunctionComponent = ({ , ]} rightSideGroupProps={{ diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_error.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_error.tsx index 9eaca894b963e..9656dcb77268b 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_error.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_error.tsx @@ -7,14 +7,23 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiButton, EuiPageTemplate, EuiSpacer, EuiText } from '@elastic/eui'; +import { + EuiButton, + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiPageTemplate, + EuiText, +} from '@elastic/eui'; export const DetailsPageError = ({ indexName, resendRequest, + navigateToIndicesList, }: { indexName: string; resendRequest: () => Promise; + navigateToIndicesList: () => void; }) => { return ( } body={ - <> - - - - - - - - + + + + } + actions={ + + + + + + + + + + + + } /> ); diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/data_stream_details.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/data_stream_details.tsx index 0ebc7afae33d7..a9b2768e140bb 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/data_stream_details.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/data_stream_details.tsx @@ -10,12 +10,10 @@ import { i18n } from '@kbn/i18n'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText, EuiTextColor } from '@elastic/eui'; import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; -import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public'; import { SectionLoading } from '@kbn/es-ui-shared-plugin/public'; import { FormattedMessage } from '@kbn/i18n-react'; -import { getDataStreamDetailsLink } from '../../../../../services/routing'; -import { getTemplateDetailsLink } from '../../../../../..'; +import { getDataStreamDetailsLink, getTemplateDetailsLink } from '../../../../../services/routing'; import { useLoadDataStream } from '../../../../../services/api'; import { useAppContext } from '../../../../../app_context'; import { humanizeTimeStamp } from '../../../data_stream_list/humanize_time_stamp'; @@ -25,7 +23,9 @@ export const DataStreamDetails: FunctionComponent<{ dataStreamName: string }> = dataStreamName, }) => { const { error, data: dataStream, isLoading, resendRequest } = useLoadDataStream(dataStreamName); - const { history } = useAppContext(); + const { + core: { getUrlForApp }, + } = useAppContext(); const hasError = !isLoading && (error || !dataStream); let contentLeft: ReactNode = ( @@ -53,7 +53,10 @@ export const DataStreamDetails: FunctionComponent<{ dataStreamName: string }> = {i18n.translate('xpack.idxMgmt.indexDetails.overviewTab.dataStream.dataStreamLinkLabel', { defaultMessage: 'See details', @@ -63,10 +66,12 @@ export const DataStreamDetails: FunctionComponent<{ dataStreamName: string }> = {i18n.translate('xpack.idxMgmt.indexDetails.overviewTab.dataStream.templateLinkLabel', { defaultMessage: 'Related template', diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/languages.ts b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/languages.ts index 9904f7cbb70c7..d5a8bbb60a091 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/languages.ts +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/details_page_overview/languages.ts @@ -23,6 +23,7 @@ export const curlDefinition: LanguageDefinition = { -d' { "index" : { "_index" : "${indexName ?? INDEX_NAME_PLACEHOLDER}" } } {"name": "foo", "title": "bar" } +' `, }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/manage_index_button.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/manage_index_button.tsx index 8bfaffa51273f..7de07493ef78e 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/manage_index_button.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/details_page/manage_index_button.tsx @@ -43,7 +43,7 @@ const getIndexStatusByName = ( interface Props { index: Index; reloadIndexDetails: () => Promise; - navigateToAllIndices: () => void; + navigateToIndicesList: () => void; } /** @@ -55,7 +55,7 @@ interface Props { export const ManageIndexButton: FunctionComponent = ({ index, reloadIndexDetails, - navigateToAllIndices, + navigateToIndicesList, }) => { const [isLoading, setIsLoading] = useState(false); @@ -212,12 +212,12 @@ export const ManageIndexButton: FunctionComponent = ({ values: { indexNames: indexNames.join(', ') }, }) ); - navigateToAllIndices(); + navigateToIndicesList(); } catch (error) { setIsLoading(false); notificationService.showDangerToast(error.body.message); } - }, [navigateToAllIndices, indexNames]); + }, [navigateToIndicesList, indexNames]); const performExtensionAction = useCallback( async ( diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js index 838aee24a9c58..6ea481ae463a6 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.container.js @@ -24,7 +24,6 @@ import { pageSizeChanged, sortChanged, loadIndices, - reloadIndices, toggleChanged, } from '../../../../store/actions'; @@ -64,9 +63,6 @@ const mapDispatchToProps = (dispatch) => { loadIndices: () => { dispatch(loadIndices()); }, - reloadIndices: (indexNames, options) => { - dispatch(reloadIndices(indexNames, options)); - }, }; }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js index 000c34988310b..2c26a91a5108f 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/index_table/index_table.js @@ -41,7 +41,6 @@ import { reactRouterNavigate, attemptToURIDecode, } from '../../../../../shared_imports'; -import { REFRESH_RATE_INDEX_LIST } from '../../../../constants'; import { getDataStreamDetailsLink, getIndexDetailsLink } from '../../../../services/routing'; import { documentationService } from '../../../../services/documentation'; import { AppContextConsumer } from '../../../../app_context'; @@ -119,14 +118,6 @@ export class IndexTable extends Component { componentDidMount() { this.props.loadIndices(); - this.interval = setInterval( - () => - this.props.reloadIndices( - this.props.indices.map((i) => i.name), - { asSystemRequest: true } - ), - REFRESH_RATE_INDEX_LIST - ); const { location, filterChanged } = this.props; const { filter } = qs.parse((location && location.search) || ''); if (filter) { @@ -147,7 +138,6 @@ export class IndexTable extends Component { // navigating back to this tab would just show an empty list because the backing indices // would be hidden. this.props.filterChanged(''); - clearInterval(this.interval); } readURLParams() { @@ -617,9 +607,7 @@ export class IndexTable extends Component { { - loadIndices(); - }} + onClick={loadIndices} iconType="refresh" data-test-subj="reloadIndicesButton" > diff --git a/x-pack/plugins/infra/public/containers/metrics_source/source.tsx b/x-pack/plugins/infra/public/containers/metrics_source/source.tsx index ffbc7148bc017..4cce1e9540f75 100644 --- a/x-pack/plugins/infra/public/containers/metrics_source/source.tsx +++ b/x-pack/plugins/infra/public/containers/metrics_source/source.tsx @@ -8,8 +8,8 @@ import createContainer from 'constate'; import React, { useEffect, useState } from 'react'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; import { IHttpFetchError } from '@kbn/core-http-browser'; +import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import type { MetricsSourceConfigurationResponse, MetricsSourceConfiguration, @@ -34,11 +34,13 @@ export const pickIndexPattern = ( }; export const useSource = ({ sourceId }: { sourceId: string }) => { - const { services } = useKibana(); + const { + services: { http, telemetry }, + } = useKibanaContextForPlugin(); const notify = useSourceNotifier(); - const fetchService = services.http; + const fetchService = http; const API_URL = `/api/metrics/source/${sourceId}`; const [source, setSource] = useState(undefined); @@ -46,12 +48,22 @@ export const useSource = ({ sourceId }: { sourceId: string }) => { const [loadSourceRequest, loadSource] = useTrackedPromise( { cancelPreviousOn: 'resolution', - createPromise: () => { + createPromise: async () => { if (!fetchService) { throw new MissingHttpClientException(); } - return fetchService.fetch(API_URL, { method: 'GET' }); + const start = performance.now(); + const response = await fetchService.fetch(API_URL, { + method: 'GET', + }); + telemetry.reportPerformanceMetricEvent( + 'infra_source_load', + performance.now() - start, + {}, + {} + ); + return response; }, onResolve: (response) => { if (response) { diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx index 2082689cb6e1a..bbb8c44a85f7e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/hosts_table.tsx @@ -44,7 +44,7 @@ export const HostsTable = () => { /> { const { sourceId } = useSourceContext(); const { - services: { http, data }, + services: { http, data, telemetry }, } = useKibanaContextForPlugin(); const { buildQuery, parsedDateRange, searchCriteria } = useUnifiedSearchContext(); const abortCtrlRef = useRef(new AbortController()); @@ -59,14 +59,26 @@ export const useHostsView = () => { ); const [state, refetch] = useAsyncFn( - () => { + async () => { abortCtrlRef.current.abort(); abortCtrlRef.current = new AbortController(); - return http.post(`${BASE_INFRA_METRICS_PATH}`, { - signal: abortCtrlRef.current.signal, - body: JSON.stringify(baseRequest), - }); + const start = performance.now(); + const metricsResponse = await http.post( + `${BASE_INFRA_METRICS_PATH}`, + { + signal: abortCtrlRef.current.signal, + body: JSON.stringify(baseRequest), + } + ); + const duration = performance.now() - start; + telemetry.reportPerformanceMetricEvent( + 'infra_hosts_table_load', + duration, + { key1: 'data_load', value1: duration }, + { limit: searchCriteria.limit } + ); + return metricsResponse; }, [baseRequest, http], { loading: true } diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts index 1f354ecd1670f..08a2f9fb9eedb 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.mock.ts @@ -15,4 +15,5 @@ export const createTelemetryClientMock = (): jest.Mocked => ({ reportHostsViewTotalHostCountRetrieved: jest.fn(), reportAssetDetailsFlyoutViewed: jest.fn(), reportAssetDetailsPageViewed: jest.fn(), + reportPerformanceMetricEvent: jest.fn(), }); diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts index d4acc0a8bd96d..2c8cac426635d 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts @@ -6,6 +6,7 @@ */ import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; +import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { AssetDetailsFlyoutViewedParams, AssetDetailsPageViewedParams, @@ -15,6 +16,7 @@ import { HostsViewQuerySubmittedParams, InfraTelemetryEventTypes, ITelemetryClient, + PerformanceMetricInnerEvents, } from './types'; /** @@ -70,4 +72,18 @@ export class TelemetryClient implements ITelemetryClient { public reportAssetDetailsPageViewed = (params: AssetDetailsPageViewedParams) => { this.analytics.reportEvent(InfraTelemetryEventTypes.ASSET_DETAILS_PAGE_VIEWED, params); }; + + public reportPerformanceMetricEvent = ( + eventName: string, + duration: number, + innerEvents: PerformanceMetricInnerEvents = {}, + meta: Record = {} + ) => { + reportPerformanceMetricEvent(this.analytics, { + eventName, + duration, + meta, + ...innerEvents, + }); + }; } diff --git a/x-pack/plugins/infra/public/services/telemetry/types.ts b/x-pack/plugins/infra/public/services/telemetry/types.ts index 769cc303def50..0556b20af0fb4 100644 --- a/x-pack/plugins/infra/public/services/telemetry/types.ts +++ b/x-pack/plugins/infra/public/services/telemetry/types.ts @@ -61,6 +61,11 @@ export type InfraTelemetryEventParams = | HostsViewQueryHostsCountRetrievedParams | AssetDetailsFlyoutViewedParams; +export interface PerformanceMetricInnerEvents { + key1?: string; + value1?: number; +} + export interface ITelemetryClient { reportHostEntryClicked(params: HostEntryClickedParams): void; reportHostFlyoutFilterRemoved(params: HostFlyoutFilterActionParams): void; @@ -69,6 +74,12 @@ export interface ITelemetryClient { reportHostsViewQuerySubmitted(params: HostsViewQuerySubmittedParams): void; reportAssetDetailsFlyoutViewed(params: AssetDetailsFlyoutViewedParams): void; reportAssetDetailsPageViewed(params: AssetDetailsPageViewedParams): void; + reportPerformanceMetricEvent( + eventName: string, + duration: number, + innerEvents: PerformanceMetricInnerEvents, + meta: Record + ): void; } export type InfraTelemetryEvent = diff --git a/x-pack/plugins/infra/tsconfig.json b/x-pack/plugins/infra/tsconfig.json index cbcbdbbbc365f..955a3a18cf2e1 100644 --- a/x-pack/plugins/infra/tsconfig.json +++ b/x-pack/plugins/infra/tsconfig.json @@ -79,7 +79,8 @@ "@kbn/profiling-utils", "@kbn/profiling-data-access-plugin", "@kbn/core-http-request-handler-context-server", - "@kbn/observability-get-padded-alert-time-range-util" + "@kbn/observability-get-padded-alert-time-range-util", + "@kbn/ebt-tools" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index 8b7705260c1e4..842904741ec9b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -27,6 +27,7 @@ import type { Datatable } from '@kbn/expressions-plugin/public'; import { DropIllustration } from '@kbn/chart-icons'; import { DragDrop, useDragDropContext, DragDropIdentifier } from '@kbn/dom-drag-drop'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; +import { ChartSizeSpec, isChartSizeEvent } from '@kbn/chart-expressions-common'; import { trackUiCounterEvents } from '../../../lens_ui_telemetry'; import { getSearchWarningMessages } from '../../../utils'; import { @@ -43,6 +44,7 @@ import { UserMessagesGetter, AddUserMessages, isMessageRemovable, + VisualizationDisplayOptions, } from '../../../types'; import { switchToSuggestion } from '../suggestion_helpers'; import { buildExpression } from '../expression_helpers'; @@ -413,6 +415,8 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ } }, [expressionExists, localState.expressionToRender]); + const [chartSizeSpec, setChartSize] = useState(); + const onEvent = useCallback( (event: ExpressionRendererEvent) => { if (!plugins.uiActions) { @@ -443,10 +447,15 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ }) ); } + + if (isChartSizeEvent(event)) { + setChartSize(event.data); + } }, [plugins.data.datatableUtilities, plugins.uiActions, activeVisualization, dispatchLens] ); + const displayOptions = activeVisualization?.getDisplayOptions?.(); const hasCompatibleActions = useCallback( async (event: ExpressionRendererEvent) => { if (!plugins.uiActions) { @@ -478,6 +487,10 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ const IS_DARK_THEME: boolean = useObservable(core.theme.theme$, { darkMode: false }).darkMode; const renderDragDropPrompt = () => { + if (chartSizeSpec) { + setChartSize(undefined); + } + return ( { + if (chartSizeSpec) { + setChartSize(undefined); + } + const applyChangesString = i18n.translate('xpack.lens.editorFrame.applyChanges', { defaultMessage: 'Apply changes', }); @@ -590,6 +607,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ onComponentRendered={() => { visualizationRenderStartTime.current = performance.now(); }} + displayOptions={displayOptions} /> ); }; @@ -639,7 +657,6 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ return ( {renderWorkspace()} @@ -686,6 +704,7 @@ export const VisualizationWrapper = ({ onRender$, onData$, onComponentRendered, + displayOptions, }: { expression: string | null | undefined; lensInspector: LensInspector; @@ -699,6 +718,7 @@ export const VisualizationWrapper = ({ onRender$: () => void; onData$: (data: unknown, adapters?: Partial) => void; onComponentRendered: () => void; + displayOptions: VisualizationDisplayOptions | undefined; }) => { useEffect(() => { onComponentRendered(); @@ -751,7 +771,7 @@ export const VisualizationWrapper = ({ > * { + &>* { flex: 1 1 100%; display: flex; align-items: center; @@ -37,6 +37,7 @@ &.lnsWorkspacePanelWrapper--fullscreen { margin-bottom: 0; + .lnsWorkspacePanelWrapper__pageContentBody { box-shadow: none; } @@ -45,8 +46,6 @@ } .lnsWorkspacePanel__dragDrop { - border: $euiBorderWidthThin solid transparent; - &.domDragDrop-isDropTarget { p { transition: filter $euiAnimSpeedFast ease-in-out; @@ -120,9 +119,7 @@ // Hard-coded px values OK (@cchaos) // sass-lint:disable-block indentation filter: - drop-shadow(0 6px 12px transparentize($euiShadowColor, .8)) - drop-shadow(0 4px 4px transparentize($euiShadowColor, .8)) - drop-shadow(0 2px 2px transparentize($euiShadowColor, .8)); + drop-shadow(0 6px 12px transparentize($euiShadowColor, .8)) drop-shadow(0 4px 4px transparentize($euiShadowColor, .8)) drop-shadow(0 2px 2px transparentize($euiShadowColor, .8)); } .lnsDropIllustration__adjustFill { @@ -134,20 +131,51 @@ } @keyframes lnsWorkspacePanel__illustrationPulseArrow { - 0% { transform: translateY(0%); } - 65% { transform: translateY(0%); } - 72% { transform: translateY(10%); } - 79% { transform: translateY(7%); } - 86% { transform: translateY(10%); } - 95% { transform: translateY(0); } + 0% { + transform: translateY(0%); + } + + 65% { + transform: translateY(0%); + } + + 72% { + transform: translateY(10%); + } + + 79% { + transform: translateY(7%); + } + + 86% { + transform: translateY(10%); + } + + 95% { + transform: translateY(0); + } } @keyframes lnsWorkspacePanel__illustrationPulseContinuous { - 0% { transform: translateY(10%); } - 25% { transform: translateY(15%); } - 50% { transform: translateY(10%); } - 75% { transform: translateY(15%); } - 100% { transform: translateY(10%); } + 0% { + transform: translateY(10%); + } + + 25% { + transform: translateY(15%); + } + + 50% { + transform: translateY(10%); + } + + 75% { + transform: translateY(15%); + } + + 100% { + transform: translateY(10%); + } } .lnsVisualizationToolbar--fixed { @@ -155,4 +183,4 @@ width: 100%; z-index: 1; background-color: $euiColorLightestShade; -} +} \ No newline at end of file diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx index eeec313584117..8694cc7c27dcf 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.test.tsx @@ -34,7 +34,6 @@ describe('workspace_panel_wrapper', () => { <> { lensInspector={{} as unknown as LensInspector} getUserMessages={() => []} children={} + displayOptions={undefined} {...propsOverrides} /> = { + pixels: 'px', + percentage: '%', +}; + +const getAspectRatioStyles = ({ x, y }: { x: number; y: number }) => { + return { + aspectRatio: `${x}/${y}`, + ...(y > x + ? { + height: '100%', + width: 'auto', + } + : { + height: 'auto', + width: '100%', + }), + }; +}; + export function VisualizationToolbar(props: { activeVisualization: Visualization | null; framePublicAPI: FramePublicAPI; @@ -98,12 +120,12 @@ export function VisualizationToolbar(props: { export function WorkspacePanelWrapper({ children, framePublicAPI, - visualizationState, visualizationId, visualizationMap, datasourceMap, isFullscreen, getUserMessages, + displayOptions, }: WorkspacePanelWrapperProps) { const dispatchLens = useLensDispatch(); @@ -113,6 +135,34 @@ export function WorkspacePanelWrapper({ const activeVisualization = visualizationId ? visualizationMap[visualizationId] : null; const userMessages = getUserMessages('toolbar'); + const aspectRatio = displayOptions?.aspectRatio; + const maxDimensions = displayOptions?.maxDimensions; + const minDimensions = displayOptions?.minDimensions; + + let visDimensionsCSS: Interpolation = {}; + + if (aspectRatio) { + visDimensionsCSS = getAspectRatioStyles(aspectRatio ?? maxDimensions); + } + + if (maxDimensions) { + visDimensionsCSS.maxWidth = maxDimensions.x + ? `${maxDimensions.x.value}${unitToCSSUnit[maxDimensions.x.unit]}` + : ''; + visDimensionsCSS.maxHeight = maxDimensions.y + ? `${maxDimensions.y.value}${unitToCSSUnit[maxDimensions.y.unit]}` + : ''; + } + + if (minDimensions) { + visDimensionsCSS.minWidth = minDimensions.x + ? `${minDimensions.x.value}${unitToCSSUnit[minDimensions.x.unit]}` + : ''; + visDimensionsCSS.minHeight = minDimensions.y + ? `${minDimensions.y.value}${unitToCSSUnit[minDimensions.y.unit]}` + : ''; + } + return ( )} + - - {children} + + + + {children} + + ); diff --git a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx index edb54facff31c..6c038125b0718 100644 --- a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx @@ -92,6 +92,7 @@ export function ExpressionWrapper({ syncTooltips={syncTooltips} syncCursor={syncCursor} executionContext={executionContext} + shouldUseSizeTransitionVeil={true} renderError={(errorMessage, error) => { const messages = getOriginalRequestErrorMessages(error || null); addUserMessages(messages); diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 53bb59c0a5459..38054103183a5 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -42,6 +42,7 @@ import { CellValueContext } from '@kbn/embeddable-plugin/public'; import { EventAnnotationGroupConfig } from '@kbn/event-annotation-common'; import type { DraggingIdentifier, DragDropIdentifier, DropType } from '@kbn/dom-drag-drop'; import type { AccessorConfig } from '@kbn/visualization-ui-components'; +import type { ChartSizeEvent } from '@kbn/chart-expressions-common'; import type { DateRange, LayerType, SortingHint } from '../common/types'; import type { LensSortActionData, @@ -1391,6 +1392,7 @@ export interface ILensInterpreterRenderHandlers extends IInterpreterRenderHandle | BrushTriggerEvent | LensEditEvent | LensTableRowContextMenuEvent + | ChartSizeEvent ) => void; } diff --git a/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx b/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx index 6c97dae2baab1..eae35c5a925dc 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/expression.tsx @@ -18,6 +18,7 @@ import type { IInterpreterRenderHandlers, } from '@kbn/expressions-plugin/common'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; +import { ChartSizeEvent } from '@kbn/chart-expressions-common'; import { trackUiCounterEvents } from '../../lens_ui_telemetry'; import { DatatableComponent } from './components/table_basic'; @@ -103,6 +104,18 @@ export const getDatatableRenderer = (dependencies: { handlers.done(); }; + const chartSizeEvent: ChartSizeEvent = { + name: 'chartSize', + data: { + maxDimensions: { + x: { value: 100, unit: 'percentage' }, + y: { value: 100, unit: 'percentage' }, + }, + }, + }; + + handlers.event(chartSizeEvent); + // An entry for each table row, whether it has any actions attached to // ROW_CLICK_TRIGGER trigger. let rowHasRowClickTriggerActions: boolean[] = []; diff --git a/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts b/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts index 1b45671e29cc6..3b79cb69cd38c 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts +++ b/x-pack/plugins/lens/public/visualizations/metric/visualization.test.ts @@ -143,7 +143,7 @@ describe('metric visualization', () => { ).toMatchInlineSnapshot(` Array [ Object { - "color": "#f5f7fa", + "color": "#ffffff", "columnId": "metric-col-id", "triggerIconType": "color", }, @@ -727,7 +727,7 @@ describe('metric visualization', () => { datasourceLayers ) as ExpressionAstExpression ).chain[1].arguments.color[0] - ).toBe(euiLightVars.euiColorLightestShade); + ).toBe(euiLightVars.euiColorEmptyShade); expect( ( @@ -741,7 +741,7 @@ describe('metric visualization', () => { datasourceLayers ) as ExpressionAstExpression ).chain[1].arguments.color[0] - ).toBe(euiLightVars.euiColorLightestShade); + ).toBe(euiLightVars.euiColorEmptyShade); // this case isn't currently relevant because other parts of the code don't allow showBar to be // set when there isn't a max dimension but this test covers the branch anyhow @@ -757,7 +757,7 @@ describe('metric visualization', () => { datasourceLayers ) as ExpressionAstExpression ).chain[1].arguments.color[0] - ).toEqual(euiThemeVars.euiColorLightestShade); + ).toEqual(euiThemeVars.euiColorEmptyShade); }); }); diff --git a/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx b/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx index 00b931714c1be..28c547df25ebd 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx +++ b/x-pack/plugins/lens/public/visualizations/metric/visualization.tsx @@ -45,7 +45,7 @@ export const showingBar = ( export const getDefaultColor = (state: MetricVisualizationState, isMetricNumeric?: boolean) => { return showingBar(state) && isMetricNumeric ? euiLightVars.euiColorPrimary - : euiThemeVars.euiColorLightestShade; + : euiThemeVars.euiColorEmptyShade; }; export interface MetricVisualizationState { diff --git a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx index 615945280c264..059d612883d82 100644 --- a/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx +++ b/x-pack/plugins/maps/public/lens/choropleth_chart/expression_renderer.tsx @@ -13,6 +13,7 @@ import { METRIC_TYPE } from '@kbn/analytics'; import type { CoreSetup, CoreStart } from '@kbn/core/public'; import type { FileLayer } from '@elastic/ems-client'; import type { KibanaExecutionContext } from '@kbn/core-execution-context-common'; +import { ChartSizeEvent } from '@kbn/chart-expressions-common'; import type { MapsPluginStartDependencies } from '../../plugin'; import type { ChoroplethChartProps } from './types'; import type { MapEmbeddableInput, MapEmbeddableOutput } from '../../embeddable'; @@ -92,6 +93,18 @@ export function getExpressionRenderer(coreSetup: CoreSetup; -}; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_ccr_read_exceptions', () => ({ - fetchCCRReadExceptions: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); - -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('CCRReadExceptionsRule', () => { - it('should have defaults', () => { - const rule = new CCRReadExceptionsRule() as ICCRReadExceptionsRuleMock; - expect(rule.ruleOptions.id).toBe(RULE_CCR_READ_EXCEPTIONS); - expect(rule.ruleOptions.name).toBe('CCR read exceptions'); - expect(rule.ruleOptions.throttle).toBe('6h'); - expect(rule.ruleOptions.defaultParams).toStrictEqual({ - duration: '1h', - }); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { - name: 'remoteCluster', - description: 'The remote cluster experiencing CCR read exceptions.', - }, - { - name: 'followerIndex', - description: 'The follower index reporting CCR read exceptions.', - }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - describe('execute', () => { - const FakeDate = function () {}; - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const nodeId = 'myNodeId'; - const nodeName = 'myNodeName'; - const remoteCluster = 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1'; - const followerIndex = '.follower_index_1'; - const leaderIndex = '.leader_index_1'; - const readExceptions = [ - { - exception: { - type: 'read_exceptions_type_1', - reason: 'read_exceptions_reason_1', - }, - }, - ]; - const stat = { - remoteCluster, - followerIndex, - leaderIndex, - read_exceptions: readExceptions, - clusterUuid, - nodeId, - nodeName, - }; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - Date = FakeDate as DateConstructor; - (fetchCCRReadExceptions as jest.Mock).mockImplementation(() => { - return [stat]; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new CCRReadExceptionsRule() as ICCRReadExceptionsRuleMock; - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Current 'follower_index' index affected: ${followerIndex}. [View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Verify follower and leader index relationships on the affected remote cluster.`, - action: `[View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: - 'Verify follower and leader index relationships on the affected remote cluster.', - clusterName, - state: 'firing', - remoteCluster, - remoteClusters: remoteCluster, - followerIndex, - followerIndices: followerIndex, - }); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchCCRReadExceptions as jest.Mock).mockImplementation(() => { - return [ - { - ...stat, - ccs, - }, - ]; - }); - const rule = new CCRReadExceptionsRule() as ICCRReadExceptionsRuleMock; - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Current 'follower_index' index affected: ${followerIndex}. [View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, - internalShortMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Verify follower and leader index relationships on the affected remote cluster.`, - action: `[View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, - actionPlain: - 'Verify follower and leader index relationships on the affected remote cluster.', - clusterName, - state: 'firing', - remoteCluster, - remoteClusters: remoteCluster, - followerIndex, - followerIndices: followerIndex, - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.test.ts deleted file mode 100644 index 6c5858d48e94e..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.test.ts +++ /dev/null @@ -1,257 +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 { CpuUsageRule } from './cpu_usage_rule'; -import { RULE_CPU_USAGE } from '../../common/constants'; -import { fetchCpuUsageNodeStats } from '../lib/alerts/fetch_cpu_usage_node_stats'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_cpu_usage_node_stats', () => ({ - fetchCpuUsageNodeStats: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('CpuUsageRule', () => { - it('should have defaults', () => { - const rule = new CpuUsageRule(); - expect(rule.ruleOptions.id).toBe(RULE_CPU_USAGE); - expect(rule.ruleOptions.name).toBe('CPU Usage'); - expect(rule.ruleOptions.throttle).toBe('1d'); - expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 85, duration: '5m' }); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { name: 'node', description: 'The node reporting high cpu usage.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - - describe('execute', () => { - function FakeDate() {} - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const nodeId = 'myNodeId'; - const nodeName = 'myNodeName'; - const cpuUsage = 91; - const stat = { - clusterUuid, - nodeId, - nodeName, - cpuUsage, - }; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - // @ts-ignore - Date = FakeDate; - (fetchCpuUsageNodeStats as jest.Mock).mockImplementation(() => { - return [stat]; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new CpuUsageRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - ccs: undefined, - cluster: { clusterUuid, clusterName }, - cpuUsage, - itemLabel: undefined, - meta: { - clusterUuid, - cpuUsage, - nodeId, - nodeName, - }, - nodeId, - nodeName, - ui: { - isFiring: true, - message: { - text: `Node #start_link${nodeName}#end_link is reporting cpu usage of ${cpuUsage}% at #absolute`, - nextSteps: [ - { - text: '#start_linkCheck hot threads#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/cluster-nodes-hot-threads.html', - }, - ], - }, - { - text: '#start_linkCheck long running tasks#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/tasks.html', - }, - ], - }, - ], - tokens: [ - { - startToken: '#absolute', - type: 'time', - isAbsolute: true, - isRelative: false, - timestamp: 1, - }, - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'elasticsearch/nodes/myNodeId', - }, - ], - }, - severity: 'danger', - triggeredMS: 1, - lastCheckedMS: 0, - }, - }, - ], - }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify CPU level of node.`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: 'Verify CPU level of node.', - clusterName, - count, - nodes: `${nodeName}:${cpuUsage}`, - node: `${nodeName}:${cpuUsage}`, - state: 'firing', - }); - }); - - it('should not fire actions if under threshold', async () => { - (fetchCpuUsageNodeStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat, - cpuUsage: 1, - }, - ]; - }); - const rule = new CpuUsageRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [], - }); - expect(scheduleActions).not.toHaveBeenCalled(); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchCpuUsageNodeStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat, - ccs, - }, - ]; - }); - const rule = new CpuUsageRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, - internalShortMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify CPU level of node.`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, - actionPlain: 'Verify CPU level of node.', - clusterName, - count, - nodes: `${nodeName}:${cpuUsage}`, - node: `${nodeName}:${cpuUsage}`, - state: 'firing', - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.test.ts deleted file mode 100644 index c0b9720422e53..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.test.ts +++ /dev/null @@ -1,180 +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 { DiskUsageRule } from './disk_usage_rule'; -import { RULE_DISK_USAGE } from '../../common/constants'; -import { fetchDiskUsageNodeStats } from '../lib/alerts/fetch_disk_usage_node_stats'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -type IDiskUsageAlertMock = DiskUsageRule & { - defaultParams: { - threshold: number; - duration: string; - }; -} & { - actionVariables: Array<{ - name: string; - description: string; - }>; -}; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_disk_usage_node_stats', () => ({ - fetchDiskUsageNodeStats: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); - -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('DiskUsageRule', () => { - it('should have defaults', () => { - const alert = new DiskUsageRule() as IDiskUsageAlertMock; - expect(alert.ruleOptions.id).toBe(RULE_DISK_USAGE); - expect(alert.ruleOptions.name).toBe('Disk Usage'); - expect(alert.ruleOptions.throttle).toBe('1d'); - expect(alert.ruleOptions.defaultParams).toStrictEqual({ threshold: 80, duration: '5m' }); - expect(alert.ruleOptions.actionVariables).toStrictEqual([ - { name: 'node', description: 'The node reporting high disk usage.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - - describe('execute', () => { - const FakeDate = function () {}; - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const nodeId = 'myNodeId'; - const nodeName = 'myNodeName'; - const diskUsage = 91; - const stat = { - clusterUuid, - nodeId, - nodeName, - diskUsage, - }; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - Date = FakeDate as DateConstructor; - (fetchDiskUsageNodeStats as jest.Mock).mockImplementation(() => { - return [stat]; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new DiskUsageRule() as IDiskUsageAlertMock; - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify disk usage level of node.`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: 'Verify disk usage level of node.', - clusterName, - count, - nodes: `${nodeName}:${diskUsage}`, - node: `${nodeName}:${diskUsage}`, - state: 'firing', - }); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchDiskUsageNodeStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat, - ccs, - }, - ]; - }); - const rule = new DiskUsageRule() as IDiskUsageAlertMock; - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, - internalShortMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify disk usage level of node.`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/myNodeId?_g=(cluster_uuid:abc123,ccs:testCluster))`, - actionPlain: 'Verify disk usage level of node.', - clusterName, - count, - nodes: `${nodeName}:${diskUsage}`, - node: `${nodeName}:${diskUsage}`, - state: 'firing', - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.test.ts deleted file mode 100644 index 1784ca8c0df71..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.test.ts +++ /dev/null @@ -1,176 +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 { LargeShardSizeRule } from './large_shard_size_rule'; -import { RULE_LARGE_SHARD_SIZE } from '../../common/constants'; -import { fetchIndexShardSize } from '../lib/alerts/fetch_index_shard_size'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -type ILargeShardSizeRuleMock = LargeShardSizeRule & { - defaultParams: { - threshold: number; - duration: string; - }; -} & { - actionVariables: Array<{ - name: string; - description: string; - }>; -}; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_index_shard_size', () => ({ - fetchIndexShardSize: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); - -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('LargeShardSizeRule', () => { - it('should have defaults', () => { - const rule = new LargeShardSizeRule() as ILargeShardSizeRuleMock; - expect(rule.ruleOptions.id).toBe(RULE_LARGE_SHARD_SIZE); - expect(rule.ruleOptions.name).toBe('Shard size'); - expect(rule.ruleOptions.throttle).toBe('12h'); - expect(rule.ruleOptions.defaultParams).toStrictEqual({ - threshold: 55, - indexPattern: '-.*', - }); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { name: 'shardIndex', description: 'The index experiencing large average shard size.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - describe('execute', () => { - const FakeDate = function () {}; - FakeDate.prototype.valueOf = () => 1; - - const shardIndex = 'apm-8.0.0-onboarding-2021.06.30'; - const shardSize = 0; - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const stat = { - shardIndex, - shardSize, - clusterUuid, - }; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - Date = FakeDate as DateConstructor; - (fetchIndexShardSize as jest.Mock).mockImplementation(() => { - return [stat]; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new LargeShardSizeRule() as ILargeShardSizeRuleMock; - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Large shard size alert is firing for the following index: ${shardIndex}. [View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `Large shard size alert is firing for the following index: ${shardIndex}. Investigate indices with large shard sizes.`, - action: `[View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: 'Investigate indices with large shard sizes.', - clusterName, - state: 'firing', - shardIndex, - shardIndices: shardIndex, - }); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchIndexShardSize as jest.Mock).mockImplementation(() => { - return [ - { - ...stat, - ccs, - }, - ]; - }); - const rule = new LargeShardSizeRule() as ILargeShardSizeRuleMock; - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Large shard size alert is firing for the following index: ${shardIndex}. [View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, - internalShortMessage: `Large shard size alert is firing for the following index: ${shardIndex}. Investigate indices with large shard sizes.`, - action: `[View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, - actionPlain: 'Investigate indices with large shard sizes.', - clusterName, - state: 'firing', - shardIndex, - shardIndices: shardIndex, - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.test.ts deleted file mode 100644 index 7943e2dfca973..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.test.ts +++ /dev/null @@ -1,250 +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 { LicenseExpirationRule } from './license_expiration_rule'; -import { RULE_LICENSE_EXPIRATION } from '../../common/constants'; -import { AlertSeverity } from '../../common/enums'; -import { fetchLicenses } from '../lib/alerts/fetch_licenses'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_licenses', () => ({ - fetchLicenses: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); - -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - config: { - ui: { - show_license_expiration: true, - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('LicenseExpirationRule', () => { - it('should have defaults', () => { - const rule = new LicenseExpirationRule(); - expect(rule.ruleOptions.id).toBe(RULE_LICENSE_EXPIRATION); - expect(rule.ruleOptions.name).toBe('License expiration'); - expect(rule.ruleOptions.throttle).toBe('1d'); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { name: 'expiredDate', description: 'The date when the license expires.' }, - { name: 'clusterName', description: 'The cluster to which the license belong.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - - describe('execute', () => { - function FakeDate() {} - - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const license = { - status: 'expired', - type: 'gold', - expiryDateMS: 1000 * 60 * 60 * 24 * 59, - clusterUuid, - }; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - // @ts-ignore - Date = FakeDate; - (fetchLicenses as jest.Mock).mockImplementation(() => { - return [license]; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - afterAll(() => { - jest.useRealTimers(); - }); - - it('should fire actions', async () => { - jest.useFakeTimers().setSystemTime(new Date('2023-03-30T00:00:00.000Z')); - const alert = new LicenseExpirationRule(); - const type = alert.getRuleType(); - await type.executor({ - ...executorOptions, - params: alert.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - cluster: { clusterUuid, clusterName }, - ccs: undefined, - itemLabel: undefined, - meta: { - clusterUuid: 'abc123', - expiryDateMS: 5097600000, - status: 'expired', - type: 'gold', - }, - nodeId: undefined, - nodeName: undefined, - ui: { - isFiring: true, - message: { - text: 'The license for this cluster expires in #relative at #absolute. #start_linkPlease update your license.#end_link', - tokens: [ - { - startToken: '#relative', - type: 'time', - isRelative: true, - isAbsolute: false, - timestamp: 5097600000, - }, - { - startToken: '#absolute', - type: 'time', - isAbsolute: true, - isRelative: false, - timestamp: 5097600000, - }, - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'license', - }, - ], - }, - severity: 'danger', - triggeredMS: 1680134400000, - lastCheckedMS: 0, - }, - }, - ], - }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - action: '[Please update your license.](elasticsearch/nodes)', - actionPlain: 'Please update your license.', - internalFullMessage: - 'License expiration alert is firing for testCluster. Your license expires in 53 years. [Please update your license.](elasticsearch/nodes)', - internalShortMessage: - 'License expiration alert is firing for testCluster. Your license expires in 53 years. Please update your license.', - clusterName, - expiredDate: '53 years', - state: 'firing', - }); - }); - - it('should not fire actions if the license is not expired', async () => { - (fetchLicenses as jest.Mock).mockImplementation(() => { - return [ - { - status: 'active', - type: 'gold', - expiryDateMS: 1000 * 60 * 60 * 24 * 61, - clusterUuid, - }, - ]; - }); - const rule = new LicenseExpirationRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).not.toHaveBeenCalledWith({}); - expect(scheduleActions).not.toHaveBeenCalled(); - }); - - it('should use danger severity for a license expiring soon', async () => { - (fetchLicenses as jest.Mock).mockImplementation(() => { - return [ - { - status: 'active', - type: 'gold', - expiryDateMS: 1000 * 60 * 60 * 24 * 2, - clusterUuid, - }, - ]; - }); - const rule = new LicenseExpirationRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState.mock.calls[0][0].alertStates[0].ui.severity).toBe(AlertSeverity.Danger); - }); - - it('should use warning severity for a license expiring in a bit', async () => { - (fetchLicenses as jest.Mock).mockImplementation(() => { - return [ - { - status: 'active', - type: 'gold', - expiryDateMS: 1000 * 60 * 60 * 24 * 31, - clusterUuid, - }, - ]; - }); - const rule = new LicenseExpirationRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState.mock.calls[0][0].alertStates[0].ui.severity).toBe(AlertSeverity.Warning); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.test.ts deleted file mode 100644 index ad0cc98c51bb0..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.test.ts +++ /dev/null @@ -1,291 +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 { MemoryUsageRule } from './memory_usage_rule'; -import { RULE_MEMORY_USAGE } from '../../common/constants'; -import { fetchMemoryUsageNodeStats } from '../lib/alerts/fetch_memory_usage_node_stats'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_memory_usage_node_stats', () => ({ - fetchMemoryUsageNodeStats: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('MemoryUsageRule', () => { - it('should have defaults', () => { - const rule = new MemoryUsageRule(); - expect(rule.ruleOptions.id).toBe(RULE_MEMORY_USAGE); - expect(rule.ruleOptions.name).toBe('Memory Usage (JVM)'); - expect(rule.ruleOptions.throttle).toBe('1d'); - expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 85, duration: '5m' }); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { name: 'node', description: 'The node reporting high memory usage.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - - describe('execute', () => { - function FakeDate() {} - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const nodeId = 'myNodeId'; - const nodeName = 'myNodeName'; - const memoryUsage = 91; - const stat = { - clusterUuid, - nodeId, - nodeName, - memoryUsage, - }; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - // @ts-ignore - Date = FakeDate; - (fetchMemoryUsageNodeStats as jest.Mock).mockImplementation(() => { - return [stat]; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new MemoryUsageRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - ccs: undefined, - cluster: { clusterUuid, clusterName }, - memoryUsage, - itemLabel: undefined, - meta: { - clusterUuid, - memoryUsage, - nodeId, - nodeName, - }, - nodeId, - nodeName, - ui: { - isFiring: true, - message: { - text: `Node #start_link${nodeName}#end_link is reporting JVM memory usage of ${memoryUsage}% at #absolute`, - nextSteps: [ - { - text: '#start_linkTune thread pools#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', - }, - ], - }, - { - text: '#start_linkManaging ES Heap#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: '{elasticWebsiteUrl}blog/a-heap-of-trouble', - }, - ], - }, - { - text: '#start_linkIdentify large indices/shards#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'elasticsearch/indices', - }, - ], - }, - { - text: '#start_linkAdd more data nodes#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', - }, - ], - }, - { - text: '#start_linkResize your deployment (ECE)#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', - }, - ], - }, - ], - tokens: [ - { - startToken: '#absolute', - type: 'time', - isAbsolute: true, - isRelative: false, - timestamp: 1, - }, - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'elasticsearch/nodes/myNodeId', - }, - ], - }, - severity: 'danger', - triggeredMS: 1, - lastCheckedMS: 0, - }, - }, - ], - }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify memory usage level of node.`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: 'Verify memory usage level of node.', - clusterName, - count, - nodes: `${nodeName}:${memoryUsage}.00`, - node: `${nodeName}:${memoryUsage}.00`, - state: 'firing', - }); - }); - - it('should not fire actions if under threshold', async () => { - (fetchMemoryUsageNodeStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat, - memoryUsage: 1, - }, - ]; - }); - const rule = new MemoryUsageRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [], - }); - expect(scheduleActions).not.toHaveBeenCalled(); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchMemoryUsageNodeStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat, - ccs, - }, - ]; - }); - const rule = new MemoryUsageRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, - internalShortMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify memory usage level of node.`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, - actionPlain: 'Verify memory usage level of node.', - clusterName, - count, - nodes: `${nodeName}:${memoryUsage}.00`, - node: `${nodeName}:${memoryUsage}.00`, - state: 'firing', - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.test.ts deleted file mode 100644 index 4490e6c51e902..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.test.ts +++ /dev/null @@ -1,248 +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 { MissingMonitoringDataRule } from './missing_monitoring_data_rule'; -import { RULE_MISSING_MONITORING_DATA } from '../../common/constants'; -import { fetchMissingMonitoringData } from '../lib/alerts/fetch_missing_monitoring_data'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_missing_monitoring_data', () => ({ - fetchMissingMonitoringData: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); - -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - show_license_expiration: true, - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('MissingMonitoringDataRule', () => { - it('should have defaults', () => { - const rule = new MissingMonitoringDataRule(); - expect(rule.ruleOptions.id).toBe(RULE_MISSING_MONITORING_DATA); - expect(rule.ruleOptions.name).toBe('Missing monitoring data'); - expect(rule.ruleOptions.throttle).toBe('6h'); - expect(rule.ruleOptions.defaultParams).toStrictEqual({ limit: '1d', duration: '15m' }); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { name: 'node', description: 'The node missing monitoring data.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - - describe('execute', () => { - function FakeDate() {} - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const nodeId = 'esNode1'; - const nodeName = 'esName1'; - const gapDuration = 3000001; - const missingData = [ - { - nodeId, - nodeName, - clusterUuid, - gapDuration, - }, - ]; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - // @ts-ignore - Date = FakeDate; - (fetchMissingMonitoringData as jest.Mock).mockImplementation(() => { - return missingData; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new MissingMonitoringDataRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - ccs: undefined, - cluster: { clusterUuid, clusterName }, - nodeId, - nodeName, - gapDuration, - itemLabel: undefined, - meta: { - clusterUuid, - gapDuration, - limit: 86400000, - nodeId, - nodeName, - }, - ui: { - isFiring: true, - message: { - text: 'For the past an hour, we have not detected any monitoring data from the Elasticsearch node: esName1, starting at #absolute', - nextSteps: [ - { - text: '#start_linkView all Elasticsearch nodes#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'elasticsearch/nodes', - }, - ], - }, - { - text: 'Verify monitoring settings on the node', - }, - ], - tokens: [ - { - startToken: '#absolute', - type: 'time', - isAbsolute: true, - isRelative: false, - timestamp: 1, - }, - ], - }, - severity: 'danger', - triggeredMS: 1, - lastCheckedMS: 0, - }, - }, - ], - }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. [View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. Verify the node is up and running, then double check the monitoring settings.`, - nodes: `node: ${nodeName}`, - node: `node: ${nodeName}`, - action: `[View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: - 'Verify the node is up and running, then double check the monitoring settings.', - clusterName, - count, - state: 'firing', - }); - }); - - it('should not fire actions if under threshold', async () => { - (fetchMissingMonitoringData as jest.Mock).mockImplementation(() => { - return [ - { - ...missingData[0], - gapDuration: 1, - }, - ]; - }); - const rule = new MissingMonitoringDataRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [], - }); - expect(scheduleActions).not.toHaveBeenCalled(); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchMissingMonitoringData as jest.Mock).mockImplementation(() => { - return [ - { - ...missingData[0], - ccs, - }, - ]; - }); - const rule = new MissingMonitoringDataRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. [View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, - internalShortMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. Verify the node is up and running, then double check the monitoring settings.`, - nodes: `node: ${nodeName}`, - node: `node: ${nodeName}`, - action: `[View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, - actionPlain: - 'Verify the node is up and running, then double check the monitoring settings.', - clusterName, - count, - state: 'firing', - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.test.ts deleted file mode 100644 index ff0c917684e10..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.test.ts +++ /dev/null @@ -1,297 +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 { ThreadPoolSearchRejectionsRule } from './thread_pool_search_rejections_rule'; -import { RULE_THREAD_POOL_SEARCH_REJECTIONS } from '../../common/constants'; -import { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_thread_pool_rejections_stats', () => ({ - fetchThreadPoolRejectionStats: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); - -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - show_license_expiration: true, - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('ThreadpoolSearchRejectionsRule', () => { - it('should have defaults', () => { - const rule = new ThreadPoolSearchRejectionsRule(); - expect(rule.ruleOptions.id).toBe(RULE_THREAD_POOL_SEARCH_REJECTIONS); - expect(rule.ruleOptions.name).toBe('Thread pool search rejections'); - expect(rule.ruleOptions.throttle).toBe('1d'); - expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 300, duration: '5m' }); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { name: 'node', description: 'The node reporting high thread pool search rejections.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - describe('execute', () => { - function FakeDate() {} - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const nodeId = 'esNode1'; - const nodeName = 'esName1'; - const threadPoolType = 'search'; - const rejectionCount = 400; - const stat = [ - { - rejectionCount, - type: threadPoolType, - clusterUuid, - nodeId, - nodeName, - ccs: null, - }, - ]; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - // @ts-ignore - Date = FakeDate; - (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { - return stat; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new ThreadPoolSearchRejectionsRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - ccs: null, - cluster: { clusterUuid, clusterName }, - nodeId, - nodeName, - itemLabel: undefined, - meta: { - rejectionCount, - clusterUuid, - type: threadPoolType, - nodeId, - nodeName, - ccs: null, - }, - ui: { - isFiring: true, - message: { - text: `Node #start_link${nodeName}#end_link is reporting ${rejectionCount} ${threadPoolType} rejections at #absolute`, - nextSteps: [ - { - text: '#start_linkMonitor this node#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'elasticsearch/nodes/esNode1/advanced', - }, - ], - }, - { - text: '#start_linkOptimize complex queries#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries', - }, - ], - }, - { - text: '#start_linkAdd more nodes#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', - }, - ], - }, - { - text: '#start_linkResize your deployment (ECE)#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', - }, - ], - }, - { - text: '#start_linkThread pool settings#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', - }, - ], - }, - ], - tokens: [ - { - startToken: '#absolute', - type: 'time', - isAbsolute: true, - isRelative: false, - timestamp: 1, - }, - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: `elasticsearch/nodes/${nodeId}`, - }, - ], - }, - severity: 'danger', - triggeredMS: 1, - lastCheckedMS: 0, - }, - }, - ], - }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, - node: `${nodeName}`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, - clusterName, - count: 1, - threadPoolType, - state: 'firing', - }); - }); - it('should not fire actions if under threshold', async () => { - (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat[0], - rejectionCount: 1, - }, - ]; - }); - const rule = new ThreadPoolSearchRejectionsRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [], - }); - expect(scheduleActions).not.toHaveBeenCalled(); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat[0], - ccs, - }, - ]; - }); - const rule = new ThreadPoolSearchRejectionsRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, - internalShortMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, - node: `${nodeName}`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/esNode1?_g=(cluster_uuid:abc123,ccs:testCluster))`, - actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, - clusterName, - count, - state: 'firing', - threadPoolType, - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.test.ts b/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.test.ts deleted file mode 100644 index b321f687e0672..0000000000000 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.test.ts +++ /dev/null @@ -1,297 +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 { ThreadPoolWriteRejectionsRule } from './thread_pool_write_rejections_rule'; -import { RULE_THREAD_POOL_WRITE_REJECTIONS } from '../../common/constants'; -import { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats'; -import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; - -const RealDate = Date; - -jest.mock('../lib/alerts/fetch_thread_pool_rejections_stats', () => ({ - fetchThreadPoolRejectionStats: jest.fn(), -})); -jest.mock('../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn(), -})); - -jest.mock('../static_globals', () => ({ - Globals: { - app: { - getLogger: () => ({ debug: jest.fn() }), - url: 'http://localhost:5601', - config: { - ui: { - show_license_expiration: true, - ccs: { enabled: true }, - container: { elasticsearch: { enabled: false } }, - }, - }, - }, - }, -})); - -describe('ThreadpoolWriteRejectionsAlert', () => { - it('should have defaults', () => { - const rule = new ThreadPoolWriteRejectionsRule(); - expect(rule.ruleOptions.id).toBe(RULE_THREAD_POOL_WRITE_REJECTIONS); - expect(rule.ruleOptions.name).toBe(`Thread pool write rejections`); - expect(rule.ruleOptions.throttle).toBe('1d'); - expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 300, duration: '5m' }); - expect(rule.ruleOptions.actionVariables).toStrictEqual([ - { name: 'node', description: 'The node reporting high thread pool write rejections.' }, - { - name: 'internalShortMessage', - description: 'The short internal message generated by Elastic.', - }, - { - name: 'internalFullMessage', - description: 'The full internal message generated by Elastic.', - }, - { name: 'state', description: 'The current state of the alert.' }, - { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, - { name: 'action', description: 'The recommended action for this alert.' }, - { - name: 'actionPlain', - description: 'The recommended action for this alert, without any markdown.', - }, - ]); - }); - describe('execute', () => { - function FakeDate() {} - FakeDate.prototype.valueOf = () => 1; - - const clusterUuid = 'abc123'; - const clusterName = 'testCluster'; - const nodeId = 'esNode1'; - const nodeName = 'esName1'; - const threadPoolType = 'write'; - const rejectionCount = 400; - const stat = [ - { - rejectionCount, - type: threadPoolType, - clusterUuid, - nodeId, - nodeName, - ccs: null, - }, - ]; - - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; - - beforeEach(() => { - // @ts-ignore - Date = FakeDate; - (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { - return stat; - }); - (fetchClusters as jest.Mock).mockImplementation(() => { - return [{ clusterUuid, clusterName }]; - }); - }); - - afterEach(() => { - Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); - }); - - it('should fire actions', async () => { - const rule = new ThreadPoolWriteRejectionsRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - ccs: null, - cluster: { clusterUuid, clusterName }, - nodeId, - nodeName, - itemLabel: undefined, - meta: { - rejectionCount, - clusterUuid, - type: threadPoolType, - nodeId, - nodeName, - ccs: null, - }, - ui: { - isFiring: true, - message: { - text: `Node #start_link${nodeName}#end_link is reporting ${rejectionCount} ${threadPoolType} rejections at #absolute`, - nextSteps: [ - { - text: '#start_linkMonitor this node#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'elasticsearch/nodes/esNode1/advanced', - }, - ], - }, - { - text: '#start_linkOptimize complex queries#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries', - }, - ], - }, - { - text: '#start_linkAdd more nodes#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', - }, - ], - }, - { - text: '#start_linkResize your deployment (ECE)#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', - }, - ], - }, - { - text: '#start_linkThread pool settings#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'docLink', - partialUrl: - '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', - }, - ], - }, - ], - tokens: [ - { - startToken: '#absolute', - type: 'time', - isAbsolute: true, - isRelative: false, - timestamp: 1, - }, - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: `elasticsearch/nodes/${nodeId}`, - }, - ], - }, - severity: 'danger', - triggeredMS: 1, - lastCheckedMS: 0, - }, - }, - ], - }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, - node: `${nodeName}`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, - clusterName, - count: 1, - threadPoolType, - state: 'firing', - }); - }); - it('should not fire actions if under threshold', async () => { - (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat[0], - rejectionCount: 1, - }, - ]; - }); - const rule = new ThreadPoolWriteRejectionsRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [], - }); - expect(scheduleActions).not.toHaveBeenCalled(); - }); - - it('should handle ccs', async () => { - const ccs = 'testCluster'; - (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { - return [ - { - ...stat[0], - ccs, - }, - ]; - }); - const rule = new ThreadPoolWriteRejectionsRule(); - const type = rule.getRuleType(); - await type.executor({ - ...executorOptions, - params: rule.ruleOptions.defaultParams, - } as any); - const count = 1; - expect(scheduleActions).toHaveBeenCalledWith('default', { - internalFullMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, - internalShortMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, - node: `${nodeName}`, - action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/esNode1?_g=(cluster_uuid:abc123,ccs:testCluster))`, - actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, - clusterName, - count, - state: 'firing', - threadPoolType, - }); - }); - }); -}); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_status.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_status.ts index 9a0830ab5a1a7..9fca196cf8d98 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_status.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_status.ts @@ -7,7 +7,7 @@ import { RulesClient } from '@kbn/alerting-plugin/server'; import { AlertInstanceState } from '../../../common/types/alerts'; -import { AlertsFactory } from '../../alerts'; +import { RulesFactory } from '../../rules'; import { CommonAlertState, CommonAlertFilter, RulesByType } from '../../../common/types/alerts'; import { RULES } from '../../../common/constants'; @@ -18,7 +18,7 @@ export async function fetchStatus( filters: CommonAlertFilter[] = [] ): Promise { const rulesByType = await Promise.all( - (alertTypes || RULES).map(async (type) => AlertsFactory.getByType(type, rulesClient)) + (alertTypes || RULES).map(async (type) => RulesFactory.getByType(type, rulesClient)) ); if (!rulesByType.length) return {}; diff --git a/x-pack/plugins/monitoring/server/plugin.test.ts b/x-pack/plugins/monitoring/server/plugin.test.ts index 188f1415e69fb..92ea7cf3295d3 100644 --- a/x-pack/plugins/monitoring/server/plugin.test.ts +++ b/x-pack/plugins/monitoring/server/plugin.test.ts @@ -7,7 +7,7 @@ import { coreMock } from '@kbn/core/server/mocks'; import { MonitoringPlugin } from './plugin'; -import { AlertsFactory } from './alerts'; +import { RulesFactory } from './rules'; jest.mock('./es_client/instantiate_client', () => ({ instantiateClient: jest.fn().mockImplementation(() => ({ @@ -71,10 +71,10 @@ describe('Monitoring plugin', () => { expect(plugin['bulkUploader']).not.toBeUndefined(); }); - it('should register all alerts', async () => { - const alerts = AlertsFactory.getAll(); + it('should register all rules', async () => { + const rules = RulesFactory.getAll(); const plugin = new MonitoringPlugin(initializerContext as any); await plugin.setup(coreSetup as any, setupPlugins as any); - expect(setupPlugins.alerting.registerType).toHaveBeenCalledTimes(alerts.length); + expect(setupPlugins.alerting.registerType).toHaveBeenCalledTimes(rules.length); }); }); diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 1747855112964..99cc38e44c0e4 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -30,7 +30,7 @@ import { LOGGING_TAG, SAVED_OBJECT_TELEMETRY, } from '../common/constants'; -import { AlertsFactory } from './alerts'; +import { RulesFactory } from './rules'; import { configSchema, createConfig, MonitoringConfig } from './config'; import { instantiateClient } from './es_client/instantiate_client'; import { initBulkUploader } from './kibana_monitoring'; @@ -123,9 +123,9 @@ export class MonitoringPlugin setupPlugins: this.setupPlugins!, }); - const alerts = AlertsFactory.getAll(); - for (const alert of alerts) { - plugins.alerting?.registerType(alert.getRuleType()); + const rules = RulesFactory.getAll(); + for (const rule of rules) { + plugins.alerting?.registerType(rule.getRuleType()); } const config = createConfig(this.initializerContext.config.get>()); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts index dad3f7c16c010..326033e61f1c0 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts @@ -8,7 +8,7 @@ import { ActionResult } from '@kbn/actions-plugin/server'; import { RuleTypeParams, SanitizedRule } from '@kbn/alerting-plugin/common'; import { ALERT_ACTION_TYPE_LOG } from '../../../../../common/constants'; -import { AlertsFactory } from '../../../../alerts'; +import { RulesFactory } from '../../../../rules'; import { handleError } from '../../../../lib/errors'; import { MonitoringCore, RouteDependencies } from '../../../../types'; @@ -26,7 +26,7 @@ export function enableAlertsRoute(server: MonitoringCore, npRoute: RouteDependen const infraContext = await context.infra; const actionContext = await context.actions; - const alerts = AlertsFactory.getAll(); + const alerts = RulesFactory.getAll(); if (alerts.length) { const { isSufficientlySecure, hasPermanentEncryptionKey } = npRoute.alerting ?.getSecurityHealth diff --git a/x-pack/plugins/monitoring/server/alerts/alert_helpers.ts b/x-pack/plugins/monitoring/server/rules/alert_helpers.ts similarity index 100% rename from x-pack/plugins/monitoring/server/alerts/alert_helpers.ts rename to x-pack/plugins/monitoring/server/rules/alert_helpers.ts diff --git a/x-pack/plugins/monitoring/server/alerts/base_rule.test.ts b/x-pack/plugins/monitoring/server/rules/base_rule.test.ts similarity index 100% rename from x-pack/plugins/monitoring/server/alerts/base_rule.test.ts rename to x-pack/plugins/monitoring/server/rules/base_rule.test.ts diff --git a/x-pack/plugins/monitoring/server/alerts/base_rule.ts b/x-pack/plugins/monitoring/server/rules/base_rule.ts similarity index 84% rename from x-pack/plugins/monitoring/server/alerts/base_rule.ts rename to x-pack/plugins/monitoring/server/rules/base_rule.ts index 609d4a2182148..b457185704b76 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/base_rule.ts @@ -7,15 +7,23 @@ import { Logger, ElasticsearchClient, DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; import { RuleType, RuleNotifyWhen, RuleExecutorOptions, - Alert, RulesClient, RuleExecutorServices, + DEFAULT_AAD_CONFIG, + AlertsClientError, } from '@kbn/alerting-plugin/server'; -import { Rule, RuleTypeParams, RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { + Rule, + RuleTypeParams, + RawAlertInstance, + SanitizedRule, + AlertInstanceContext, +} from '@kbn/alerting-plugin/common'; import { ActionsClient } from '@kbn/actions-plugin/server'; import { parseDuration } from '@kbn/alerting-plugin/common'; import { @@ -78,7 +86,16 @@ export class BaseRule { this.scopedLogger = Globals.app.getLogger(ruleOptions.id); } - public getRuleType(): RuleType { + public getRuleType(): RuleType< + never, + never, + ExecutedState, + AlertInstanceState, + AlertInstanceContext, + 'default', + never, + DefaultAlert + > { const { id, name, actionVariables } = this.ruleOptions; return { id, @@ -95,15 +112,21 @@ export class BaseRule { minimumLicenseRequired: 'basic', isExportable: false, executor: ( - options: RuleExecutorOptions & { - state: ExecutedState; - } + options: RuleExecutorOptions< + never, + ExecutedState, + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + > ): Promise => this.execute(options), category: DEFAULT_APP_CATEGORIES.management.id, producer: 'monitoring', actionVariables: { context: actionVariables, }, + alerts: DEFAULT_AAD_CONFIG, // As there is "[key: string]: unknown;" in CommonAlertParams, // we couldn't figure out a schema for validation and created a follow on issue: // https://github.com/elastic/kibana/issues/153754 @@ -230,13 +253,23 @@ export class BaseRule { services, params, state, - }: RuleExecutorOptions & { - state: ExecutedState; - }): Promise { + }: RuleExecutorOptions< + never, + ExecutedState, + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >): Promise { this.scopedLogger.debug( `Executing alert with params: ${JSON.stringify(params)} and state: ${JSON.stringify(state)}` ); + const { alertsClient } = services; + if (!alertsClient) { + throw new AlertsClientError(); + } + const esClient = services.scopedClusterClient.asCurrentUser; const clusters = await this.fetchClusters(esClient, params as CommonAlertParams); const data = await this.fetchData(params, esClient, clusters); @@ -270,7 +303,12 @@ export class BaseRule { protected async processData( data: AlertData[], clusters: AlertCluster[], - services: RuleExecutorServices, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, state: ExecutedState ) { const currentUTC = +new Date(); @@ -287,9 +325,6 @@ export class BaseRule { for (const node of nodes) { const newAlertStates: AlertNodeState[] = []; // quick fix for now so that non node level alerts will use the cluster id - const instance = services.alertFactory.create( - node.meta.nodeId || node.meta.instanceId || cluster.clusterUuid - ); if (node.shouldFire) { const { meta } = node; @@ -309,13 +344,19 @@ export class BaseRule { nodeState.ui.message = this.getUiMessage(nodeState, node); // store the state of each node in array. newAlertStates.push(nodeState); - } - const alertInstanceState = { alertStates: newAlertStates }; - // update the alert's state with the new node states - instance.replaceState(alertInstanceState); - if (newAlertStates.length) { - this.executeActions(instance, alertInstanceState, null, cluster); - state.lastExecutedAction = currentUTC; + + const alertInstanceState = { alertStates: newAlertStates }; + // update the alert's state with the new node states + if (newAlertStates.length) { + const alertId = node.meta.nodeId || node.meta.instanceId || cluster.clusterUuid; + services.alertsClient?.report({ + id: alertId, + actionGroup: 'default', + state: alertInstanceState, + }); + this.executeActions(services, alertId, alertInstanceState, null, cluster); + state.lastExecutedAction = currentUTC; + } } } } @@ -346,8 +387,14 @@ export class BaseRule { } protected executeActions( - instance: Alert, - instanceState: AlertInstanceState | AlertState | unknown, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, + alertState: AlertInstanceState | AlertState | unknown, item: AlertData | unknown, cluster?: AlertCluster | unknown ) { diff --git a/x-pack/plugins/monitoring/server/rules/ccr_read_exceptions_rule.test.ts b/x-pack/plugins/monitoring/server/rules/ccr_read_exceptions_rule.test.ts new file mode 100644 index 0000000000000..806c382cb3707 --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/ccr_read_exceptions_rule.test.ts @@ -0,0 +1,473 @@ +/* + * 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 { CCRReadExceptionsRule } from './ccr_read_exceptions_rule'; +import { RULE_CCR_READ_EXCEPTIONS } from '../../common/constants'; +import { fetchCCRReadExceptions } from '../lib/alerts/fetch_ccr_read_exceptions'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +type ICCRReadExceptionsRuleMock = CCRReadExceptionsRule & { + defaultParams: { + duration: string; + }; +} & { + actionVariables: Array<{ + name: string; + description: string; + }>; +}; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_ccr_read_exceptions', () => ({ + fetchCCRReadExceptions: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); + +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('CCRReadExceptionsRule', () => { + it('should have defaults', () => { + const rule = new CCRReadExceptionsRule() as ICCRReadExceptionsRuleMock; + expect(rule.ruleOptions.id).toBe(RULE_CCR_READ_EXCEPTIONS); + expect(rule.ruleOptions.name).toBe('CCR read exceptions'); + expect(rule.ruleOptions.throttle).toBe('6h'); + expect(rule.ruleOptions.defaultParams).toStrictEqual({ + duration: '1h', + }); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { + name: 'remoteCluster', + description: 'The remote cluster experiencing CCR read exceptions.', + }, + { + name: 'followerIndex', + description: 'The follower index reporting CCR read exceptions.', + }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + describe('execute', () => { + const FakeDate = function () {}; + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const nodeId = 'myNodeId'; + const nodeName = 'myNodeName'; + const remoteCluster = 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1'; + const followerIndex = '.follower_index_1'; + const leaderIndex = '.leader_index_1'; + const readExceptions = [ + { + exception: { + type: 'read_exceptions_type_1', + reason: 'read_exceptions_reason_1', + }, + }, + ]; + const stat = { + remoteCluster, + followerIndex, + leaderIndex, + read_exceptions: readExceptions, + clusterUuid, + nodeId, + nodeName, + }; + + const services = alertsMock.createRuleExecutorServices(); + + const executorOptions = { + services, + state: {}, + }; + + beforeEach(() => { + Date = FakeDate as DateConstructor; + (fetchCCRReadExceptions as jest.Mock).mockImplementation(() => { + return [stat]; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new CCRReadExceptionsRule() as ICCRReadExceptionsRuleMock; + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + actionGroup: 'default', + id: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + state: { + alertStates: [ + { + ccs: undefined, + cluster: { clusterName: 'testCluster', clusterUuid: 'abc123' }, + itemLabel: '.follower_index_1', + meta: { + followerIndex: '.follower_index_1', + instanceId: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + itemLabel: '.follower_index_1', + lastReadException: undefined, + leaderIndex: '.leader_index_1', + remoteCluster: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1', + shardId: undefined, + }, + nodeId: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + nodeName: '.follower_index_1', + ui: { + isFiring: true, + lastCheckedMS: 0, + message: { + code: undefined, + nextSteps: [ + { + text: '#start_linkIdentify CCR usage/stats#end_link', + tokens: [ + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/ccr', + }, + ], + }, + { + text: '#start_linkManage CCR follower indices#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{basePath}management/data/cross_cluster_replication/follower_indices', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkCreate auto-follow patterns#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{basePath}management/data/cross_cluster_replication/auto_follow_patterns', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkAdd follower index API (Docs)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/ccr-put-follow.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkCross-cluster replication (Docs)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/xpack-ccr.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkBi-directional replication (Blog)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}blog/bi-directional-replication-with-elasticsearch-cross-cluster-replication-ccr', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkFollow the Leader (Blog)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}blog/follow-the-leader-an-introduction-to-cross-cluster-replication-in-elasticsearch', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + ], + text: 'Follower index #start_link.follower_index_1#end_link is reporting CCR read exceptions on remote cluster: BcK-0pmsQniyPQfZuauuXw_remote_cluster_1 at #absolute', + tokens: [ + { + isAbsolute: true, + isRelative: false, + startToken: '#absolute', + timestamp: 1, + type: 'time', + }, + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/ccr/.follower_index_1/shard/undefined', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + context: { + internalFullMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Current 'follower_index' index affected: ${followerIndex}. [View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Verify follower and leader index relationships on the affected remote cluster.`, + action: `[View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: + 'Verify follower and leader index relationships on the affected remote cluster.', + clusterName, + state: 'firing', + remoteCluster, + remoteClusters: remoteCluster, + followerIndex, + followerIndices: followerIndex, + }, + payload: { + [ALERT_REASON]: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Verify follower and leader index relationships on the affected remote cluster.`, + }, + }); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchCCRReadExceptions as jest.Mock).mockImplementation(() => { + return [ + { + ...stat, + ccs, + }, + ]; + }); + const rule = new CCRReadExceptionsRule() as ICCRReadExceptionsRuleMock; + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + actionGroup: 'default', + id: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { clusterName: 'testCluster', clusterUuid: 'abc123' }, + itemLabel: '.follower_index_1', + meta: { + followerIndex: '.follower_index_1', + instanceId: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + itemLabel: '.follower_index_1', + lastReadException: undefined, + leaderIndex: '.leader_index_1', + remoteCluster: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1', + shardId: undefined, + }, + nodeId: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + nodeName: '.follower_index_1', + ui: { + isFiring: true, + lastCheckedMS: 0, + message: { + code: undefined, + nextSteps: [ + { + text: '#start_linkIdentify CCR usage/stats#end_link', + tokens: [ + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/ccr', + }, + ], + }, + { + text: '#start_linkManage CCR follower indices#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{basePath}management/data/cross_cluster_replication/follower_indices', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkCreate auto-follow patterns#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{basePath}management/data/cross_cluster_replication/auto_follow_patterns', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkAdd follower index API (Docs)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/ccr-put-follow.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkCross-cluster replication (Docs)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/xpack-ccr.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkBi-directional replication (Blog)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}blog/bi-directional-replication-with-elasticsearch-cross-cluster-replication-ccr', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkFollow the Leader (Blog)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}blog/follow-the-leader-an-introduction-to-cross-cluster-replication-in-elasticsearch', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + ], + text: 'Follower index #start_link.follower_index_1#end_link is reporting CCR read exceptions on remote cluster: BcK-0pmsQniyPQfZuauuXw_remote_cluster_1 at #absolute', + tokens: [ + { + isAbsolute: true, + isRelative: false, + startToken: '#absolute', + timestamp: 1, + type: 'time', + }, + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/ccr/.follower_index_1/shard/undefined', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'BcK-0pmsQniyPQfZuauuXw_remote_cluster_1:.follower_index_1', + context: { + internalFullMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Current 'follower_index' index affected: ${followerIndex}. [View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, + internalShortMessage: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Verify follower and leader index relationships on the affected remote cluster.`, + action: `[View CCR stats](http://localhost:5601/app/monitoring#/elasticsearch/ccr?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, + actionPlain: + 'Verify follower and leader index relationships on the affected remote cluster.', + clusterName, + state: 'firing', + remoteCluster, + remoteClusters: remoteCluster, + followerIndex, + followerIndices: followerIndex, + }, + payload: { + [ALERT_REASON]: `CCR read exceptions alert is firing for the following remote cluster: ${remoteCluster}. Verify follower and leader index relationships on the affected remote cluster.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts b/x-pack/plugins/monitoring/server/rules/ccr_read_exceptions_rule.ts similarity index 90% rename from x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts rename to x-pack/plugins/monitoring/server/rules/ccr_read_exceptions_rule.ts index 1c1bfe7bf3018..70ddc7a498fd2 100644 --- a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/ccr_read_exceptions_rule.ts @@ -7,9 +7,11 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; import { parseDuration } from '@kbn/alerting-plugin/common/parse_duration'; -import { SanitizedRule, RawAlertInstance } from '@kbn/alerting-plugin/common'; +import { SanitizedRule, RawAlertInstance, AlertInstanceContext } from '@kbn/alerting-plugin/common'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -209,7 +211,13 @@ export class CCRReadExceptionsRule extends BaseRule { } protected executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -261,21 +269,27 @@ export class CCRReadExceptionsRule extends BaseRule { } ); - instance.scheduleActions('default', { - internalShortMessage, - internalFullMessage, - state: AlertingDefaults.ALERT_STATE.firing, - remoteCluster, - followerIndex, - /* continue to send "remoteClusters" and "followerIndices" values for users still using it though + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage, + state: AlertingDefaults.ALERT_STATE.firing, + remoteCluster, + followerIndex, + /* continue to send "remoteClusters" and "followerIndices" values for users still using it though we have replaced it with "remoteCluster" and "followerIndex" in the template due to alerts per index instead of all indices see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ - remoteClusters: remoteCluster, - followerIndices: followerIndex, - clusterName: cluster.clusterName, - action, - actionPlain: shortActionText, + remoteClusters: remoteCluster, + followerIndices: followerIndex, + clusterName: cluster.clusterName, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.test.ts b/x-pack/plugins/monitoring/server/rules/cluster_health_rule.test.ts similarity index 56% rename from x-pack/plugins/monitoring/server/alerts/cluster_health_rule.test.ts rename to x-pack/plugins/monitoring/server/rules/cluster_health_rule.test.ts index d67f10613607a..fe1d8562b7ed4 100644 --- a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.test.ts +++ b/x-pack/plugins/monitoring/server/rules/cluster_health_rule.test.ts @@ -10,7 +10,8 @@ import { RULE_CLUSTER_HEALTH } from '../../common/constants'; import { AlertClusterHealthType, AlertSeverity } from '../../common/enums'; import { fetchClusterHealth } from '../lib/alerts/fetch_cluster_health'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; const RealDate = Date; @@ -75,24 +76,8 @@ describe('ClusterHealthRule', () => { }, ]; - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; beforeEach(() => { // @ts-ignore @@ -107,66 +92,77 @@ describe('ClusterHealthRule', () => { afterEach(() => { Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); + jest.resetAllMocks(); }); - it('should fire actions', async () => { + it('should fire action', async () => { const rule = new ClusterHealthRule(); const type = rule.getRuleType(); await type.executor({ ...executorOptions, params: {}, } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, - ccs, - itemLabel: undefined, - nodeId: undefined, - nodeName: undefined, - meta: { + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, ccs, - clusterUuid, - health: AlertClusterHealthType.Yellow, - }, - ui: { - isFiring: true, - message: { - text: 'Elasticsearch cluster health is yellow.', - nextSteps: [ - { - text: 'Allocate missing replica shards. #start_linkView now#end_link', - tokens: [ - { - startToken: '#start_link', - endToken: '#end_link', - type: 'link', - url: 'elasticsearch/indices', - }, - ], - }, - ], + itemLabel: undefined, + nodeId: undefined, + nodeName: undefined, + meta: { + ccs, + clusterUuid, + health: AlertClusterHealthType.Yellow, + }, + ui: { + isFiring: true, + message: { + text: 'Elasticsearch cluster health is yellow.', + nextSteps: [ + { + text: 'Allocate missing replica shards. #start_linkView now#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/indices', + }, + ], + }, + ], + }, + severity: AlertSeverity.Warning, + triggeredMS: 1, + lastCheckedMS: 0, }, - severity: AlertSeverity.Warning, - triggeredMS: 1, - lastCheckedMS: 0, }, - }, - ], + ], + }, }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - action: '[Allocate missing replica shards.](elasticsearch/indices)', - actionPlain: 'Allocate missing replica shards.', - internalFullMessage: - 'Cluster health alert is firing for testCluster. Current health is yellow. [Allocate missing replica shards.](elasticsearch/indices)', - internalShortMessage: - 'Cluster health alert is firing for testCluster. Current health is yellow. Allocate missing replica shards.', - clusterName, - clusterHealth: 'yellow', - state: 'firing', + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: '[Allocate missing replica shards.](elasticsearch/indices)', + actionPlain: 'Allocate missing replica shards.', + internalFullMessage: + 'Cluster health alert is firing for testCluster. Current health is yellow. [Allocate missing replica shards.](elasticsearch/indices)', + internalShortMessage: + 'Cluster health alert is firing for testCluster. Current health is yellow. Allocate missing replica shards.', + clusterName, + clusterHealth: 'yellow', + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'Cluster health alert is firing for testCluster. Current health is yellow. Allocate missing replica shards.', + }, }); }); @@ -186,8 +182,8 @@ describe('ClusterHealthRule', () => { ...executorOptions, params: {}, } as any); - expect(replaceState).not.toHaveBeenCalledWith({}); - expect(scheduleActions).not.toHaveBeenCalled(); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts b/x-pack/plugins/monitoring/server/rules/cluster_health_rule.ts similarity index 74% rename from x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts rename to x-pack/plugins/monitoring/server/rules/cluster_health_rule.ts index f93d182684560..f603be7f3b622 100644 --- a/x-pack/plugins/monitoring/server/alerts/cluster_health_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/cluster_health_rule.ts @@ -7,8 +7,10 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { AlertInstanceContext, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -115,8 +117,14 @@ export class ClusterHealthRule extends BaseRule { }; } - protected async executeActions( - instance: Alert, + protected executeActions( + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -139,34 +147,41 @@ export class ClusterHealthRule extends BaseRule { }); const action = `[${actionText}](elasticsearch/indices)`; - instance.scheduleActions('default', { - internalShortMessage: i18n.translate( - 'xpack.monitoring.alerts.clusterHealth.firing.internalShortMessage', - { - defaultMessage: `Cluster health alert is firing for {clusterName}. Current health is {health}. {actionText}`, - values: { - clusterName: cluster.clusterName, - health, - actionText, - }, - } - ), - internalFullMessage: i18n.translate( - 'xpack.monitoring.alerts.clusterHealth.firing.internalFullMessage', - { - defaultMessage: `Cluster health alert is firing for {clusterName}. Current health is {health}. {action}`, - values: { - clusterName: cluster.clusterName, - health, - action, - }, - } - ), - state: AlertingDefaults.ALERT_STATE.firing, - clusterHealth: health, - clusterName: cluster.clusterName, - action, - actionPlain: actionText, + const internalShortMessage = i18n.translate( + 'xpack.monitoring.alerts.clusterHealth.firing.internalShortMessage', + { + defaultMessage: `Cluster health alert is firing for {clusterName}. Current health is {health}. {actionText}`, + values: { + clusterName: cluster.clusterName, + health, + actionText, + }, + } + ); + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: i18n.translate( + 'xpack.monitoring.alerts.clusterHealth.firing.internalFullMessage', + { + defaultMessage: `Cluster health alert is firing for {clusterName}. Current health is {health}. {action}`, + values: { + clusterName: cluster.clusterName, + health, + action, + }, + } + ), + state: AlertingDefaults.ALERT_STATE.firing, + clusterHealth: health, + clusterName: cluster.clusterName, + action, + actionPlain: actionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/rules/cpu_usage_rule.test.ts b/x-pack/plugins/monitoring/server/rules/cpu_usage_rule.test.ts new file mode 100644 index 0000000000000..1b107d4031981 --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/cpu_usage_rule.test.ts @@ -0,0 +1,334 @@ +/* + * 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 { CpuUsageRule } from './cpu_usage_rule'; +import { RULE_CPU_USAGE } from '../../common/constants'; +import { fetchCpuUsageNodeStats } from '../lib/alerts/fetch_cpu_usage_node_stats'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_cpu_usage_node_stats', () => ({ + fetchCpuUsageNodeStats: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('CpuUsageRule', () => { + it('should have defaults', () => { + const rule = new CpuUsageRule(); + expect(rule.ruleOptions.id).toBe(RULE_CPU_USAGE); + expect(rule.ruleOptions.name).toBe('CPU Usage'); + expect(rule.ruleOptions.throttle).toBe('1d'); + expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 85, duration: '5m' }); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { name: 'node', description: 'The node reporting high cpu usage.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + + describe('execute', () => { + function FakeDate() {} + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const nodeId = 'myNodeId'; + const nodeName = 'myNodeName'; + const cpuUsage = 91; + const stat = { + clusterUuid, + nodeId, + nodeName, + cpuUsage, + }; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { + services, + state: {}, + }; + + beforeEach(() => { + // @ts-ignore + Date = FakeDate; + (fetchCpuUsageNodeStats as jest.Mock).mockImplementation(() => { + return [stat]; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new CpuUsageRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + actionGroup: 'default', + id: 'myNodeId', + state: { + alertStates: [ + { + ccs: undefined, + cluster: { clusterUuid, clusterName }, + cpuUsage, + itemLabel: undefined, + meta: { + clusterUuid, + cpuUsage, + nodeId, + nodeName, + }, + nodeId, + nodeName, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting cpu usage of ${cpuUsage}% at #absolute`, + nextSteps: [ + { + text: '#start_linkCheck hot threads#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/cluster-nodes-hot-threads.html', + }, + ], + }, + { + text: '#start_linkCheck long running tasks#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/tasks.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/myNodeId', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'myNodeId', + context: { + internalFullMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify CPU level of node.`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: 'Verify CPU level of node.', + clusterName, + count, + nodes: `${nodeName}:${cpuUsage}`, + node: `${nodeName}:${cpuUsage}`, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify CPU level of node.`, + }, + }); + }); + + it('should not fire actions if under threshold', async () => { + (fetchCpuUsageNodeStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat, + cpuUsage: 1, + }, + ]; + }); + const rule = new CpuUsageRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchCpuUsageNodeStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat, + ccs, + }, + ]; + }); + const rule = new CpuUsageRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + actionGroup: 'default', + id: 'myNodeId', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { clusterUuid, clusterName }, + cpuUsage, + itemLabel: undefined, + meta: { + ccs: 'testCluster', + clusterUuid, + cpuUsage, + nodeId, + nodeName, + }, + nodeId, + nodeName, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting cpu usage of ${cpuUsage}% at #absolute`, + nextSteps: [ + { + text: '#start_linkCheck hot threads#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/cluster-nodes-hot-threads.html', + }, + ], + }, + { + text: '#start_linkCheck long running tasks#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/tasks.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/myNodeId', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'myNodeId', + context: { + internalFullMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, + internalShortMessage: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify CPU level of node.`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, + actionPlain: 'Verify CPU level of node.', + clusterName, + count, + nodes: `${nodeName}:${cpuUsage}`, + node: `${nodeName}:${cpuUsage}`, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `CPU usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify CPU level of node.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts b/x-pack/plugins/monitoring/server/rules/cpu_usage_rule.ts similarity index 83% rename from x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts rename to x-pack/plugins/monitoring/server/rules/cpu_usage_rule.ts index 92c45c9e61ae2..be8aad8bf01a4 100644 --- a/x-pack/plugins/monitoring/server/alerts/cpu_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/cpu_usage_rule.ts @@ -8,9 +8,11 @@ import { i18n } from '@kbn/i18n'; import numeral from '@elastic/numeral'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { AlertInstanceContext, RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; import { parseDuration } from '@kbn/alerting-plugin/common/parse_duration'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -144,7 +146,13 @@ export class CpuUsageRule extends BaseRule { } protected executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -191,19 +199,25 @@ export class CpuUsageRule extends BaseRule { }, } ); - instance.scheduleActions('default', { - internalShortMessage, - internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, - state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 - see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 - */ - nodes: `${firingNode.nodeName}:${firingNode.cpuUsage}`, - count: 1, - node: `${firingNode.nodeName}:${firingNode.cpuUsage}`, - clusterName: cluster.clusterName, - action, - actionPlain: shortActionText, + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, + state: AlertingDefaults.ALERT_STATE.firing, + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 + */ + nodes: `${firingNode.nodeName}:${firingNode.cpuUsage}`, + count: 1, + node: `${firingNode.nodeName}:${firingNode.cpuUsage}`, + clusterName: cluster.clusterName, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/rules/disk_usage_rule.test.ts b/x-pack/plugins/monitoring/server/rules/disk_usage_rule.test.ts new file mode 100644 index 0000000000000..5e1c30dce78f6 --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/disk_usage_rule.test.ts @@ -0,0 +1,400 @@ +/* + * 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 { DiskUsageRule } from './disk_usage_rule'; +import { RULE_DISK_USAGE } from '../../common/constants'; +import { fetchDiskUsageNodeStats } from '../lib/alerts/fetch_disk_usage_node_stats'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +type IDiskUsageAlertMock = DiskUsageRule & { + defaultParams: { + threshold: number; + duration: string; + }; +} & { + actionVariables: Array<{ + name: string; + description: string; + }>; +}; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_disk_usage_node_stats', () => ({ + fetchDiskUsageNodeStats: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); + +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('DiskUsageRule', () => { + it('should have defaults', () => { + const alert = new DiskUsageRule() as IDiskUsageAlertMock; + expect(alert.ruleOptions.id).toBe(RULE_DISK_USAGE); + expect(alert.ruleOptions.name).toBe('Disk Usage'); + expect(alert.ruleOptions.throttle).toBe('1d'); + expect(alert.ruleOptions.defaultParams).toStrictEqual({ threshold: 80, duration: '5m' }); + expect(alert.ruleOptions.actionVariables).toStrictEqual([ + { name: 'node', description: 'The node reporting high disk usage.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + + describe('execute', () => { + const FakeDate = function () {}; + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const nodeId = 'myNodeId'; + const nodeName = 'myNodeName'; + const diskUsage = 91; + const stat = { + clusterUuid, + nodeId, + nodeName, + diskUsage, + }; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; + + beforeEach(() => { + Date = FakeDate as DateConstructor; + (fetchDiskUsageNodeStats as jest.Mock).mockImplementation(() => { + return [stat]; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new DiskUsageRule() as IDiskUsageAlertMock; + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'myNodeId', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: undefined, + cluster: { + clusterName: 'testCluster', + clusterUuid: 'abc123', + }, + diskUsage: 91, + itemLabel: undefined, + meta: { + clusterUuid: 'abc123', + diskUsage: 91, + nodeId: 'myNodeId', + nodeName: 'myNodeName', + }, + nodeId: 'myNodeId', + nodeName: 'myNodeName', + ui: { + isFiring: true, + lastCheckedMS: 0, + message: { + nextSteps: [ + { + text: '#start_linkTune for disk usage#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/tune-for-disk-usage.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkIdentify large indices#end_link', + tokens: [ + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/indices', + }, + ], + }, + { + text: '#start_linkImplement ILM policies#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/index-lifecycle-management.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkAdd more data nodes#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + ], + text: 'Node #start_linkmyNodeName#end_link is reporting disk usage of 91% at #absolute', + tokens: [ + { + isAbsolute: true, + isRelative: false, + startToken: '#absolute', + timestamp: 1, + type: 'time', + }, + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/nodes/myNodeId', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'myNodeId', + context: { + internalFullMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify disk usage level of node.`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: 'Verify disk usage level of node.', + clusterName, + count, + nodes: `${nodeName}:${diskUsage}`, + node: `${nodeName}:${diskUsage}`, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify disk usage level of node.`, + }, + }); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchDiskUsageNodeStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat, + ccs, + }, + ]; + }); + const rule = new DiskUsageRule() as IDiskUsageAlertMock; + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'myNodeId', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { + clusterName: 'testCluster', + clusterUuid: 'abc123', + }, + diskUsage: 91, + itemLabel: undefined, + meta: { + ccs: 'testCluster', + clusterUuid: 'abc123', + diskUsage: 91, + nodeId: 'myNodeId', + nodeName: 'myNodeName', + }, + nodeId: 'myNodeId', + nodeName: 'myNodeName', + ui: { + isFiring: true, + lastCheckedMS: 0, + message: { + nextSteps: [ + { + text: '#start_linkTune for disk usage#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/tune-for-disk-usage.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkIdentify large indices#end_link', + tokens: [ + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/indices', + }, + ], + }, + { + text: '#start_linkImplement ILM policies#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/index-lifecycle-management.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkAdd more data nodes#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + ], + text: 'Node #start_linkmyNodeName#end_link is reporting disk usage of 91% at #absolute', + tokens: [ + { + isAbsolute: true, + isRelative: false, + startToken: '#absolute', + timestamp: 1, + type: 'time', + }, + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/nodes/myNodeId', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'myNodeId', + context: { + internalFullMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, + internalShortMessage: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify disk usage level of node.`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/myNodeId?_g=(cluster_uuid:abc123,ccs:testCluster))`, + actionPlain: 'Verify disk usage level of node.', + clusterName, + count, + nodes: `${nodeName}:${diskUsage}`, + node: `${nodeName}:${diskUsage}`, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `Disk usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify disk usage level of node.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts b/x-pack/plugins/monitoring/server/rules/disk_usage_rule.ts similarity index 86% rename from x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts rename to x-pack/plugins/monitoring/server/rules/disk_usage_rule.ts index 77a5e0e8bd5bc..a57de61e9bd66 100644 --- a/x-pack/plugins/monitoring/server/alerts/disk_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/disk_usage_rule.ts @@ -8,8 +8,10 @@ import { i18n } from '@kbn/i18n'; import numeral from '@elastic/numeral'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { AlertInstanceContext, RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -151,7 +153,13 @@ export class DiskUsageRule extends BaseRule { } protected executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -200,19 +208,25 @@ export class DiskUsageRule extends BaseRule { } ); - instance.scheduleActions('default', { - internalShortMessage, - internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, - state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, + state: AlertingDefaults.ALERT_STATE.firing, + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ - nodes: `${firingNode.nodeName}:${firingNode.diskUsage}`, - count: 1, - node: `${firingNode.nodeName}:${firingNode.diskUsage}`, - clusterName: cluster.clusterName, - action, - actionPlain: shortActionText, + nodes: `${firingNode.nodeName}:${firingNode.diskUsage}`, + count: 1, + node: `${firingNode.nodeName}:${firingNode.diskUsage}`, + clusterName: cluster.clusterName, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.test.ts b/x-pack/plugins/monitoring/server/rules/elasticsearch_version_mismatch_rule.test.ts similarity index 61% rename from x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.test.ts rename to x-pack/plugins/monitoring/server/rules/elasticsearch_version_mismatch_rule.test.ts index 147f3435197a4..eafb51136fc73 100644 --- a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.test.ts +++ b/x-pack/plugins/monitoring/server/rules/elasticsearch_version_mismatch_rule.test.ts @@ -9,7 +9,8 @@ import { ElasticsearchVersionMismatchRule } from './elasticsearch_version_mismat import { RULE_ELASTICSEARCH_VERSION_MISMATCH } from '../../common/constants'; import { fetchElasticsearchVersions } from '../lib/alerts/fetch_elasticsearch_versions'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; const RealDate = Date; @@ -79,24 +80,8 @@ describe('ElasticsearchVersionMismatchAlert', () => { }, ]; - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; beforeEach(() => { // @ts-ignore @@ -111,52 +96,63 @@ describe('ElasticsearchVersionMismatchAlert', () => { afterEach(() => { Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); + jest.resetAllMocks(); }); - it('should fire actions', async () => { + it('should fire action', async () => { const rule = new ElasticsearchVersionMismatchRule(); const type = rule.getRuleType(); await type.executor({ ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, - ccs, - itemLabel: undefined, - nodeId: undefined, - nodeName: undefined, - meta: { + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, ccs, - clusterUuid, - versions: ['8.0.0', '7.2.1'], - }, - ui: { - isFiring: true, - message: { - text: 'Multiple versions of Elasticsearch (8.0.0, 7.2.1) running in this cluster.', + itemLabel: undefined, + nodeId: undefined, + nodeName: undefined, + meta: { + ccs, + clusterUuid, + versions: ['8.0.0', '7.2.1'], + }, + ui: { + isFiring: true, + message: { + text: 'Multiple versions of Elasticsearch (8.0.0, 7.2.1) running in this cluster.', + }, + severity: 'warning', + triggeredMS: 1, + lastCheckedMS: 0, }, - severity: 'warning', - triggeredMS: 1, - lastCheckedMS: 0, }, - }, - ], + ], + }, }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - action: `[View nodes](UNIT_TEST_URL/app/monitoring#/elasticsearch/nodes?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: 'Verify you have the same version across all nodes.', - internalFullMessage: `Elasticsearch version mismatch alert is firing for testCluster. Elasticsearch is running 8.0.0, 7.2.1. [View nodes](UNIT_TEST_URL/app/monitoring#/elasticsearch/nodes?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: - 'Elasticsearch version mismatch alert is firing for testCluster. Verify you have the same version across all nodes.', - versionList: ['8.0.0', '7.2.1'], - clusterName, - state: 'firing', + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: `[View nodes](UNIT_TEST_URL/app/monitoring#/elasticsearch/nodes?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: 'Verify you have the same version across all nodes.', + internalFullMessage: `Elasticsearch version mismatch alert is firing for testCluster. Elasticsearch is running 8.0.0, 7.2.1. [View nodes](UNIT_TEST_URL/app/monitoring#/elasticsearch/nodes?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: + 'Elasticsearch version mismatch alert is firing for testCluster. Verify you have the same version across all nodes.', + versionList: ['8.0.0', '7.2.1'], + clusterName, + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'Elasticsearch version mismatch alert is firing for testCluster. Verify you have the same version across all nodes.', + }, }); }); @@ -176,8 +172,8 @@ describe('ElasticsearchVersionMismatchAlert', () => { ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).not.toHaveBeenCalledWith({}); - expect(scheduleActions).not.toHaveBeenCalled(); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/rules/elasticsearch_version_mismatch_rule.ts similarity index 70% rename from x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts rename to x-pack/plugins/monitoring/server/rules/elasticsearch_version_mismatch_rule.ts index 77ad2dc5f3aa2..a2c4f4aa6687f 100644 --- a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/elasticsearch_version_mismatch_rule.ts @@ -7,8 +7,10 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { AlertInstanceContext, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -87,7 +89,13 @@ export class ElasticsearchVersionMismatchRule extends BaseRule { } protected async executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -118,33 +126,40 @@ export class ElasticsearchVersionMismatchRule extends BaseRule { state.ccs ); const action = `[${fullActionText}](${globalStateLink})`; - instance.scheduleActions('default', { - internalShortMessage: i18n.translate( - 'xpack.monitoring.alerts.elasticsearchVersionMismatch.firing.internalShortMessage', - { - defaultMessage: `Elasticsearch version mismatch alert is firing for {clusterName}. {shortActionText}`, - values: { - clusterName: cluster.clusterName, - shortActionText, - }, - } - ), - internalFullMessage: i18n.translate( - 'xpack.monitoring.alerts.elasticsearchVersionMismatch.firing.internalFullMessage', - { - defaultMessage: `Elasticsearch version mismatch alert is firing for {clusterName}. Elasticsearch is running {versions}. {action}`, - values: { - clusterName: cluster.clusterName, - versions: versions.join(', '), - action, - }, - } - ), - state: AlertingDefaults.ALERT_STATE.firing, - clusterName: cluster.clusterName, - versionList: versions, - action, - actionPlain: shortActionText, + const internalShortMessage = i18n.translate( + 'xpack.monitoring.alerts.elasticsearchVersionMismatch.firing.internalShortMessage', + { + defaultMessage: `Elasticsearch version mismatch alert is firing for {clusterName}. {shortActionText}`, + values: { + clusterName: cluster.clusterName, + shortActionText, + }, + } + ); + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: i18n.translate( + 'xpack.monitoring.alerts.elasticsearchVersionMismatch.firing.internalFullMessage', + { + defaultMessage: `Elasticsearch version mismatch alert is firing for {clusterName}. Elasticsearch is running {versions}. {action}`, + values: { + clusterName: cluster.clusterName, + versions: versions.join(', '), + action, + }, + } + ), + state: AlertingDefaults.ALERT_STATE.firing, + clusterName: cluster.clusterName, + versionList: versions, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/alerts/index.ts b/x-pack/plugins/monitoring/server/rules/index.ts similarity index 96% rename from x-pack/plugins/monitoring/server/alerts/index.ts rename to x-pack/plugins/monitoring/server/rules/index.ts index d5c59c802b681..2be1e70d5f15e 100644 --- a/x-pack/plugins/monitoring/server/alerts/index.ts +++ b/x-pack/plugins/monitoring/server/rules/index.ts @@ -20,4 +20,4 @@ export { NodesChangedRule } from './nodes_changed_rule'; export { ElasticsearchVersionMismatchRule } from './elasticsearch_version_mismatch_rule'; export { KibanaVersionMismatchRule } from './kibana_version_mismatch_rule'; export { LogstashVersionMismatchRule } from './logstash_version_mismatch_rule'; -export { AlertsFactory } from './alerts_factory'; +export { RulesFactory } from './rules_factory'; diff --git a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.test.ts b/x-pack/plugins/monitoring/server/rules/kibana_version_mismatch_rule.test.ts similarity index 60% rename from x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.test.ts rename to x-pack/plugins/monitoring/server/rules/kibana_version_mismatch_rule.test.ts index d7032597881a3..46b777dbee4a2 100644 --- a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.test.ts +++ b/x-pack/plugins/monitoring/server/rules/kibana_version_mismatch_rule.test.ts @@ -9,7 +9,8 @@ import { KibanaVersionMismatchRule } from './kibana_version_mismatch_rule'; import { RULE_KIBANA_VERSION_MISMATCH } from '../../common/constants'; import { fetchKibanaVersions } from '../lib/alerts/fetch_kibana_versions'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; const RealDate = Date; @@ -82,24 +83,8 @@ describe('KibanaVersionMismatchRule', () => { }, ]; - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; beforeEach(() => { // @ts-ignore @@ -114,52 +99,63 @@ describe('KibanaVersionMismatchRule', () => { afterEach(() => { Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); + jest.resetAllMocks(); }); - it('should fire actions', async () => { + it('should fire action', async () => { const rule = new KibanaVersionMismatchRule(); const type = rule.getRuleType(); await type.executor({ ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, - ccs, - itemLabel: undefined, - nodeId: undefined, - nodeName: undefined, - meta: { + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, ccs, - clusterUuid, - versions: ['8.0.0', '7.2.1'], - }, - ui: { - isFiring: true, - message: { - text: 'Multiple versions of Kibana (8.0.0, 7.2.1) running in this cluster.', + itemLabel: undefined, + nodeId: undefined, + nodeName: undefined, + meta: { + ccs, + clusterUuid, + versions: ['8.0.0', '7.2.1'], + }, + ui: { + isFiring: true, + message: { + text: 'Multiple versions of Kibana (8.0.0, 7.2.1) running in this cluster.', + }, + severity: 'warning', + triggeredMS: 1, + lastCheckedMS: 0, }, - severity: 'warning', - triggeredMS: 1, - lastCheckedMS: 0, }, - }, - ], + ], + }, }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - action: `[View instances](UNIT_TEST_URL/app/monitoring#/kibana/instances?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: 'Verify you have the same version across all instances.', - internalFullMessage: `Kibana version mismatch alert is firing for testCluster. Kibana is running 8.0.0, 7.2.1. [View instances](UNIT_TEST_URL/app/monitoring#/kibana/instances?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: - 'Kibana version mismatch alert is firing for testCluster. Verify you have the same version across all instances.', - versionList: ['8.0.0', '7.2.1'], - clusterName, - state: 'firing', + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: `[View instances](UNIT_TEST_URL/app/monitoring#/kibana/instances?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: 'Verify you have the same version across all instances.', + internalFullMessage: `Kibana version mismatch alert is firing for testCluster. Kibana is running 8.0.0, 7.2.1. [View instances](UNIT_TEST_URL/app/monitoring#/kibana/instances?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: + 'Kibana version mismatch alert is firing for testCluster. Verify you have the same version across all instances.', + versionList: ['8.0.0', '7.2.1'], + clusterName, + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'Kibana version mismatch alert is firing for testCluster. Verify you have the same version across all instances.', + }, }); }); @@ -179,8 +175,8 @@ describe('KibanaVersionMismatchRule', () => { ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).not.toHaveBeenCalledWith({}); - expect(scheduleActions).not.toHaveBeenCalled(); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/rules/kibana_version_mismatch_rule.ts similarity index 79% rename from x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts rename to x-pack/plugins/monitoring/server/rules/kibana_version_mismatch_rule.ts index ff7653dc59e85..559c27f69d46f 100644 --- a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/kibana_version_mismatch_rule.ts @@ -7,8 +7,10 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { AlertInstanceContext, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -97,7 +99,13 @@ export class KibanaVersionMismatchRule extends BaseRule { } protected async executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -128,6 +136,16 @@ export class KibanaVersionMismatchRule extends BaseRule { state.ccs ); const action = `[${fullActionText}](${globalStateLink})`; + const internalShortMessage = i18n.translate( + 'xpack.monitoring.alerts.kibanaVersionMismatch.firing.internalShortMessage', + { + defaultMessage: `Kibana version mismatch alert is firing for {clusterName}. {shortActionText}`, + values: { + clusterName: cluster.clusterName, + shortActionText, + }, + } + ); const internalFullMessage = i18n.translate( 'xpack.monitoring.alerts.kibanaVersionMismatch.firing.internalFullMessage', { @@ -139,23 +157,20 @@ export class KibanaVersionMismatchRule extends BaseRule { }, } ); - instance.scheduleActions('default', { - internalShortMessage: i18n.translate( - 'xpack.monitoring.alerts.kibanaVersionMismatch.firing.internalShortMessage', - { - defaultMessage: `Kibana version mismatch alert is firing for {clusterName}. {shortActionText}`, - values: { - clusterName: cluster.clusterName, - shortActionText, - }, - } - ), - internalFullMessage, - state: AlertingDefaults.ALERT_STATE.firing, - clusterName: cluster.clusterName, - versionList: versions, - action, - actionPlain: shortActionText, + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage, + state: AlertingDefaults.ALERT_STATE.firing, + clusterName: cluster.clusterName, + versionList: versions, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/rules/large_shard_size_rule.test.ts b/x-pack/plugins/monitoring/server/rules/large_shard_size_rule.test.ts new file mode 100644 index 0000000000000..0ad6c7687c203 --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/large_shard_size_rule.test.ts @@ -0,0 +1,345 @@ +/* + * 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 { LargeShardSizeRule } from './large_shard_size_rule'; +import { RULE_LARGE_SHARD_SIZE } from '../../common/constants'; +import { fetchIndexShardSize } from '../lib/alerts/fetch_index_shard_size'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +type ILargeShardSizeRuleMock = LargeShardSizeRule & { + defaultParams: { + threshold: number; + duration: string; + }; +} & { + actionVariables: Array<{ + name: string; + description: string; + }>; +}; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_index_shard_size', () => ({ + fetchIndexShardSize: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); + +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('LargeShardSizeRule', () => { + it('should have defaults', () => { + const rule = new LargeShardSizeRule() as ILargeShardSizeRuleMock; + expect(rule.ruleOptions.id).toBe(RULE_LARGE_SHARD_SIZE); + expect(rule.ruleOptions.name).toBe('Shard size'); + expect(rule.ruleOptions.throttle).toBe('12h'); + expect(rule.ruleOptions.defaultParams).toStrictEqual({ + threshold: 55, + indexPattern: '-.*', + }); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { name: 'shardIndex', description: 'The index experiencing large average shard size.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + describe('execute', () => { + const FakeDate = function () {}; + FakeDate.prototype.valueOf = () => 1; + + const shardIndex = 'apm-8.0.0-onboarding-2021.06.30'; + const shardSize = 0; + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const stat = { + shardIndex, + shardSize, + clusterUuid, + }; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; + + beforeEach(() => { + Date = FakeDate as DateConstructor; + (fetchIndexShardSize as jest.Mock).mockImplementation(() => { + return [stat]; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new LargeShardSizeRule() as ILargeShardSizeRuleMock; + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123:apm-8.0.0-onboarding-2021.06.30', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: undefined, + cluster: { + clusterName: 'testCluster', + clusterUuid: 'abc123', + }, + itemLabel: 'apm-8.0.0-onboarding-2021.06.30', + meta: { + instanceId: 'abc123:apm-8.0.0-onboarding-2021.06.30', + itemLabel: 'apm-8.0.0-onboarding-2021.06.30', + shardIndex: 'apm-8.0.0-onboarding-2021.06.30', + shardSize: 0, + }, + nodeId: 'abc123:apm-8.0.0-onboarding-2021.06.30', + nodeName: 'apm-8.0.0-onboarding-2021.06.30', + ui: { + isFiring: true, + lastCheckedMS: 0, + message: { + nextSteps: [ + { + text: '#start_linkInvestigate detailed index stats#end_link', + tokens: [ + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/indices/apm-8.0.0-onboarding-2021.06.30/advanced', + }, + ], + }, + { + text: '#start_linkHow to size your shards (Docs)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/current/size-your-shards.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkShard sizing tips (Blog)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + ], + text: 'The following index: #start_linkapm-8.0.0-onboarding-2021.06.30#end_link has a large average shard size of: 0GB at #absolute', + tokens: [ + { + isAbsolute: true, + isRelative: false, + startToken: '#absolute', + timestamp: 1, + type: 'time', + }, + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/indices/apm-8.0.0-onboarding-2021.06.30', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123:apm-8.0.0-onboarding-2021.06.30', + context: { + internalFullMessage: `Large shard size alert is firing for the following index: ${shardIndex}. [View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `Large shard size alert is firing for the following index: ${shardIndex}. Investigate indices with large shard sizes.`, + action: `[View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: 'Investigate indices with large shard sizes.', + clusterName, + state: 'firing', + shardIndex, + shardIndices: shardIndex, + }, + payload: { + [ALERT_REASON]: `Large shard size alert is firing for the following index: ${shardIndex}. Investigate indices with large shard sizes.`, + }, + }); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchIndexShardSize as jest.Mock).mockImplementation(() => { + return [ + { + ...stat, + ccs, + }, + ]; + }); + const rule = new LargeShardSizeRule() as ILargeShardSizeRuleMock; + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123:apm-8.0.0-onboarding-2021.06.30', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { + clusterName: 'testCluster', + clusterUuid: 'abc123', + }, + itemLabel: 'apm-8.0.0-onboarding-2021.06.30', + meta: { + instanceId: 'abc123:apm-8.0.0-onboarding-2021.06.30', + itemLabel: 'apm-8.0.0-onboarding-2021.06.30', + shardIndex: 'apm-8.0.0-onboarding-2021.06.30', + shardSize: 0, + }, + nodeId: 'abc123:apm-8.0.0-onboarding-2021.06.30', + nodeName: 'apm-8.0.0-onboarding-2021.06.30', + ui: { + isFiring: true, + lastCheckedMS: 0, + message: { + nextSteps: [ + { + text: '#start_linkInvestigate detailed index stats#end_link', + tokens: [ + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/indices/apm-8.0.0-onboarding-2021.06.30/advanced', + }, + ], + }, + { + text: '#start_linkHow to size your shards (Docs)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/current/size-your-shards.html', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + { + text: '#start_linkShard sizing tips (Blog)#end_link', + tokens: [ + { + endToken: '#end_link', + partialUrl: + '{elasticWebsiteUrl}blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster', + startToken: '#start_link', + type: 'docLink', + }, + ], + }, + ], + text: 'The following index: #start_linkapm-8.0.0-onboarding-2021.06.30#end_link has a large average shard size of: 0GB at #absolute', + tokens: [ + { + isAbsolute: true, + isRelative: false, + startToken: '#absolute', + timestamp: 1, + type: 'time', + }, + { + endToken: '#end_link', + startToken: '#start_link', + type: 'link', + url: 'elasticsearch/indices/apm-8.0.0-onboarding-2021.06.30', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123:apm-8.0.0-onboarding-2021.06.30', + context: { + internalFullMessage: `Large shard size alert is firing for the following index: ${shardIndex}. [View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, + internalShortMessage: `Large shard size alert is firing for the following index: ${shardIndex}. Investigate indices with large shard sizes.`, + action: `[View index shard size stats](http://localhost:5601/app/monitoring#/elasticsearch/indices/${shardIndex}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, + actionPlain: 'Investigate indices with large shard sizes.', + clusterName, + state: 'firing', + shardIndex, + shardIndices: shardIndex, + }, + payload: { + [ALERT_REASON]: `Large shard size alert is firing for the following index: ${shardIndex}. Investigate indices with large shard sizes.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts b/x-pack/plugins/monitoring/server/rules/large_shard_size_rule.ts similarity index 87% rename from x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts rename to x-pack/plugins/monitoring/server/rules/large_shard_size_rule.ts index 528c757299f9c..67664695fec87 100644 --- a/x-pack/plugins/monitoring/server/alerts/large_shard_size_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/large_shard_size_rule.ts @@ -7,8 +7,10 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { SanitizedRule, RawAlertInstance } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { SanitizedRule, RawAlertInstance, AlertInstanceContext } from '@kbn/alerting-plugin/common'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -149,7 +151,13 @@ export class LargeShardSizeRule extends BaseRule { } protected executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -196,19 +204,25 @@ export class LargeShardSizeRule extends BaseRule { } ); - instance.scheduleActions('default', { - internalShortMessage, - internalFullMessage, - state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "shardIndices" values for users still using it though + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage, + state: AlertingDefaults.ALERT_STATE.firing, + /* continue to send "shardIndices" values for users still using it though we have replaced it with shardIndex in the template due to alerts per index instead of all indices see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ - shardIndices: shardIndex, - shardIndex, - clusterName: cluster.clusterName, - action, - actionPlain: shortActionText, + shardIndices: shardIndex, + shardIndex, + clusterName: cluster.clusterName, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/rules/license_expiration_rule.test.ts b/x-pack/plugins/monitoring/server/rules/license_expiration_rule.test.ts new file mode 100644 index 0000000000000..f1c193ce5f8ee --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/license_expiration_rule.test.ts @@ -0,0 +1,387 @@ +/* + * 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 { LicenseExpirationRule } from './license_expiration_rule'; +import { RULE_LICENSE_EXPIRATION } from '../../common/constants'; +import { fetchLicenses } from '../lib/alerts/fetch_licenses'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_licenses', () => ({ + fetchLicenses: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); + +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + config: { + ui: { + show_license_expiration: true, + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('LicenseExpirationRule', () => { + it('should have defaults', () => { + const rule = new LicenseExpirationRule(); + expect(rule.ruleOptions.id).toBe(RULE_LICENSE_EXPIRATION); + expect(rule.ruleOptions.name).toBe('License expiration'); + expect(rule.ruleOptions.throttle).toBe('1d'); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { name: 'expiredDate', description: 'The date when the license expires.' }, + { name: 'clusterName', description: 'The cluster to which the license belong.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + + describe('execute', () => { + function FakeDate() {} + + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const license = { + status: 'expired', + type: 'gold', + expiryDateMS: 1000 * 60 * 60 * 24 * 59, + clusterUuid, + }; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; + + beforeEach(() => { + // @ts-ignore + Date = FakeDate; + (fetchLicenses as jest.Mock).mockImplementation(() => { + return [license]; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + it('should fire action', async () => { + jest.useFakeTimers().setSystemTime(new Date('2023-03-30T00:00:00.000Z')); + const alert = new LicenseExpirationRule(); + const type = alert.getRuleType(); + await type.executor({ + ...executorOptions, + params: alert.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid, clusterName }, + ccs: undefined, + itemLabel: undefined, + meta: { + clusterUuid: 'abc123', + expiryDateMS: 5097600000, + status: 'expired', + type: 'gold', + }, + nodeId: undefined, + nodeName: undefined, + ui: { + isFiring: true, + message: { + text: 'The license for this cluster expires in #relative at #absolute. #start_linkPlease update your license.#end_link', + tokens: [ + { + startToken: '#relative', + type: 'time', + isRelative: true, + isAbsolute: false, + timestamp: 5097600000, + }, + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 5097600000, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'license', + }, + ], + }, + severity: 'danger', + triggeredMS: 1680134400000, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: '[Please update your license.](elasticsearch/nodes)', + actionPlain: 'Please update your license.', + internalFullMessage: + 'License expiration alert is firing for testCluster. Your license expires in 53 years. [Please update your license.](elasticsearch/nodes)', + internalShortMessage: + 'License expiration alert is firing for testCluster. Your license expires in 53 years. Please update your license.', + clusterName, + expiredDate: '53 years', + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'License expiration alert is firing for testCluster. Your license expires in 53 years. Please update your license.', + }, + }); + }); + + it('should not fire actions if the license is not expired', async () => { + (fetchLicenses as jest.Mock).mockImplementation(() => { + return [ + { + status: 'active', + type: 'gold', + expiryDateMS: 1000 * 60 * 60 * 24 * 61, + clusterUuid, + }, + ]; + }); + const rule = new LicenseExpirationRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); + }); + + it('should use danger severity for a license expiring soon', async () => { + (fetchLicenses as jest.Mock).mockImplementation(() => { + return [ + { + status: 'active', + type: 'gold', + expiryDateMS: 1000 * 60 * 60 * 24 * 2, + clusterUuid, + }, + ]; + }); + const rule = new LicenseExpirationRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid, clusterName }, + ccs: undefined, + itemLabel: undefined, + meta: { + clusterUuid: 'abc123', + expiryDateMS: 172800000, + status: 'active', + type: 'gold', + }, + nodeId: undefined, + nodeName: undefined, + ui: { + isFiring: true, + message: { + text: 'The license for this cluster expires in #relative at #absolute. #start_linkPlease update your license.#end_link', + tokens: [ + { + startToken: '#relative', + type: 'time', + isRelative: true, + isAbsolute: false, + timestamp: 172800000, + }, + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 172800000, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'license', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: '[Please update your license.](elasticsearch/nodes)', + actionPlain: 'Please update your license.', + internalFullMessage: + 'License expiration alert is firing for testCluster. Your license expires in 2 days. [Please update your license.](elasticsearch/nodes)', + internalShortMessage: + 'License expiration alert is firing for testCluster. Your license expires in 2 days. Please update your license.', + clusterName, + expiredDate: '2 days', + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'License expiration alert is firing for testCluster. Your license expires in 2 days. Please update your license.', + }, + }); + }); + + it('should use warning severity for a license expiring in a bit', async () => { + (fetchLicenses as jest.Mock).mockImplementation(() => { + return [ + { + status: 'active', + type: 'gold', + expiryDateMS: 1000 * 60 * 60 * 24 * 31, + clusterUuid, + }, + ]; + }); + const rule = new LicenseExpirationRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid, clusterName }, + ccs: undefined, + itemLabel: undefined, + meta: { + clusterUuid: 'abc123', + expiryDateMS: 2678400000, + status: 'active', + type: 'gold', + }, + nodeId: undefined, + nodeName: undefined, + ui: { + isFiring: true, + message: { + text: 'The license for this cluster expires in #relative at #absolute. #start_linkPlease update your license.#end_link', + tokens: [ + { + startToken: '#relative', + type: 'time', + isRelative: true, + isAbsolute: false, + timestamp: 2678400000, + }, + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 2678400000, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'license', + }, + ], + }, + severity: 'warning', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: '[Please update your license.](elasticsearch/nodes)', + actionPlain: 'Please update your license.', + internalFullMessage: + 'License expiration alert is firing for testCluster. Your license expires in a month. [Please update your license.](elasticsearch/nodes)', + internalShortMessage: + 'License expiration alert is firing for testCluster. Your license expires in a month. Please update your license.', + clusterName, + expiredDate: 'a month', + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'License expiration alert is firing for testCluster. Your license expires in a month. Please update your license.', + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts b/x-pack/plugins/monitoring/server/rules/license_expiration_rule.ts similarity index 76% rename from x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts rename to x-pack/plugins/monitoring/server/rules/license_expiration_rule.ts index 6be4aa3edc1a8..b3ed188f33ee2 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/license_expiration_rule.ts @@ -7,8 +7,10 @@ import moment from 'moment'; import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { RuleExecutorOptions, Alert } from '@kbn/alerting-plugin/server'; -import { SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { RuleExecutorOptions, RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { AlertInstanceContext, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -143,7 +145,13 @@ export class LicenseExpirationRule extends BaseRule { } protected async executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -161,34 +169,41 @@ export class LicenseExpirationRule extends BaseRule { }); const action = `[${actionText}](elasticsearch/nodes)`; const expiredDate = $duration.humanize(); - instance.scheduleActions('default', { - internalShortMessage: i18n.translate( - 'xpack.monitoring.alerts.licenseExpiration.firing.internalShortMessage', - { - defaultMessage: `License expiration alert is firing for {clusterName}. Your license expires in {expiredDate}. {actionText}`, - values: { - clusterName: cluster.clusterName, - expiredDate, - actionText, - }, - } - ), - internalFullMessage: i18n.translate( - 'xpack.monitoring.alerts.licenseExpiration.firing.internalFullMessage', - { - defaultMessage: `License expiration alert is firing for {clusterName}. Your license expires in {expiredDate}. {action}`, - values: { - clusterName: cluster.clusterName, - expiredDate, - action, - }, - } - ), - state: AlertingDefaults.ALERT_STATE.firing, - expiredDate, - clusterName: cluster.clusterName, - action, - actionPlain: actionText, + const internalShortMessage = i18n.translate( + 'xpack.monitoring.alerts.licenseExpiration.firing.internalShortMessage', + { + defaultMessage: `License expiration alert is firing for {clusterName}. Your license expires in {expiredDate}. {actionText}`, + values: { + clusterName: cluster.clusterName, + expiredDate, + actionText, + }, + } + ); + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: i18n.translate( + 'xpack.monitoring.alerts.licenseExpiration.firing.internalFullMessage', + { + defaultMessage: `License expiration alert is firing for {clusterName}. Your license expires in {expiredDate}. {action}`, + values: { + clusterName: cluster.clusterName, + expiredDate, + action, + }, + } + ), + state: AlertingDefaults.ALERT_STATE.firing, + expiredDate, + clusterName: cluster.clusterName, + action, + actionPlain: actionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.test.ts b/x-pack/plugins/monitoring/server/rules/logstash_version_mismatch_rule.test.ts similarity index 61% rename from x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.test.ts rename to x-pack/plugins/monitoring/server/rules/logstash_version_mismatch_rule.test.ts index aaa0260c1cee5..97cbbd2c619a6 100644 --- a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.test.ts +++ b/x-pack/plugins/monitoring/server/rules/logstash_version_mismatch_rule.test.ts @@ -9,7 +9,8 @@ import { LogstashVersionMismatchRule } from './logstash_version_mismatch_rule'; import { RULE_LOGSTASH_VERSION_MISMATCH } from '../../common/constants'; import { fetchLogstashVersions } from '../lib/alerts/fetch_logstash_versions'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; const RealDate = Date; @@ -80,24 +81,8 @@ describe('LogstashVersionMismatchRule', () => { }, ]; - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; beforeEach(() => { // @ts-ignore @@ -112,52 +97,63 @@ describe('LogstashVersionMismatchRule', () => { afterEach(() => { Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); + jest.resetAllMocks(); }); - it('should fire actions', async () => { + it('should fire action', async () => { const rule = new LogstashVersionMismatchRule(); const type = rule.getRuleType(); await type.executor({ ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, - ccs, - itemLabel: undefined, - nodeId: undefined, - nodeName: undefined, - meta: { + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid: 'abc123', clusterName: 'testCluster' }, ccs, - clusterUuid, - versions: ['8.0.0', '7.2.1'], - }, - ui: { - isFiring: true, - message: { - text: 'Multiple versions of Logstash (8.0.0, 7.2.1) running in this cluster.', + itemLabel: undefined, + nodeId: undefined, + nodeName: undefined, + meta: { + ccs, + clusterUuid, + versions: ['8.0.0', '7.2.1'], + }, + ui: { + isFiring: true, + message: { + text: 'Multiple versions of Logstash (8.0.0, 7.2.1) running in this cluster.', + }, + severity: 'warning', + triggeredMS: 1, + lastCheckedMS: 0, }, - severity: 'warning', - triggeredMS: 1, - lastCheckedMS: 0, }, - }, - ], + ], + }, }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - action: `[View nodes](UNIT_TEST_URL/app/monitoring#/logstash/nodes?_g=(cluster_uuid:${clusterUuid}))`, - actionPlain: 'Verify you have the same version across all nodes.', - internalFullMessage: `Logstash version mismatch alert is firing for testCluster. Logstash is running 8.0.0, 7.2.1. [View nodes](UNIT_TEST_URL/app/monitoring#/logstash/nodes?_g=(cluster_uuid:${clusterUuid}))`, - internalShortMessage: - 'Logstash version mismatch alert is firing for testCluster. Verify you have the same version across all nodes.', - versionList: ['8.0.0', '7.2.1'], - clusterName, - state: 'firing', + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: `[View nodes](UNIT_TEST_URL/app/monitoring#/logstash/nodes?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: 'Verify you have the same version across all nodes.', + internalFullMessage: `Logstash version mismatch alert is firing for testCluster. Logstash is running 8.0.0, 7.2.1. [View nodes](UNIT_TEST_URL/app/monitoring#/logstash/nodes?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: + 'Logstash version mismatch alert is firing for testCluster. Verify you have the same version across all nodes.', + versionList: ['8.0.0', '7.2.1'], + clusterName, + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'Logstash version mismatch alert is firing for testCluster. Verify you have the same version across all nodes.', + }, }); }); @@ -177,8 +173,8 @@ describe('LogstashVersionMismatchRule', () => { ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).not.toHaveBeenCalledWith({}); - expect(scheduleActions).not.toHaveBeenCalled(); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts b/x-pack/plugins/monitoring/server/rules/logstash_version_mismatch_rule.ts similarity index 70% rename from x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts rename to x-pack/plugins/monitoring/server/rules/logstash_version_mismatch_rule.ts index a21e54c2b3c11..100e33d272844 100644 --- a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/logstash_version_mismatch_rule.ts @@ -7,8 +7,10 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { AlertInstanceContext, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -87,7 +89,13 @@ export class LogstashVersionMismatchRule extends BaseRule { } protected async executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -118,33 +126,40 @@ export class LogstashVersionMismatchRule extends BaseRule { state.ccs ); const action = `[${fullActionText}](${globalStateLink})`; - instance.scheduleActions('default', { - internalShortMessage: i18n.translate( - 'xpack.monitoring.alerts.logstashVersionMismatch.firing.internalShortMessage', - { - defaultMessage: `Logstash version mismatch alert is firing for {clusterName}. {shortActionText}`, - values: { - clusterName: cluster.clusterName, - shortActionText, - }, - } - ), - internalFullMessage: i18n.translate( - 'xpack.monitoring.alerts.logstashVersionMismatch.firing.internalFullMessage', - { - defaultMessage: `Logstash version mismatch alert is firing for {clusterName}. Logstash is running {versions}. {action}`, - values: { - clusterName: cluster.clusterName, - versions: versions.join(', '), - action, - }, - } - ), - state: AlertingDefaults.ALERT_STATE.firing, - clusterName: cluster.clusterName, - versionList: versions, - action, - actionPlain: shortActionText, + const internalShortMessage = i18n.translate( + 'xpack.monitoring.alerts.logstashVersionMismatch.firing.internalShortMessage', + { + defaultMessage: `Logstash version mismatch alert is firing for {clusterName}. {shortActionText}`, + values: { + clusterName: cluster.clusterName, + shortActionText, + }, + } + ); + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: i18n.translate( + 'xpack.monitoring.alerts.logstashVersionMismatch.firing.internalFullMessage', + { + defaultMessage: `Logstash version mismatch alert is firing for {clusterName}. Logstash is running {versions}. {action}`, + values: { + clusterName: cluster.clusterName, + versions: versions.join(', '), + action, + }, + } + ), + state: AlertingDefaults.ALERT_STATE.firing, + clusterName: cluster.clusterName, + versionList: versions, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/rules/memory_usage_rule.test.ts b/x-pack/plugins/monitoring/server/rules/memory_usage_rule.test.ts new file mode 100644 index 0000000000000..c1a8836e293c1 --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/memory_usage_rule.test.ts @@ -0,0 +1,399 @@ +/* + * 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 { MemoryUsageRule } from './memory_usage_rule'; +import { RULE_MEMORY_USAGE } from '../../common/constants'; +import { fetchMemoryUsageNodeStats } from '../lib/alerts/fetch_memory_usage_node_stats'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_memory_usage_node_stats', () => ({ + fetchMemoryUsageNodeStats: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('MemoryUsageRule', () => { + it('should have defaults', () => { + const rule = new MemoryUsageRule(); + expect(rule.ruleOptions.id).toBe(RULE_MEMORY_USAGE); + expect(rule.ruleOptions.name).toBe('Memory Usage (JVM)'); + expect(rule.ruleOptions.throttle).toBe('1d'); + expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 85, duration: '5m' }); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { name: 'node', description: 'The node reporting high memory usage.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + + describe('execute', () => { + function FakeDate() {} + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const nodeId = 'myNodeId'; + const nodeName = 'myNodeName'; + const memoryUsage = 91; + const stat = { + clusterUuid, + nodeId, + nodeName, + memoryUsage, + }; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; + + beforeEach(() => { + // @ts-ignore + Date = FakeDate; + (fetchMemoryUsageNodeStats as jest.Mock).mockImplementation(() => { + return [stat]; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new MemoryUsageRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'myNodeId', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: undefined, + cluster: { clusterUuid, clusterName }, + memoryUsage, + itemLabel: undefined, + meta: { + clusterUuid, + memoryUsage, + nodeId, + nodeName, + }, + nodeId, + nodeName, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting JVM memory usage of ${memoryUsage}% at #absolute`, + nextSteps: [ + { + text: '#start_linkTune thread pools#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', + }, + ], + }, + { + text: '#start_linkManaging ES Heap#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: '{elasticWebsiteUrl}blog/a-heap-of-trouble', + }, + ], + }, + { + text: '#start_linkIdentify large indices/shards#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/indices', + }, + ], + }, + { + text: '#start_linkAdd more data nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/myNodeId', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'myNodeId', + context: { + internalFullMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify memory usage level of node.`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: 'Verify memory usage level of node.', + clusterName, + count, + nodes: `${nodeName}:${memoryUsage}.00`, + node: `${nodeName}:${memoryUsage}.00`, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify memory usage level of node.`, + }, + }); + }); + + it('should not fire actions if under threshold', async () => { + (fetchMemoryUsageNodeStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat, + memoryUsage: 1, + }, + ]; + }); + const rule = new MemoryUsageRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchMemoryUsageNodeStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat, + ccs, + }, + ]; + }); + const rule = new MemoryUsageRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'myNodeId', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { clusterUuid, clusterName }, + memoryUsage, + itemLabel: undefined, + meta: { + ccs: 'testCluster', + clusterUuid, + memoryUsage, + nodeId, + nodeName, + }, + nodeId, + nodeName, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting JVM memory usage of ${memoryUsage}% at #absolute`, + nextSteps: [ + { + text: '#start_linkTune thread pools#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', + }, + ], + }, + { + text: '#start_linkManaging ES Heap#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: '{elasticWebsiteUrl}blog/a-heap-of-trouble', + }, + ], + }, + { + text: '#start_linkIdentify large indices/shards#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/indices', + }, + ], + }, + { + text: '#start_linkAdd more data nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/myNodeId', + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'myNodeId', + context: { + internalFullMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, + internalShortMessage: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify memory usage level of node.`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:testCluster))`, + actionPlain: 'Verify memory usage level of node.', + clusterName, + count, + nodes: `${nodeName}:${memoryUsage}.00`, + node: `${nodeName}:${memoryUsage}.00`, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `Memory usage alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify memory usage level of node.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts b/x-pack/plugins/monitoring/server/rules/memory_usage_rule.ts similarity index 86% rename from x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts rename to x-pack/plugins/monitoring/server/rules/memory_usage_rule.ts index fa94e7cb18b6e..9b7f1f72a47f1 100644 --- a/x-pack/plugins/monitoring/server/alerts/memory_usage_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/memory_usage_rule.ts @@ -8,9 +8,11 @@ import { i18n } from '@kbn/i18n'; import numeral from '@elastic/numeral'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { AlertInstanceContext, RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; import { parseDuration } from '@kbn/alerting-plugin/common/parse_duration'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -157,7 +159,13 @@ export class MemoryUsageRule extends BaseRule { } protected executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -207,19 +215,25 @@ export class MemoryUsageRule extends BaseRule { } ); - instance.scheduleActions('default', { - internalShortMessage, - internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, - state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, + state: AlertingDefaults.ALERT_STATE.firing, + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ - nodes: `${firingNode.nodeName}:${firingNode.memoryUsage.toFixed(2)}`, - count: 1, - node: `${firingNode.nodeName}:${firingNode.memoryUsage.toFixed(2)}`, - clusterName: cluster.clusterName, - action, - actionPlain: shortActionText, + nodes: `${firingNode.nodeName}:${firingNode.memoryUsage.toFixed(2)}`, + count: 1, + node: `${firingNode.nodeName}:${firingNode.memoryUsage.toFixed(2)}`, + clusterName: cluster.clusterName, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/rules/missing_monitoring_data_rule.test.ts b/x-pack/plugins/monitoring/server/rules/missing_monitoring_data_rule.test.ts new file mode 100644 index 0000000000000..8bf66a839d6dd --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/missing_monitoring_data_rule.test.ts @@ -0,0 +1,307 @@ +/* + * 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 { MissingMonitoringDataRule } from './missing_monitoring_data_rule'; +import { RULE_MISSING_MONITORING_DATA } from '../../common/constants'; +import { fetchMissingMonitoringData } from '../lib/alerts/fetch_missing_monitoring_data'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_missing_monitoring_data', () => ({ + fetchMissingMonitoringData: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); + +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + show_license_expiration: true, + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('MissingMonitoringDataRule', () => { + it('should have defaults', () => { + const rule = new MissingMonitoringDataRule(); + expect(rule.ruleOptions.id).toBe(RULE_MISSING_MONITORING_DATA); + expect(rule.ruleOptions.name).toBe('Missing monitoring data'); + expect(rule.ruleOptions.throttle).toBe('6h'); + expect(rule.ruleOptions.defaultParams).toStrictEqual({ limit: '1d', duration: '15m' }); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { name: 'node', description: 'The node missing monitoring data.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + + describe('execute', () => { + function FakeDate() {} + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const nodeId = 'esNode1'; + const nodeName = 'esName1'; + const gapDuration = 3000001; + const missingData = [ + { + nodeId, + nodeName, + clusterUuid, + gapDuration, + }, + ]; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; + + beforeEach(() => { + // @ts-ignore + Date = FakeDate; + (fetchMissingMonitoringData as jest.Mock).mockImplementation(() => { + return missingData; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new MissingMonitoringDataRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'esNode1', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: undefined, + cluster: { clusterUuid, clusterName }, + nodeId, + nodeName, + gapDuration, + itemLabel: undefined, + meta: { + clusterUuid, + gapDuration, + limit: 86400000, + nodeId, + nodeName, + }, + ui: { + isFiring: true, + message: { + text: 'For the past an hour, we have not detected any monitoring data from the Elasticsearch node: esName1, starting at #absolute', + nextSteps: [ + { + text: '#start_linkView all Elasticsearch nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes', + }, + ], + }, + { + text: 'Verify monitoring settings on the node', + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'esNode1', + context: { + internalFullMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. [View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. Verify the node is up and running, then double check the monitoring settings.`, + nodes: `node: ${nodeName}`, + node: `node: ${nodeName}`, + action: `[View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: + 'Verify the node is up and running, then double check the monitoring settings.', + clusterName, + count, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. Verify the node is up and running, then double check the monitoring settings.`, + }, + }); + }); + + it('should not fire actions if under threshold', async () => { + (fetchMissingMonitoringData as jest.Mock).mockImplementation(() => { + return [ + { + ...missingData[0], + gapDuration: 1, + }, + ]; + }); + const rule = new MissingMonitoringDataRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchMissingMonitoringData as jest.Mock).mockImplementation(() => { + return [ + { + ...missingData[0], + ccs, + }, + ]; + }); + const rule = new MissingMonitoringDataRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'esNode1', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { clusterUuid, clusterName }, + nodeId, + nodeName, + gapDuration, + itemLabel: undefined, + meta: { + ccs: 'testCluster', + clusterUuid, + gapDuration, + limit: 86400000, + nodeId, + nodeName, + }, + ui: { + isFiring: true, + message: { + text: 'For the past an hour, we have not detected any monitoring data from the Elasticsearch node: esName1, starting at #absolute', + nextSteps: [ + { + text: '#start_linkView all Elasticsearch nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes', + }, + ], + }, + { + text: 'Verify monitoring settings on the node', + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'esNode1', + context: { + internalFullMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. [View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, + internalShortMessage: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. Verify the node is up and running, then double check the monitoring settings.`, + nodes: `node: ${nodeName}`, + node: `node: ${nodeName}`, + action: `[View what monitoring data we do have for this node.](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, + actionPlain: + 'Verify the node is up and running, then double check the monitoring settings.', + clusterName, + count, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `We have not detected any monitoring data for node ${nodeName} in cluster: ${clusterName}. Verify the node is up and running, then double check the monitoring settings.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts b/x-pack/plugins/monitoring/server/rules/missing_monitoring_data_rule.ts similarity index 85% rename from x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts rename to x-pack/plugins/monitoring/server/rules/missing_monitoring_data_rule.ts index 0afd06708767a..a210d9ddf4209 100644 --- a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/missing_monitoring_data_rule.ts @@ -8,9 +8,16 @@ import { i18n } from '@kbn/i18n'; import moment from 'moment'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { RawAlertInstance, SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { + AlertInstanceContext, + AlertInstanceState, + RawAlertInstance, + SanitizedRule, +} from '@kbn/alerting-plugin/common'; import { parseDuration } from '@kbn/alerting-plugin/common/parse_duration'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -137,7 +144,13 @@ export class MissingMonitoringDataRule extends BaseRule { } protected executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: { alertStates: AlertState[] }, item: AlertData | null, cluster: AlertCluster @@ -187,19 +200,25 @@ export class MissingMonitoringDataRule extends BaseRule { }, } ); - instance.scheduleActions('default', { - internalShortMessage, - internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, - state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, + state: AlertingDefaults.ALERT_STATE.firing, + /* continue to send "nodes" and "count" values for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ - nodes: `node: ${firingNode.nodeName}`, - count: 1, - node: `node: ${firingNode.nodeName}`, - clusterName: cluster.clusterName, - action, - actionPlain: shortActionText, + nodes: `node: ${firingNode.nodeName}`, + count: 1, + node: `node: ${firingNode.nodeName}`, + clusterName: cluster.clusterName, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.test.ts b/x-pack/plugins/monitoring/server/rules/nodes_changed_rule.test.ts similarity index 50% rename from x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.test.ts rename to x-pack/plugins/monitoring/server/rules/nodes_changed_rule.test.ts index 02578102741da..3abd163343e9e 100644 --- a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.test.ts +++ b/x-pack/plugins/monitoring/server/rules/nodes_changed_rule.test.ts @@ -9,7 +9,8 @@ import { NodesChangedRule } from './nodes_changed_rule'; import { RULE_NODES_CHANGED } from '../../common/constants'; import { fetchNodesFromClusterStats } from '../lib/alerts/fetch_nodes_from_cluster_stats'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; -import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; const RealDate = Date; @@ -125,24 +126,8 @@ describe('NodesChangedAlert', () => { }, ]; - const replaceState = jest.fn(); - const scheduleActions = jest.fn(); - const getState = jest.fn(); - const executorOptions = { - services: { - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), - alertFactory: { - create: jest.fn().mockImplementation(() => { - return { - replaceState, - scheduleActions, - getState, - }; - }), - }, - }, - state: {}, - }; + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; beforeEach(() => { // @ts-ignore @@ -154,12 +139,10 @@ describe('NodesChangedAlert', () => { afterEach(() => { Date = RealDate; - replaceState.mockReset(); - scheduleActions.mockReset(); - getState.mockReset(); + jest.resetAllMocks(); }); - it('should fire actions when nodes change', async () => { + it('should fire action when nodes change', async () => { (fetchNodesFromClusterStats as jest.Mock).mockImplementation(() => { return nodesChanged; }); @@ -169,59 +152,72 @@ describe('NodesChangedAlert', () => { ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - cluster: { clusterUuid, clusterName }, - ccs, - itemLabel: undefined, - nodeId: undefined, - nodeName: undefined, - meta: { + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid, clusterName }, ccs, - clusterUuid, - recentNodes: [ - { - nodeUuid, - nodeEphemeralId: nodeEphemeralIdChanged, - nodeName, - }, - ], - priorNodes: [ - { - nodeUuid, - nodeEphemeralId, - nodeName, + itemLabel: undefined, + nodeId: undefined, + nodeName: undefined, + meta: { + ccs, + clusterUuid, + recentNodes: [ + { + nodeUuid, + nodeEphemeralId: nodeEphemeralIdChanged, + nodeName, + }, + ], + priorNodes: [ + { + nodeUuid, + nodeEphemeralId, + nodeName, + }, + ], + }, + ui: { + isFiring: true, + message: { + text: "Elasticsearch nodes 'test' restarted in this cluster.", }, - ], - }, - ui: { - isFiring: true, - message: { - text: "Elasticsearch nodes 'test' restarted in this cluster.", + severity: 'warning', + triggeredMS: 1, + lastCheckedMS: 0, }, - severity: 'warning', - triggeredMS: 1, - lastCheckedMS: 0, }, - }, - ], + ], + }, }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - action: '[View nodes](elasticsearch/nodes)', - actionPlain: 'Verify that you added, removed, or restarted nodes.', - internalFullMessage: - 'Nodes changed alert is firing for testCluster. The following Elasticsearch nodes have been added: removed: restarted:test. [View nodes](elasticsearch/nodes)', - internalShortMessage: - 'Nodes changed alert is firing for testCluster. Verify that you added, removed, or restarted nodes.', - added: '', - removed: '', - restarted: 'test', - clusterName, - state: 'firing', + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: '[View nodes](elasticsearch/nodes)', + actionPlain: 'Verify that you added, removed, or restarted nodes.', + internalFullMessage: + 'Nodes changed alert is firing for testCluster. The following Elasticsearch nodes have been added: removed: restarted:test. [View nodes](elasticsearch/nodes)', + internalShortMessage: + 'Nodes changed alert is firing for testCluster. Verify that you added, removed, or restarted nodes.', + added: '', + removed: '', + restarted: 'test', + clusterName, + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'Nodes changed alert is firing for testCluster. Verify that you added, removed, or restarted nodes.', + }, }); }); - it('should fire actions when nodes added, changed, and removed', async () => { + it('should fire action when nodes added, changed, and removed', async () => { (fetchNodesFromClusterStats as jest.Mock).mockImplementation(() => { return nodesAddedChangedRemoved; }); @@ -231,66 +227,79 @@ describe('NodesChangedAlert', () => { ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).toHaveBeenCalledWith({ - alertStates: [ - { - cluster: { clusterUuid, clusterName }, - ccs, - itemLabel: undefined, - nodeId: undefined, - nodeName: undefined, - meta: { + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'abc123', + actionGroup: 'default', + state: { + alertStates: [ + { + cluster: { clusterUuid, clusterName }, ccs, - clusterUuid, - recentNodes: [ - { - nodeUuid, - nodeEphemeralId: nodeEphemeralIdChanged, - nodeName, - }, - { - nodeUuid: 'newNodeId', - nodeEphemeralId: 'newNodeEmpheralId', - nodeName: 'newNodeName', - }, - ], - priorNodes: [ - { - nodeUuid, - nodeEphemeralId, - nodeName, - }, - { - nodeUuid: 'removedNodeId', - nodeEphemeralId: 'removedNodeEmpheralId', - nodeName: 'removedNodeName', + itemLabel: undefined, + nodeId: undefined, + nodeName: undefined, + meta: { + ccs, + clusterUuid, + recentNodes: [ + { + nodeUuid, + nodeEphemeralId: nodeEphemeralIdChanged, + nodeName, + }, + { + nodeUuid: 'newNodeId', + nodeEphemeralId: 'newNodeEmpheralId', + nodeName: 'newNodeName', + }, + ], + priorNodes: [ + { + nodeUuid, + nodeEphemeralId, + nodeName, + }, + { + nodeUuid: 'removedNodeId', + nodeEphemeralId: 'removedNodeEmpheralId', + nodeName: 'removedNodeName', + }, + ], + }, + ui: { + isFiring: true, + message: { + text: "Elasticsearch nodes 'newNodeName' added to this cluster. Elasticsearch nodes 'removedNodeName' removed from this cluster. Elasticsearch nodes 'test' restarted in this cluster.", }, - ], - }, - ui: { - isFiring: true, - message: { - text: "Elasticsearch nodes 'newNodeName' added to this cluster. Elasticsearch nodes 'removedNodeName' removed from this cluster. Elasticsearch nodes 'test' restarted in this cluster.", + severity: 'warning', + triggeredMS: 1, + lastCheckedMS: 0, }, - severity: 'warning', - triggeredMS: 1, - lastCheckedMS: 0, }, - }, - ], + ], + }, }); - expect(scheduleActions).toHaveBeenCalledWith('default', { - action: '[View nodes](elasticsearch/nodes)', - actionPlain: 'Verify that you added, removed, or restarted nodes.', - internalFullMessage: - 'Nodes changed alert is firing for testCluster. The following Elasticsearch nodes have been added:newNodeName removed:removedNodeName restarted:test. [View nodes](elasticsearch/nodes)', - internalShortMessage: - 'Nodes changed alert is firing for testCluster. Verify that you added, removed, or restarted nodes.', - added: 'newNodeName', - removed: 'removedNodeName', - restarted: 'test', - clusterName, - state: 'firing', + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'abc123', + context: { + action: '[View nodes](elasticsearch/nodes)', + actionPlain: 'Verify that you added, removed, or restarted nodes.', + internalFullMessage: + 'Nodes changed alert is firing for testCluster. The following Elasticsearch nodes have been added:newNodeName removed:removedNodeName restarted:test. [View nodes](elasticsearch/nodes)', + internalShortMessage: + 'Nodes changed alert is firing for testCluster. Verify that you added, removed, or restarted nodes.', + added: 'newNodeName', + removed: 'removedNodeName', + restarted: 'test', + clusterName, + state: 'firing', + }, + payload: { + [ALERT_REASON]: + 'Nodes changed alert is firing for testCluster. Verify that you added, removed, or restarted nodes.', + }, }); }); @@ -323,8 +332,8 @@ describe('NodesChangedAlert', () => { ...executorOptions, params: rule.ruleOptions.defaultParams, } as any); - expect(replaceState).not.toHaveBeenCalledWith({}); - expect(scheduleActions).not.toHaveBeenCalled(); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); }); }); }); diff --git a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts b/x-pack/plugins/monitoring/server/rules/nodes_changed_rule.ts similarity index 80% rename from x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts rename to x-pack/plugins/monitoring/server/rules/nodes_changed_rule.ts index 6c20fe6326630..b433be6ac1dd9 100644 --- a/x-pack/plugins/monitoring/server/alerts/nodes_changed_rule.ts +++ b/x-pack/plugins/monitoring/server/rules/nodes_changed_rule.ts @@ -7,8 +7,10 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { AlertInstanceContext, SanitizedRule } from '@kbn/alerting-plugin/common'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -174,7 +176,13 @@ export class NodesChangedRule extends BaseRule { } protected async executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: AlertInstanceState, item: AlertData | null, cluster: AlertCluster @@ -198,37 +206,44 @@ export class NodesChangedRule extends BaseRule { const added = states.added.map((node) => node.nodeName).join(','); const removed = states.removed.map((node) => node.nodeName).join(','); const restarted = states.restarted.map((node) => node.nodeName).join(','); - instance.scheduleActions('default', { - internalShortMessage: i18n.translate( - 'xpack.monitoring.alerts.nodesChanged.firing.internalShortMessage', - { - defaultMessage: `Nodes changed alert is firing for {clusterName}. {shortActionText}`, - values: { - clusterName: cluster.clusterName, - shortActionText, - }, - } - ), - internalFullMessage: i18n.translate( - 'xpack.monitoring.alerts.nodesChanged.firing.internalFullMessage', - { - defaultMessage: `Nodes changed alert is firing for {clusterName}. The following Elasticsearch nodes have been added:{added} removed:{removed} restarted:{restarted}. {action}`, - values: { - clusterName: cluster.clusterName, - added, - removed, - restarted, - action, - }, - } - ), - state: AlertingDefaults.ALERT_STATE.firing, - clusterName: cluster.clusterName, - added, - removed, - restarted, - action, - actionPlain: shortActionText, + const internalShortMessage = i18n.translate( + 'xpack.monitoring.alerts.nodesChanged.firing.internalShortMessage', + { + defaultMessage: `Nodes changed alert is firing for {clusterName}. {shortActionText}`, + values: { + clusterName: cluster.clusterName, + shortActionText, + }, + } + ); + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: i18n.translate( + 'xpack.monitoring.alerts.nodesChanged.firing.internalFullMessage', + { + defaultMessage: `Nodes changed alert is firing for {clusterName}. The following Elasticsearch nodes have been added:{added} removed:{removed} restarted:{restarted}. {action}`, + values: { + clusterName: cluster.clusterName, + added, + removed, + restarted, + action, + }, + } + ), + state: AlertingDefaults.ALERT_STATE.firing, + clusterName: cluster.clusterName, + added, + removed, + restarted, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/alerts/alerts_factory.test.ts b/x-pack/plugins/monitoring/server/rules/rules_factory.test.ts similarity index 84% rename from x-pack/plugins/monitoring/server/alerts/alerts_factory.test.ts rename to x-pack/plugins/monitoring/server/rules/rules_factory.test.ts index c86a5264b204b..15fbc332cbb2f 100644 --- a/x-pack/plugins/monitoring/server/alerts/alerts_factory.test.ts +++ b/x-pack/plugins/monitoring/server/rules/rules_factory.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertsFactory } from './alerts_factory'; +import { RulesFactory } from './rules_factory'; import { RULE_CPU_USAGE } from '../../common/constants'; jest.mock('../static_globals', () => ({ @@ -16,7 +16,7 @@ jest.mock('../static_globals', () => ({ }, })); -describe('AlertsFactory', () => { +describe('RulesFactory', () => { const rulesClient = { find: jest.fn(), }; @@ -39,7 +39,7 @@ describe('AlertsFactory', () => { ], }; }); - const alerts = await AlertsFactory.getByType(RULE_CPU_USAGE, rulesClient as any); + const alerts = await RulesFactory.getByType(RULE_CPU_USAGE, rulesClient as any); expect(alerts).not.toBeNull(); expect(alerts.length).toBe(2); expect(alerts[0].getId()).toBe(1); @@ -54,7 +54,7 @@ describe('AlertsFactory', () => { total: 0, }; }); - await AlertsFactory.getByType(RULE_CPU_USAGE, rulesClient as any); + await RulesFactory.getByType(RULE_CPU_USAGE, rulesClient as any); expect(filter).toBe(`alert.attributes.alertTypeId:${RULE_CPU_USAGE}`); }); }); diff --git a/x-pack/plugins/monitoring/server/alerts/alerts_factory.ts b/x-pack/plugins/monitoring/server/rules/rules_factory.ts similarity index 81% rename from x-pack/plugins/monitoring/server/alerts/alerts_factory.ts rename to x-pack/plugins/monitoring/server/rules/rules_factory.ts index 9cebe881936a3..72aea1b57ea6e 100644 --- a/x-pack/plugins/monitoring/server/alerts/alerts_factory.ts +++ b/x-pack/plugins/monitoring/server/rules/rules_factory.ts @@ -40,7 +40,7 @@ import { RULE_CCR_READ_EXCEPTIONS, RULE_LARGE_SHARD_SIZE, } from '../../common/constants'; -import { CommonAlertParams } from '../../common/types/alerts'; +import { CommonAlertParams as CommonRuleParams } from '../../common/types/alerts'; const BY_TYPE = { [RULE_CLUSTER_HEALTH]: ClusterHealthRule, @@ -59,28 +59,28 @@ const BY_TYPE = { [RULE_LARGE_SHARD_SIZE]: LargeShardSizeRule, }; -export class AlertsFactory { +export class RulesFactory { public static async getByType( type: string, - alertsClient: RulesClient | undefined + rulesClient: RulesClient | undefined ): Promise { - const alertCls = BY_TYPE[type]; - if (!alertCls || !alertsClient) { + const ruleCls = BY_TYPE[type]; + if (!ruleCls || !rulesClient) { return []; } - const alertClientAlerts = await alertsClient.find({ + const rulesClientRules = await rulesClient.find({ options: { filter: `alert.attributes.alertTypeId:${type}`, }, }); - if (!alertClientAlerts.total || !alertClientAlerts.data?.length) { + if (!rulesClientRules.total || !rulesClientRules.data?.length) { return []; } - return alertClientAlerts.data.map((alert) => new alertCls(alert as Rule) as BaseRule); + return rulesClientRules.data.map((rule) => new ruleCls(rule as Rule) as BaseRule); } public static getAll() { - return Object.values(BY_TYPE).map((alert) => new alert()); + return Object.values(BY_TYPE).map((rule) => new rule()); } } diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts b/x-pack/plugins/monitoring/server/rules/thread_pool_rejections_rule_base.ts similarity index 88% rename from x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts rename to x-pack/plugins/monitoring/server/rules/thread_pool_rejections_rule_base.ts index e5b4b7d691a52..ed453b0e208f7 100644 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_rule_base.ts +++ b/x-pack/plugins/monitoring/server/rules/thread_pool_rejections_rule_base.ts @@ -7,8 +7,15 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient } from '@kbn/core/server'; -import { Alert } from '@kbn/alerting-plugin/server'; -import { Rule, RawAlertInstance } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; +import { + Rule, + RawAlertInstance, + AlertInstanceState, + AlertInstanceContext, +} from '@kbn/alerting-plugin/common'; +import { RuleExecutorServices } from '@kbn/alerting-plugin/server'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; import { BaseRule } from './base_rule'; import { AlertData, @@ -176,7 +183,13 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule { }; } protected executeActions( - instance: Alert, + services: RuleExecutorServices< + AlertInstanceState, + AlertInstanceContext, + 'default', + DefaultAlert + >, + alertId: string, { alertStates }: { alertStates: AlertState[] }, item: AlertData | null, cluster: AlertCluster @@ -243,19 +256,25 @@ export class ThreadPoolRejectionsRuleBase extends BaseRule { } ); - instance.scheduleActions('default', { - internalShortMessage, - internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, - threadPoolType: type, - state: AlertingDefaults.ALERT_STATE.firing, - /* continue to send "count" value for users before https://github.com/elastic/kibana/pull/102544 + services.alertsClient?.setAlertData({ + id: alertId, + context: { + internalShortMessage, + internalFullMessage: Globals.app.isCloud ? internalShortMessage : internalFullMessage, + threadPoolType: type, + state: AlertingDefaults.ALERT_STATE.firing, + /* continue to send "count" value for users before https://github.com/elastic/kibana/pull/102544 see https://github.com/elastic/kibana/issues/100136#issuecomment-865229431 */ - count: 1, - node: nodeName, - clusterName, - action, - actionPlain: shortActionText, + count: 1, + node: nodeName, + clusterName, + action, + actionPlain: shortActionText, + }, + payload: { + [ALERT_REASON]: internalShortMessage, + }, }); } } diff --git a/x-pack/plugins/monitoring/server/rules/thread_pool_search_rejections_rule.test.ts b/x-pack/plugins/monitoring/server/rules/thread_pool_search_rejections_rule.test.ts new file mode 100644 index 0000000000000..c6602f536a83c --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/thread_pool_search_rejections_rule.test.ts @@ -0,0 +1,406 @@ +/* + * 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 { ThreadPoolSearchRejectionsRule } from './thread_pool_search_rejections_rule'; +import { RULE_THREAD_POOL_SEARCH_REJECTIONS } from '../../common/constants'; +import { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_thread_pool_rejections_stats', () => ({ + fetchThreadPoolRejectionStats: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); + +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + show_license_expiration: true, + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('ThreadpoolSearchRejectionsRule', () => { + it('should have defaults', () => { + const rule = new ThreadPoolSearchRejectionsRule(); + expect(rule.ruleOptions.id).toBe(RULE_THREAD_POOL_SEARCH_REJECTIONS); + expect(rule.ruleOptions.name).toBe('Thread pool search rejections'); + expect(rule.ruleOptions.throttle).toBe('1d'); + expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 300, duration: '5m' }); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { name: 'node', description: 'The node reporting high thread pool search rejections.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + describe('execute', () => { + function FakeDate() {} + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const nodeId = 'esNode1'; + const nodeName = 'esName1'; + const threadPoolType = 'search'; + const rejectionCount = 400; + const stat = [ + { + rejectionCount, + type: threadPoolType, + clusterUuid, + nodeId, + nodeName, + ccs: null, + }, + ]; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; + + beforeEach(() => { + // @ts-ignore + Date = FakeDate; + (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { + return stat; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new ThreadPoolSearchRejectionsRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'esNode1', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: null, + cluster: { clusterUuid, clusterName }, + nodeId, + nodeName, + itemLabel: undefined, + meta: { + rejectionCount, + clusterUuid, + type: threadPoolType, + nodeId, + nodeName, + ccs: null, + }, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting ${rejectionCount} ${threadPoolType} rejections at #absolute`, + nextSteps: [ + { + text: '#start_linkMonitor this node#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/esNode1/advanced', + }, + ], + }, + { + text: '#start_linkOptimize complex queries#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries', + }, + ], + }, + { + text: '#start_linkAdd more nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + }, + ], + }, + { + text: '#start_linkThread pool settings#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: `elasticsearch/nodes/${nodeId}`, + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'esNode1', + context: { + internalFullMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + node: `${nodeName}`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, + clusterName, + count: 1, + threadPoolType, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + }, + }); + }); + it('should not fire actions if under threshold', async () => { + (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat[0], + rejectionCount: 1, + }, + ]; + }); + const rule = new ThreadPoolSearchRejectionsRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat[0], + ccs, + }, + ]; + }); + const rule = new ThreadPoolSearchRejectionsRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'esNode1', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { clusterUuid, clusterName }, + nodeId, + nodeName, + itemLabel: undefined, + meta: { + rejectionCount, + clusterUuid, + type: threadPoolType, + nodeId, + nodeName, + ccs: 'testCluster', + }, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting ${rejectionCount} ${threadPoolType} rejections at #absolute`, + nextSteps: [ + { + text: '#start_linkMonitor this node#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/esNode1/advanced', + }, + ], + }, + { + text: '#start_linkOptimize complex queries#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries', + }, + ], + }, + { + text: '#start_linkAdd more nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + }, + ], + }, + { + text: '#start_linkThread pool settings#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: `elasticsearch/nodes/${nodeId}`, + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'esNode1', + context: { + internalFullMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, + internalShortMessage: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + node: `${nodeName}`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/esNode1?_g=(cluster_uuid:abc123,ccs:testCluster))`, + actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, + clusterName, + count, + state: 'firing', + threadPoolType, + }, + payload: { + [ALERT_REASON]: `Thread pool search rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.ts b/x-pack/plugins/monitoring/server/rules/thread_pool_search_rejections_rule.ts similarity index 100% rename from x-pack/plugins/monitoring/server/alerts/thread_pool_search_rejections_rule.ts rename to x-pack/plugins/monitoring/server/rules/thread_pool_search_rejections_rule.ts diff --git a/x-pack/plugins/monitoring/server/rules/thread_pool_write_rejections_rule.test.ts b/x-pack/plugins/monitoring/server/rules/thread_pool_write_rejections_rule.test.ts new file mode 100644 index 0000000000000..163dc2b1a677b --- /dev/null +++ b/x-pack/plugins/monitoring/server/rules/thread_pool_write_rejections_rule.test.ts @@ -0,0 +1,406 @@ +/* + * 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 { ThreadPoolWriteRejectionsRule } from './thread_pool_write_rejections_rule'; +import { RULE_THREAD_POOL_WRITE_REJECTIONS } from '../../common/constants'; +import { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats'; +import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; +import { ALERT_REASON } from '@kbn/rule-data-utils'; + +const RealDate = Date; + +jest.mock('../lib/alerts/fetch_thread_pool_rejections_stats', () => ({ + fetchThreadPoolRejectionStats: jest.fn(), +})); +jest.mock('../lib/alerts/fetch_clusters', () => ({ + fetchClusters: jest.fn(), +})); + +jest.mock('../static_globals', () => ({ + Globals: { + app: { + getLogger: () => ({ debug: jest.fn() }), + url: 'http://localhost:5601', + config: { + ui: { + show_license_expiration: true, + ccs: { enabled: true }, + container: { elasticsearch: { enabled: false } }, + }, + }, + }, + }, +})); + +describe('ThreadpoolWriteRejectionsAlert', () => { + it('should have defaults', () => { + const rule = new ThreadPoolWriteRejectionsRule(); + expect(rule.ruleOptions.id).toBe(RULE_THREAD_POOL_WRITE_REJECTIONS); + expect(rule.ruleOptions.name).toBe(`Thread pool write rejections`); + expect(rule.ruleOptions.throttle).toBe('1d'); + expect(rule.ruleOptions.defaultParams).toStrictEqual({ threshold: 300, duration: '5m' }); + expect(rule.ruleOptions.actionVariables).toStrictEqual([ + { name: 'node', description: 'The node reporting high thread pool write rejections.' }, + { + name: 'internalShortMessage', + description: 'The short internal message generated by Elastic.', + }, + { + name: 'internalFullMessage', + description: 'The full internal message generated by Elastic.', + }, + { name: 'state', description: 'The current state of the alert.' }, + { name: 'clusterName', description: 'The cluster to which the node(s) belongs.' }, + { name: 'action', description: 'The recommended action for this alert.' }, + { + name: 'actionPlain', + description: 'The recommended action for this alert, without any markdown.', + }, + ]); + }); + describe('execute', () => { + function FakeDate() {} + FakeDate.prototype.valueOf = () => 1; + + const clusterUuid = 'abc123'; + const clusterName = 'testCluster'; + const nodeId = 'esNode1'; + const nodeName = 'esName1'; + const threadPoolType = 'write'; + const rejectionCount = 400; + const stat = [ + { + rejectionCount, + type: threadPoolType, + clusterUuid, + nodeId, + nodeName, + ccs: null, + }, + ]; + + const services = alertsMock.createRuleExecutorServices(); + const executorOptions = { services, state: {} }; + + beforeEach(() => { + // @ts-ignore + Date = FakeDate; + (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { + return stat; + }); + (fetchClusters as jest.Mock).mockImplementation(() => { + return [{ clusterUuid, clusterName }]; + }); + }); + + afterEach(() => { + Date = RealDate; + jest.resetAllMocks(); + }); + + it('should fire action', async () => { + const rule = new ThreadPoolWriteRejectionsRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'esNode1', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: null, + cluster: { clusterUuid, clusterName }, + nodeId, + nodeName, + itemLabel: undefined, + meta: { + rejectionCount, + clusterUuid, + type: threadPoolType, + nodeId, + nodeName, + ccs: null, + }, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting ${rejectionCount} ${threadPoolType} rejections at #absolute`, + nextSteps: [ + { + text: '#start_linkMonitor this node#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/esNode1/advanced', + }, + ], + }, + { + text: '#start_linkOptimize complex queries#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries', + }, + ], + }, + { + text: '#start_linkAdd more nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + }, + ], + }, + { + text: '#start_linkThread pool settings#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: `elasticsearch/nodes/${nodeId}`, + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'esNode1', + context: { + internalFullMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + internalShortMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + node: `${nodeName}`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`, + actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, + clusterName, + count: 1, + threadPoolType, + state: 'firing', + }, + payload: { + [ALERT_REASON]: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + }, + }); + }); + it('should not fire actions if under threshold', async () => { + (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat[0], + rejectionCount: 1, + }, + ]; + }); + const rule = new ThreadPoolWriteRejectionsRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + expect(services.alertsClient.report).not.toHaveBeenCalled(); + expect(services.alertsClient.setAlertData).not.toHaveBeenCalled(); + }); + + it('should handle ccs', async () => { + const ccs = 'testCluster'; + (fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => { + return [ + { + ...stat[0], + ccs, + }, + ]; + }); + const rule = new ThreadPoolWriteRejectionsRule(); + const type = rule.getRuleType(); + await type.executor({ + ...executorOptions, + params: rule.ruleOptions.defaultParams, + } as any); + const count = 1; + expect(services.alertsClient.report).toHaveBeenCalledTimes(1); + expect(services.alertsClient.setAlertData).toHaveBeenCalledTimes(1); + expect(services.alertsClient.report).toHaveBeenCalledWith({ + id: 'esNode1', + actionGroup: 'default', + state: { + alertStates: [ + { + ccs: 'testCluster', + cluster: { clusterUuid, clusterName }, + nodeId, + nodeName, + itemLabel: undefined, + meta: { + rejectionCount, + clusterUuid, + type: threadPoolType, + nodeId, + nodeName, + ccs: 'testCluster', + }, + ui: { + isFiring: true, + message: { + text: `Node #start_link${nodeName}#end_link is reporting ${rejectionCount} ${threadPoolType} rejections at #absolute`, + nextSteps: [ + { + text: '#start_linkMonitor this node#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: 'elasticsearch/nodes/esNode1/advanced', + }, + ], + }, + { + text: '#start_linkOptimize complex queries#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries', + }, + ], + }, + { + text: '#start_linkAdd more nodes#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html', + }, + ], + }, + { + text: '#start_linkResize your deployment (ECE)#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html', + }, + ], + }, + { + text: '#start_linkThread pool settings#end_link', + tokens: [ + { + startToken: '#start_link', + endToken: '#end_link', + type: 'docLink', + partialUrl: + '{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html', + }, + ], + }, + ], + tokens: [ + { + startToken: '#absolute', + type: 'time', + isAbsolute: true, + isRelative: false, + timestamp: 1, + }, + { + startToken: '#start_link', + endToken: '#end_link', + type: 'link', + url: `elasticsearch/nodes/${nodeId}`, + }, + ], + }, + severity: 'danger', + triggeredMS: 1, + lastCheckedMS: 0, + }, + }, + ], + }, + }); + expect(services.alertsClient.setAlertData).toHaveBeenCalledWith({ + id: 'esNode1', + context: { + internalFullMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`, + internalShortMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + node: `${nodeName}`, + action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/esNode1?_g=(cluster_uuid:abc123,ccs:testCluster))`, + actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`, + clusterName, + count, + state: 'firing', + threadPoolType, + }, + payload: { + [ALERT_REASON]: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.ts b/x-pack/plugins/monitoring/server/rules/thread_pool_write_rejections_rule.ts similarity index 100% rename from x-pack/plugins/monitoring/server/alerts/thread_pool_write_rejections_rule.ts rename to x-pack/plugins/monitoring/server/rules/thread_pool_write_rejections_rule.ts diff --git a/x-pack/plugins/monitoring/tsconfig.json b/x-pack/plugins/monitoring/tsconfig.json index 00ca962568141..112bf5f695b17 100644 --- a/x-pack/plugins/monitoring/tsconfig.json +++ b/x-pack/plugins/monitoring/tsconfig.json @@ -42,6 +42,8 @@ "@kbn/observability-shared-plugin", "@kbn/shared-ux-link-redirect-app", "@kbn/logs-shared-plugin", + "@kbn/alerts-as-data-utils", + "@kbn/rule-data-utils", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/observability_ai_assistant/scripts/evaluation/scenarios/esql/index.spec.ts b/x-pack/plugins/observability_ai_assistant/scripts/evaluation/scenarios/esql/index.spec.ts index 8acc2c98aa504..4c9b724686c0f 100644 --- a/x-pack/plugins/observability_ai_assistant/scripts/evaluation/scenarios/esql/index.spec.ts +++ b/x-pack/plugins/observability_ai_assistant/scripts/evaluation/scenarios/esql/index.spec.ts @@ -7,48 +7,21 @@ /// -import { last } from 'lodash'; -import moment from 'moment'; import { apm, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; -import { MessageRole } from '../../../../common'; +import moment from 'moment'; import { chatClient, esClient, synthtraceEsClients } from '../../services'; -function extractEsqlQuery(response: string) { - return response.match(/```esql([\s\S]*?)```/)?.[1]; -} - async function evaluateEsqlQuery({ question, expected, criteria = [], - execute = true, }: { question: string; expected?: string; criteria?: string[]; - execute?: boolean; }): Promise { - let conversation = await chatClient.complete(question); - - const esqlQuery = extractEsqlQuery(last(conversation.messages)?.content || ''); - - if (esqlQuery && execute) { - conversation = await chatClient.complete( - conversation.conversationId!, - conversation.messages.concat({ - content: '', - role: MessageRole.Assistant, - function_call: { - name: 'execute_query', - arguments: JSON.stringify({ - query: esqlQuery, - }), - trigger: MessageRole.User, - }, - }) - ); - } + const conversation = await chatClient.complete(question); const evaluation = await chatClient.evaluate(conversation, [ ...(expected @@ -57,7 +30,7 @@ async function evaluateEsqlQuery({ ${expected}`, ] : []), - ...(execute && expected ? [`The query successfully executed without an error`] : []), + ...(expected ? [`The query successfully executed without an error`] : []), ...criteria, ]); @@ -146,7 +119,6 @@ describe('ES|QL query generation', () => { | SORT hire_date | KEEP emp_no, hire_date_formatted | LIMIT 5`, - execute: false, }); }); diff --git a/x-pack/plugins/observability_ai_assistant/scripts/load_esql_docs/format_esql_examples.ts b/x-pack/plugins/observability_ai_assistant/scripts/load_esql_docs/format_esql_examples.ts new file mode 100644 index 0000000000000..4bb578f91f6c1 --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/scripts/load_esql_docs/format_esql_examples.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. + */ + +export function formatEsqlExamples(content: string) { + // Regular expression to match the queries + const queryRegex = /(\s*(FROM |ROW |SHOW ).*?)(?=\n[^|\s]|$)/gs; + + // Function to format a matched query + const formatQuery = (match: string) => { + return `\n\`\`\`esql\n${match.trim()}\n\`\`\`\n`; + }; + + // Replace all matches in the input string + return content.replace(queryRegex, formatQuery); +} diff --git a/x-pack/plugins/observability_ai_assistant/scripts/load_esql_docs/load_esql_docs.ts b/x-pack/plugins/observability_ai_assistant/scripts/load_esql_docs/load_esql_docs.ts index 20bb43cd49d11..a3d1a07533956 100644 --- a/x-pack/plugins/observability_ai_assistant/scripts/load_esql_docs/load_esql_docs.ts +++ b/x-pack/plugins/observability_ai_assistant/scripts/load_esql_docs/load_esql_docs.ts @@ -15,6 +15,7 @@ import Path from 'path'; import git, { SimpleGitProgressEvent } from 'simple-git'; import yargs, { Argv } from 'yargs'; import { extractSections } from './extract_sections'; +import { formatEsqlExamples } from './format_esql_examples'; yargs(process.argv.slice(2)) .command( @@ -221,7 +222,19 @@ yargs(process.argv.slice(2)) outDir, `esql-${doc.title.replaceAll(' ', '-').toLowerCase()}.txt` ); - await Fs.writeFile(fileName, doc.content); + + // We ask the LLM to output queries wrapped in ```esql...```, + // so we try to format ES|QL examples in the docs in the same + // way. The hope is that this creates a stronger relation in the + // output. + const formattedContent = formatEsqlExamples(doc.content); + + log.debug({ + content: doc.content, + formattedContent, + }); + + await Fs.writeFile(fileName, formattedContent); }) ) ); diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-abs.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-abs.txt index f27b33d6d1473..add29ab4b88e6 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-abs.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-abs.txt @@ -1,8 +1,18 @@ ABS +Syntax +Parameters +n +Numeric expression. If null, the function returns null. +DescriptionReturns the absolute value.Supported types +Examples +```esql +ROW number = -1.0 +| EVAL abs_number = ABS(number) +``` -Returns the absolute value. +```esql FROM employees | KEEP first_name, last_name, height | EVAL abs_height = ABS(0.0 - height) -Supported types: +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-acos.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-acos.txt index 0274cdfac205a..5cccde6b4321d 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-acos.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-acos.txt @@ -7,5 +7,7 @@ Numeric expression. If null, the function returns null. DescriptionReturns the arccosine of n as an angle, expressed in radians.Supported types Example +```esql ROW a=.9 | EVAL acos=ACOS(a) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-asin.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-asin.txt index 6e36b7d776cd0..5210583fba7ef 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-asin.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-asin.txt @@ -1,7 +1,14 @@ ASIN - -Inverse sine trigonometric function. +Syntax +Parameters +n +Numeric expression. If null, the function returns null. +DescriptionReturns the +arcsine +of the input numeric expression as an angle, expressed in radians.Supported types +Example +```esql ROW a=.9 | EVAL asin=ASIN(a) -Supported types: +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan.txt index 78a6c0b4a4f71..8360a44147a02 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan.txt @@ -1,7 +1,14 @@ ATAN - -Inverse tangent trigonometric function. +Syntax +Parameters +n +Numeric expression. If null, the function returns null. +DescriptionReturns the +arctangent of the +input numeric expression as an angle, expressed in radians.Supported types +Example +```esql ROW a=12.9 | EVAL atan=ATAN(a) -Supported types: +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan2.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan2.txt index c194e8ee9f0a7..7bf09faf50e41 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan2.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-atan2.txt @@ -1,8 +1,16 @@ ATAN2 - -The angle between the positive x-axis and the -ray from the origin to the point (x , y) in the Cartesian plane. +Syntax +Parameters +y +Numeric expression. If null, the function returns null. +x +Numeric expression. If null, the function returns null. +DescriptionThe angle between the positive x-axis and +the ray from the origin to the point (x , y) in the Cartesian plane, expressed +in radians.Supported types +Example +```esql ROW y=12.9, x=.6 | EVAL atan2=ATAN2(y, x) -Supported types: +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-auto_bucket.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-auto_bucket.txt index 1263cccd6d519..a4c81c732d35a 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-auto_bucket.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-auto_bucket.txt @@ -1,27 +1,83 @@ AUTO_BUCKET -Creates human-friendly buckets and returns a datetime value for each row that -corresponds to the resulting bucket the row falls into. Combine AUTO_BUCKET -with STATS ... BY to create a date histogram.You provide a target number of buckets, a start date, and an end date, and it -picks an appropriate bucket size to generate the target number of buckets or -fewer. For example, this asks for at most 20 buckets over a whole year, which -picks monthly buckets: -ROW date=TO_DATETIME("1985-07-09T00:00:00.000Z") -| EVAL bucket=AUTO_BUCKET(date, 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") +Syntax +AUTO_BUCKET(field, buckets, from, to) +Parameters +field +Numeric or date column from which to derive buckets. +buckets +Target number of buckets. +from +Start of the range. Can be a number or a date expressed as a string. +to +End of the range. Can be a number or a date expressed as a string. +DescriptionCreates human-friendly buckets and returns a value for each row that corresponds +to the resulting bucket the row falls into.Using a target number of buckets, a start of a range, and an end of a range, +AUTO_BUCKET picks an appropriate bucket size to generate the target number of +buckets or fewer. For example, asking for at most 20 buckets over a year results +in monthly buckets: +```esql +FROM employees +| WHERE hire_date >= "1985-01-01T00:00:00Z" AND hire_date < "1986-01-01T00:00:00Z" +| EVAL month = AUTO_BUCKET(hire_date, 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") +| KEEP hire_date, month +| SORT hire_date +``` + The goal isn’t to provide exactly the target number of buckets, it’s to pick a -range that people are comfortable with that provides at most the target number of -buckets.If you ask for more buckets then AUTO_BUCKET can pick a smaller range. For example, -asking for at most 100 buckets in a year will get you week long buckets: -ROW date=TO_DATETIME("1985-07-09T00:00:00.000Z") -| EVAL bucket=AUTO_BUCKET(date, 100, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") -AUTO_BUCKET does not filter any rows. It only uses the provided time range to -pick a good bucket size. For rows with a date outside of the range, it returns a -datetime that corresponds to a bucket outside the range. Combine AUTO_BUCKET -with WHERE to filter rows.A more complete example might look like: +range that people are comfortable with that provides at most the target number +of buckets.Combine AUTO_BUCKET with +STATS ... BY to create a histogram: +```esql +FROM employees +| WHERE hire_date >= "1985-01-01T00:00:00Z" AND hire_date < "1986-01-01T00:00:00Z" +| EVAL month = AUTO_BUCKET(hire_date, 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") +| STATS hires_per_month = COUNT(*) BY month +| SORT month +``` + +AUTO_BUCKET does not create buckets that don’t match any documents. +That’s why this example is missing 1985-03-01 and other dates. +Asking for more buckets can result in a smaller range. For example, asking for +at most 100 buckets in a year results in weekly buckets: +```esql +FROM employees +| WHERE hire_date >= "1985-01-01T00:00:00Z" AND hire_date < "1986-01-01T00:00:00Z" +| EVAL week = AUTO_BUCKET(hire_date, 100, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") +| STATS hires_per_week = COUNT(*) BY week +| SORT week +``` + +AUTO_BUCKET does not filter any rows. It only uses the provided range to +pick a good bucket size. For rows with a value outside of the range, it returns +a bucket value that corresponds to a bucket outside the range. Combine +AUTO_BUCKET with WHERE to filter rows. +AUTO_BUCKET can also operate on numeric fields. For example, to create a +salary histogram: +```esql +FROM employees +| EVAL bs = AUTO_BUCKET(salary, 20, 25324, 74999) +| STATS COUNT(*) by bs +| SORT bs +``` + +Unlike the earlier example that intentionally filters on a date range, you +rarely want to filter on a numeric range. You have to find the min and max +separately. ES|QL doesn’t yet have an easy way to do that automatically.ExamplesCreate hourly buckets for the last 24 hours, and calculate the number of events +per hour: +```esql +FROM sample_data +| WHERE @timestamp >= NOW() - 1 day and @timestamp < NOW() +| EVAL bucket = AUTO_BUCKET(@timestamp, 25, DATE_FORMAT(NOW() - 1 day), DATE_FORMAT(NOW())) +| STATS COUNT(*) BY bucket +``` + +Create monthly buckets for the year 1985, and calculate the average salary by +hiring month: +```esql FROM employees | WHERE hire_date >= "1985-01-01T00:00:00Z" AND hire_date < "1986-01-01T00:00:00Z" | EVAL bucket = AUTO_BUCKET(hire_date, 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") | STATS AVG(salary) BY bucket | SORT bucket -AUTO_BUCKET does not create buckets that don’t match any documents. That’s -why the example above is missing 1985-03-01 and other dates. +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-avg.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-avg.txt index 40667a199cc1f..ea5132bab11b4 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-avg.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-avg.txt @@ -1,6 +1,11 @@ AVG -The average of a numeric field. +Syntax +AVG(column) +column +Numeric column. If null, the function returns null. +DescriptionThe average of a numeric field.Supported typesThe result is always a double no matter the input type.Example +```esql FROM employees | STATS AVG(height) -The result is always a double not matter the input type. \ No newline at end of file +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-case.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-case.txt index 35c9278ba2fd5..a8d2ca35fb1c8 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-case.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-case.txt @@ -13,10 +13,32 @@ The default value that’s is returned when no condition matches. DescriptionAccepts pairs of conditions and values. The function returns the value that belongs to the first condition that evaluates to true.If the number of arguments is odd, the last argument is the default value which is returned when no condition matches. If the number of arguments is even, and -no condition matches, the function returns null.Example +no condition matches, the function returns null.ExampleDetermine whether employees are monolingual, bilingual, or polyglot: +```esql FROM employees | EVAL type = CASE( languages <= 1, "monolingual", languages <= 2, "bilingual", "polyglot") | KEEP emp_no, languages, type +``` + +Calculate the total connection success rate based on log messages: +```esql +FROM sample_data +| EVAL successful = CASE( + STARTS_WITH(message, "Connected to"), 1, + message == "Connection error", 0 + ) +| STATS success_rate = AVG(successful) +``` + +Calculate an hourly error rate as a percentage of the total number of log +messages: +```esql +FROM sample_data +| EVAL error = CASE(message LIKE "*error*", 1, 0) +| EVAL hour = DATE_TRUNC(1 hour, @timestamp) +| STATS error_rate = AVG(error) by hour +| SORT hour +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ceil.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ceil.txt index 685ec6690772d..8fac3b0bddc2f 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ceil.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ceil.txt @@ -1,10 +1,16 @@ CEIL - -Round a number up to the nearest integer. +Syntax +Parameters +n +Numeric expression. If null, the function returns null. +DescriptionRound a number up to the nearest integer. +This is a noop for long (including unsigned) and integer. + For double this picks the closest double value to the integer + similar to Math.ceil. +Supported types +Example +```esql ROW a=1.8 | EVAL a=CEIL(a) -This is a noop for long (including unsigned) and integer. - For double this picks the the closest double value to the integer ala - Math.ceil. -Supported types: +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-coalesce.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-coalesce.txt index 568f045de8d64..b8d3d2498b57b 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-coalesce.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-coalesce.txt @@ -1,5 +1,13 @@ COALESCE -Returns the first non-null value. +Syntax +COALESCE(expression1 [, ..., expressionN]) +Parameters +expressionX +Expression to evaluate. +DescriptionReturns the first of its arguments that is not null. If all arguments are null, +it returns null.Example +```esql ROW a=null, b="b" | EVAL COALESCE(a, b) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-concat.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-concat.txt index e92c691a7e520..6e5c1ba1b69f6 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-concat.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-concat.txt @@ -1,6 +1,13 @@ CONCAT -Concatenates two or more strings. +Syntax +CONCAT(string1, string2[, ..., stringN]) +Parameters +stringX +Strings to concatenate. +DescriptionConcatenates two or more strings.Example +```esql FROM employees -| KEEP first_name, last_name, height +| KEEP first_name, last_name | EVAL fullname = CONCAT(first_name, " ", last_name) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cos.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cos.txt index db7252d5966c4..ebda0596fca8a 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cos.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cos.txt @@ -1,7 +1,13 @@ COS - -Cosine trigonometric function. Input expected in radians. +Syntax +Parameters +n +Numeric expression. If null, the function returns null. +DescriptionReturns the cosine of n. Input +expected in radians.Supported types +Example +```esql ROW a=1.8 | EVAL cos=COS(a) -Supported types: +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cosh.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cosh.txt index 22f221bbe18bb..a8920bdf4e694 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cosh.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-cosh.txt @@ -1,7 +1,13 @@ COSH - -Cosine hyperbolic function. +Syntax +Parameters +n +Numeric expression. If null, the function returns null. +Supported types +DescriptionReturns the hyperbolic +cosine.Example +```esql ROW a=1.8 | EVAL cosh=COSH(a) -Supported types: +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count.txt index 555b80f2d532d..c3c7136459ebb 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count.txt @@ -1,10 +1,20 @@ COUNT -Counts field values. +Syntax +COUNT([input]) +Parameters +input +Column or literal for which to count the number of values. If omitted, returns a +count all (the number of rows). +DescriptionReturns the total number (count) of input values.Supported typesCan take any field type as input.Examples +```esql FROM employees | STATS COUNT(height) -Can take any field type as input and the result is always a long not matter -the input type.To count the number of rows, use COUNT(*): +``` + +To count the number of rows, use COUNT() or COUNT(*): +```esql FROM employees | STATS count = COUNT(*) BY languages | SORT languages DESC +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count_distinct.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count_distinct.txt index dbe422e6703b5..b09825440dc42 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count_distinct.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-count_distinct.txt @@ -1,10 +1,13 @@ COUNT_DISTINCT -The approximate number of distinct values. -FROM hosts -| STATS COUNT_DISTINCT(ip0), COUNT_DISTINCT(ip1) -Can take any field type as input and the result is always a long not matter -the input type.Counts are approximateeditComputing exact counts requires loading values into a set and returning its +Syntax +COUNT_DISTINCT(column[, precision]) +Parameters +column +Column for which to count the number of distinct values. +precision +Precision. Refer to Counts are approximate. +DescriptionReturns the approximate number of distinct values.Counts are approximateeditComputing exact counts requires loading values into a set and returning its size. This doesn’t scale when working on high-cardinality sets and/or large values as the required memory usage and the need to communicate those per-shard sets between nodes would utilize too many resources of the cluster.This COUNT_DISTINCT function is based on the @@ -22,7 +25,15 @@ on the dataset in question. In general, most datasets show consistently good accuracy. Also note that even with a threshold as low as 100, the error remains very low (1-6% as seen in the above graph) even when counting millions of items.The HyperLogLog++ algorithm depends on the leading zeros of hashed values, the exact distributions of hashes in a dataset can affect the -accuracy of the cardinality.Precision is configurableeditThe COUNT_DISTINCT function takes an optional second parameter to configure the -precision discussed previously. +accuracy of the cardinality.The COUNT_DISTINCT function takes an optional second parameter to configure the +precision.Supported typesCan take any field type as input.Examples +```esql +FROM hosts +| STATS COUNT_DISTINCT(ip0), COUNT_DISTINCT(ip1) +``` + +With the optional second parameter to configure the precision: +```esql FROM hosts | STATS COUNT_DISTINCT(ip0, 80000), COUNT_DISTINCT(ip1, 5) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_extract.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_extract.txt index 442c9e6c9d719..0ea53cb38d1f9 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_extract.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_extract.txt @@ -1,6 +1,31 @@ DATE_EXTRACT -Extracts parts of a date, like year, month, day, hour. -The supported field types are those provided by java.time.temporal.ChronoField. +Syntax +DATE_EXTRACT(date_part, date) +Parameters +date_part +Part of the date to extract. Can be: aligned_day_of_week_in_month, +aligned_day_of_week_in_year, aligned_week_of_month, aligned_week_of_year, +ampm_of_day, clock_hour_of_ampm, clock_hour_of_day, day_of_month, +day_of_week, day_of_year, epoch_day, era, hour_of_ampm, hour_of_day, +instant_seconds, micro_of_day, micro_of_second, milli_of_day, +milli_of_second, minute_of_day, minute_of_hour, month_of_year, +nano_of_day, nano_of_second, offset_seconds, proleptic_month, +second_of_day, second_of_minute, year, or year_of_era. Refer to +java.time.temporal.ChronoField +for a description of these values. +If null, the function returns null. +date +Date expression. If null, the function returns null. +DescriptionExtracts parts of a date, like year, month, day, hour.Examples +```esql ROW date = DATE_PARSE("yyyy-MM-dd", "2022-05-06") | EVAL year = DATE_EXTRACT("year", date) +``` + +Find all events that occurred outside of business hours (before 9 AM or after 5 +PM), on any given date: +```esql +FROM sample_data +| WHERE DATE_EXTRACT("hour_of_day", @timestamp) < 9 AND DATE_EXTRACT("hour_of_day", @timestamp) >= 17 +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_format.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_format.txt index b772cac90a0ee..70feb4d1e3bf4 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_format.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_format.txt @@ -1,7 +1,17 @@ DATE_FORMAT -Returns a string representation of a date in the provided format. If no format -is specified, the yyyy-MM-dd'T'HH:mm:ss.SSSZ format is used. +Syntax +DATE_FORMAT([format,] date) +Parameters +format +Date format (optional). If no format is specified, the +yyyy-MM-dd'T'HH:mm:ss.SSSZ format is used. If null, the function returns +null. +date +Date expression. If null, the function returns null. +DescriptionReturns a string representation of a date, in the provided format.Example +```esql FROM employees | KEEP first_name, last_name, hire_date | EVAL hired = DATE_FORMAT("YYYY-MM-dd", hire_date) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_parse.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_parse.txt index f03321af7eb93..c8a224b713610 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_parse.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_parse.txt @@ -12,5 +12,7 @@ Date expression as a string. If null or an empty string, the function returns null. DescriptionReturns a date by parsing the second argument using the format specified in the first argument.Example +```esql ROW date_string = "2022-05-06" | EVAL date = DATE_PARSE("yyyy-MM-dd", date_string) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_trunc.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_trunc.txt index 773a2a9ce9513..dd87fa74a69d4 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_trunc.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-date_trunc.txt @@ -1,8 +1,34 @@ DATE_TRUNC -Rounds down a date to the closest interval. Intervals can be expressed using the -timespan literal syntax. +Syntax +DATE_TRUNC(interval, date) +Parameters +interval +Interval, expressed using the timespan literal +syntax. If null, the function returns null. +date +Date expression. If null, the function returns null. +DescriptionRounds down a date to the closest interval.Examples +```esql FROM employees +| KEEP first_name, last_name, hire_date | EVAL year_hired = DATE_TRUNC(1 year, hire_date) -| STATS COUNT(emp_no) BY year_hired -| SORT year_hired +``` + +Combine DATE_TRUNC with STATS ... BY to create date histograms. For +example, the number of hires per year: +```esql +FROM employees +| EVAL year = DATE_TRUNC(1 year, hire_date) +| STATS hires = COUNT(emp_no) BY year +| SORT year +``` + +Or an hourly error rate: +```esql +FROM sample_data +| EVAL error = CASE(message LIKE "*error*", 1, 0) +| EVAL hour = DATE_TRUNC(1 hour, @timestamp) +| STATS error_rate = AVG(error) by hour +| SORT hour +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-dissect.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-dissect.txt index c4f99757f0b57..f323c2078a79b 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-dissect.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-dissect.txt @@ -14,12 +14,17 @@ DescriptionDISSECT enables you to extract structured data out of a string. DISSECT matches the string against a delimiter-based pattern, and extracts the specified keys as columns.Refer to Process data with DISSECT for the syntax of dissect patterns.ExamplesThe following example parses a string that contains a timestamp, some text, and an IP address: +```esql ROW a = "2023-01-23T12:15:00.000Z - some text - 127.0.0.1" | DISSECT a "%{date} - %{msg} - %{ip}" | KEEP date, msg, ip +``` + By default, DISSECT outputs keyword string columns. To convert to another type, use Type conversion functions: +```esql ROW a = "2023-01-23T12:15:00.000Z - some text - 127.0.0.1" | DISSECT a "%{date} - %{msg} - %{ip}" | KEEP date, msg, ip | EVAL date = TO_DATETIME(date) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-drop.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-drop.txt index 88d5af4315d9f..f84f9b9613de0 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-drop.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-drop.txt @@ -6,9 +6,14 @@ Parameters columns A comma-separated list of columns to remove. Supports wildcards. DescriptionThe DROP processing command removes one or more columns.Examples +```esql FROM employees | DROP height +``` + Rather than specify each column by name, you can use wildcards to drop all columns with a name that matches a pattern: +```esql FROM employees | DROP height* +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-e.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-e.txt index 7b56bebff6dce..4438b7dc35683 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-e.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-e.txt @@ -2,4 +2,6 @@ E Euler’s number. +```esql ROW E() +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-enrich.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-enrich.txt index 94b18473228cb..c7de9fd3e3c56 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-enrich.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-enrich.txt @@ -29,19 +29,31 @@ the match_field defined in the enrich policy and requires that the input table has a column with the same name (language_code in this example). ENRICH will look for records in the enrich index based on the match field value. +```esql ROW language_code = "1" | ENRICH languages_policy +``` + To use a column with a different name than the match_field defined in the policy as the match field, use ON : +```esql ROW a = "1" | ENRICH languages_policy ON a +``` + By default, each of the enrich fields defined in the policy is added as a column. To explicitly select the enrich fields that are added, use WITH , , ...: +```esql ROW a = "1" | ENRICH languages_policy ON a WITH language_name +``` + You can rename the columns that are added using WITH new_name=: +```esql ROW a = "1" | ENRICH languages_policy ON a WITH name = language_name +``` + In case of name collisions, the newly created columns will override existing columns. \ No newline at end of file diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-eval.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-eval.txt index 23aa334bdbb71..fb11bfe545510 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-eval.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-eval.txt @@ -11,13 +11,18 @@ function. DescriptionThe EVAL processing command enables you to append new columns with calculated values. EVAL supports various functions for calculating values. Refer to Functions for more information.Examples +```esql FROM employees | SORT emp_no | KEEP first_name, last_name, height | EVAL height_feet = height * 3.281, height_cm = height * 100 +``` + If the specified column already exists, the existing column will be dropped, and the new column will be appended to the table: +```esql FROM employees | SORT emp_no | KEEP first_name, last_name, height | EVAL height = height * 3.281 +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-floor.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-floor.txt index b27997edd8bff..cb68b3277cdc3 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-floor.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-floor.txt @@ -2,8 +2,11 @@ FLOOR Round a number down to the nearest integer. +```esql ROW a=1.8 | EVAL a=FLOOR(a) +``` + This is a noop for long (including unsigned) and integer. For double this picks the the closest double value to the integer ala Math.floor. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-from.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-from.txt index 15a471cb44ead..f57f10de37c96 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-from.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-from.txt @@ -1,29 +1,57 @@ FROM Syntax +```esql FROM index_pattern [METADATA fields] +``` + Parameters index_pattern A list of indices, data streams or aliases. Supports wildcards and date math. fields A comma-separated list of metadata fields to retrieve. -DescriptionThe FROM source command returns a table with data from a data stream, index, +DescriptionThe +```esql +FROM source command returns a table with data from a data stream, index, +``` + or alias. Each row in the resulting table represents a document. Each column corresponds to a field, and can be accessed by the name of that field. By default, an ES|QL query without an explicit LIMIT uses an implicit -limit of 500. This applies to FROM too. A FROM command without LIMIT: +limit of 500. This applies to +```esql +FROM too. A FROM command without LIMIT: +``` + +```esql FROM employees +``` + is executed as: +```esql FROM employees | LIMIT 500 +``` + Examples +```esql FROM employees +``` + You can use date math to refer to indices, aliases and data streams. This can be useful for time series data, for example to access today’s index: +```esql FROM +``` + Use comma-separated lists or wildcards to query multiple data streams, indices, or aliases: +```esql FROM employees-00001,other-employees-* +``` + Use the METADATA directive to enable metadata fields: +```esql FROM employees [METADATA _id] +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-greatest.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-greatest.txt index 119ecd48edf4c..3a217abe2a0e4 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-greatest.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-greatest.txt @@ -3,8 +3,11 @@ GREATEST Returns the maximum value from many columns. This is similar to MV_MAX except it’s intended to run on multiple columns at once. +```esql ROW a = 10, b = 20 | EVAL g = GREATEST(a, b) +``` + When run on keyword or text fields, this’ll return the last string in alphabetical order. When run on boolean columns this will return true if any values are true. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-grok.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-grok.txt index 57d3cb32b7270..4b940e5c2c7f1 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-grok.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-grok.txt @@ -12,17 +12,25 @@ DescriptionGROK enables you to extract structured data out of a string. GROK matches the string against patterns, based on regular expressions, and extracts the specified patterns as columns.Refer to Process data with GROK for the syntax of grok patterns.ExamplesThe following example parses a string that contains a timestamp, an IP address, an email address, and a number: +```esql ROW a = "2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42" | GROK a "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num}" | KEEP date, ip, email, num +``` + By default, GROK outputs keyword string columns. int and float types can be converted by appending :type to the semantics in the pattern. For example {NUMBER:num:int}: +```esql ROW a = "2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42" | GROK a "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num:int}" | KEEP date, ip, email, num +``` + For other type conversions, use Type conversion functions: +```esql ROW a = "2023-01-23T12:15:00.000Z 127.0.0.1 some.email@foo.com 42" | GROK a "%{TIMESTAMP_ISO8601:date} %{IP:ip} %{EMAILADDRESS:email} %{NUMBER:num:int}" | KEEP date, ip, email, num | EVAL date = TO_DATETIME(date) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-keep.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-keep.txt index 466a421cb247a..287e079bb861c 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-keep.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-keep.txt @@ -6,14 +6,22 @@ Parameters columns:: A comma-separated list of columns to keep. Supports wildcards.DescriptionThe KEEP processing command enables you to specify what columns are returned and the order in which they are returned.ExamplesThe columns are returned in the specified order: +```esql FROM employees | KEEP emp_no, first_name, last_name, height +``` + Rather than specify each column by name, you can use wildcards to return all columns with a name that matches a pattern: +```esql FROM employees | KEEP h* +``` + The asterisk wildcard (*) by itself translates to all columns that do not match the other arguments. This query will first return all columns with a name that starts with h, followed by all other columns: +```esql FROM employees | KEEP h*, * +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-least.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-least.txt index d598679f84f57..949864ec07e4f 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-least.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-least.txt @@ -3,8 +3,11 @@ LEAST Returns the minimum value from many columns. This is similar to MV_MIN except it’s intended to run on multiple columns at once. +```esql ROW a = 10, b = 20 | EVAL l = LEAST(a, b) +``` + When run on keyword or text fields, this’ll return the first string in alphabetical order. When run on boolean columns this will return false if any values are false. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-left.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-left.txt index 2edc0378aa312..fea60895db137 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-left.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-left.txt @@ -2,9 +2,12 @@ LEFT Return the substring that extracts length chars from the string starting from the left. +```esql FROM employees | KEEP last_name | EVAL left = LEFT(last_name, 3) | SORT last_name ASC | LIMIT 5 +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-length.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-length.txt index 29e22edcb4176..b8a2ecf821e64 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-length.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-length.txt @@ -1,6 +1,8 @@ LENGTH Returns the character length of a string. +```esql FROM employees | KEEP first_name, last_name, height | EVAL fn_length = LENGTH(first_name) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-limit.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-limit.txt index 520b8e5547e9f..5ee1f5fd6999d 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-limit.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-limit.txt @@ -19,6 +19,8 @@ settings: esql.query.result_truncation_default_size esql.query.result_truncation_max_size Example +```esql FROM employees | SORT emp_no ASC | LIMIT 5 +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-log10.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-log10.txt index dabc5bc7c05c7..259ce71384a36 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-log10.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-log10.txt @@ -3,6 +3,9 @@ LOG10 Returns the log base 10. The input can be any numeric value, the return value is always a double.Logs of negative numbers are NaN. Logs of infinites are infinite, as is the log of 0. +```esql ROW d = 1000.0 | EVAL s = LOG10(d) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ltrim.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ltrim.txt index 350b0b1e369ba..d4d8e1c244a51 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ltrim.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-ltrim.txt @@ -2,9 +2,12 @@ LTRIM Removes leading whitespaces from strings. +```esql ROW message = " some text ", color = " red " | EVAL message = LTRIM(message) | EVAL color = LTRIM(color) | EVAL message = CONCAT("'", message, "'") | EVAL color = CONCAT("'", color, "'") +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-max.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-max.txt index 22b23e89c7438..eae40918c20eb 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-max.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-max.txt @@ -1,5 +1,7 @@ MAX The maximum value of a numeric field. +```esql FROM employees | STATS MAX(languages) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median.txt index df0aa45577b2e..84807da7a352d 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median.txt @@ -2,8 +2,11 @@ MEDIAN The value that is greater than half of all values and less than half of all values, also known as the 50% PERCENTILE. +```esql FROM employees | STATS MEDIAN(salary), PERCENTILE(salary, 50) +``` + Like PERCENTILE, MEDIAN is usually approximate. MEDIAN is also non-deterministic. This means you can get slightly different results using the same data. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median_absolute_deviation.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median_absolute_deviation.txt index bf7329c62fb3b..f05b04d62e497 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median_absolute_deviation.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-median_absolute_deviation.txt @@ -6,8 +6,11 @@ or may not be normally distributed. For such data it can be more descriptive tha standard deviation.It is calculated as the median of each data point’s deviation from the median of the entire sample. That is, for a random variable X, the median absolute deviation is median(|median(X) - Xi|). +```esql FROM employees | STATS MEDIAN(salary), MEDIAN_ABSOLUTE_DEVIATION(salary) +``` + Like PERCENTILE, MEDIAN_ABSOLUTE_DEVIATION is usually approximate. MEDIAN_ABSOLUTE_DEVIATION is also non-deterministic. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-min.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-min.txt index 97e021e3153ab..62ff3d7c6be86 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-min.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-min.txt @@ -1,5 +1,7 @@ MIN The minimum value of a numeric field. +```esql FROM employees | STATS MIN(languages) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_avg.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_avg.txt index ee144a77697df..554e0a50c7a59 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_avg.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_avg.txt @@ -2,6 +2,9 @@ MV_AVG Converts a multivalued field into a single valued field containing the average of all of the values. For example: +```esql ROW a=[3, 5, 1, 6] | EVAL avg_a = MV_AVG(a) +``` + The output type is always a double and the input type can be any number. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_concat.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_concat.txt index 1d579bee82a43..872234370fddb 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_concat.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_concat.txt @@ -3,9 +3,15 @@ MV_CONCAT Converts a multivalued string field into a single valued field containing the concatenation of all values separated by a delimiter: +```esql ROW a=["foo", "zoo", "bar"] | EVAL j = MV_CONCAT(a, ", ") +``` + If you want to concat non-string fields call TO_STRING on them first: +```esql ROW a=[10, 9, 8] | EVAL j = MV_CONCAT(TO_STRING(a), ", ") +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_count.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_count.txt index e6149e02c9fd9..e2e1884e76604 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_count.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_count.txt @@ -3,6 +3,9 @@ MV_COUNT Converts a multivalued field into a single valued field containing a count of the number of values: +```esql ROW a=["foo", "zoo", "bar"] | EVAL count_a = MV_COUNT(a) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_dedupe.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_dedupe.txt index e844e01bdc626..b5335d48506db 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_dedupe.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_dedupe.txt @@ -2,7 +2,10 @@ MV_DEDUPE Removes duplicates from a multivalued field. For example: +```esql ROW a=["foo", "foo", "bar", "foo"] | EVAL dedupe_a = MV_DEDUPE(a) +``` + Supported types: MV_DEDUPE may, but won’t always, sort the values in the field. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_expand.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_expand.txt index b8e757914b0b0..5125367fbc21d 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_expand.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_expand.txt @@ -7,5 +7,7 @@ column The multivalued column to expand. DescriptionThe MV_EXPAND processing command expands multivalued columns into one row per value, duplicating other columns.Example +```esql ROW a=[1,2,3], b="b", j=["a","b"] | MV_EXPAND a +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_max.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_max.txt index 91ff991dfcb42..430f23b27c43a 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_max.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_max.txt @@ -2,10 +2,16 @@ MV_MAX Converts a multivalued field into a single valued field containing the maximum value. For example: +```esql ROW a=[3, 5, 1] | EVAL max_a = MV_MAX(a) +``` + It can be used by any field type, including keyword fields. In that case picks the last string, comparing their utf-8 representation byte by byte: +```esql ROW a=["foo", "zoo", "bar"] | EVAL max_a = MV_MAX(a) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_median.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_median.txt index 293e86b022c5d..63ab2329d9ebb 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_median.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_median.txt @@ -1,10 +1,15 @@ MV_MEDIAN Converts a multivalued field into a single valued field containing the median value. For example: +```esql ROW a=[3, 5, 1] | EVAL median_a = MV_MEDIAN(a) +``` + It can be used by any numeric field type and returns a value of the same type. If the row has an even number of values for a column the result will be the average of the middle two entries. If the field is not floating point then the average rounds down: +```esql ROW a=[3, 7, 1, 6] | EVAL median_a = MV_MEDIAN(a) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_min.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_min.txt index 577464825cd72..1179f61d280d6 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_min.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_min.txt @@ -2,10 +2,16 @@ MV_MIN Converts a multivalued field into a single valued field containing the minimum value. For example: +```esql ROW a=[2, 1] | EVAL min_a = MV_MIN(a) +``` + It can be used by any field type, including keyword fields. In that case picks the first string, comparing their utf-8 representation byte by byte: +```esql ROW a=["foo", "bar"] | EVAL min_a = MV_MIN(a) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_sum.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_sum.txt index 34973728b2710..f6b6fdecc6130 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_sum.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-mv_sum.txt @@ -2,6 +2,9 @@ MV_SUM Converts a multivalued field into a single valued field containing the sum of all of the values. For example: +```esql ROW a=[3, 5, 6] | EVAL sum_a = MV_SUM(a) +``` + The input type can be any number and the output type is the same as the input type. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-now.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-now.txt index 2145d6b17add7..ccff8a884b0e6 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-now.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-now.txt @@ -1,4 +1,6 @@ NOW Returns current date and time. +```esql ROW current_date = NOW() +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-numeric-fields.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-numeric-fields.txt deleted file mode 100644 index f08b10515aa55..0000000000000 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-numeric-fields.txt +++ /dev/null @@ -1,12 +0,0 @@ -Numeric fields - -auto_bucket can also operate on numeric fields like this: -FROM employees -| WHERE hire_date >= "1985-01-01T00:00:00Z" AND hire_date < "1986-01-01T00:00:00Z" -| EVAL bs = AUTO_BUCKET(salary, 20, 25324, 74999) -| SORT hire_date, salary -| KEEP hire_date, salary, bs -Unlike the example above where you are intentionally filtering on a date range, -you rarely want to filter on a numeric range. So you have find the min and max -separately. We don’t yet have an easy way to do that automatically. Improvements -coming! \ No newline at end of file diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-operators.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-operators.txt index dc1eca3a0fc5c..708fa25b2eae1 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-operators.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-operators.txt @@ -86,24 +86,37 @@ IS NULL and IS NOT NULL predicates IS NULL and IS NOT NULL predicates For NULL comparison, use the IS NULL and IS NOT NULL predicates: +```esql FROM employees | WHERE birth_date IS NULL | KEEP first_name, last_name | SORT first_name | LIMIT 3 +``` + +```esql FROM employees | WHERE is_rehired IS NOT NULL | STATS COUNT(emp_no) +``` CIDR_MATCH CIDR_MATCH -Returns true if the provided IP is contained in one of the provided CIDR -blocks.CIDR_MATCH accepts two or more arguments. The first argument is the IP -address of type ip (both IPv4 and IPv6 are supported). Subsequent arguments -are the CIDR blocks to test the IP against. +Syntax +CIDR_MATCH(ip, block1[, ..., blockN]) +Parameters +ip +IP address of type ip (both IPv4 and IPv6 are supported). +blockX +CIDR block to test the IP against. +DescriptionReturns true if the provided IP is contained in one of the provided CIDR +blocks.Example +```esql FROM hosts -| WHERE CIDR_MATCH(ip, "127.0.0.2/32", "127.0.0.3/32") +| WHERE CIDR_MATCH(ip1, "127.0.0.2/32", "127.0.0.3/32") +| KEEP card, host, ip0, ip1 +``` ENDS_WITH ENDS_WITH @@ -111,9 +124,12 @@ ENDS_WITH Returns a boolean that indicates whether a keyword string ends with another string: +```esql FROM employees | KEEP last_name | EVAL ln_E = ENDS_WITH(last_name, "d") +``` + Supported types: IN @@ -121,12 +137,16 @@ IN The IN operator allows testing whether a field or expression equals an element in a list of literals, fields or expressions: +```esql ROW a = 1, b = 4, c = 3 | WHERE c-a IN (3, b / 2, a) +``` Returns a boolean that indicates whether its input is not a number. +```esql ROW d = 1.0 | EVAL s = IS_NAN(d) +``` LIKE LIKE @@ -137,9 +157,11 @@ also act on a constant (literal) expression. The right-hand side of the operator represents the pattern.The following wildcard characters are supported: * matches zero or more characters. ? matches one character. +```esql FROM employees | WHERE first_name LIKE "?b*" | KEEP first_name, last_name +``` RLIKE RLIKE @@ -148,9 +170,11 @@ Use RLIKE to filter data based on string patterns using using regular expressions. RLIKE usually acts on a field placed on the left-hand side of the operator, but it can also act on a constant (literal) expression. The right-hand side of the operator represents the pattern. +```esql FROM employees | WHERE first_name RLIKE ".leja.*" | KEEP first_name, last_name +``` STARTS_WITH STARTS_WITH @@ -158,7 +182,10 @@ STARTS_WITH Returns a boolean that indicates whether a keyword string starts with another string: +```esql FROM employees | KEEP last_name | EVAL ln_S = STARTS_WITH(last_name, "B") +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-percentile.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-percentile.txt index 432990415fc94..662fa3a611a35 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-percentile.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-percentile.txt @@ -3,10 +3,13 @@ PERCENTILE The value at which a certain percentage of observed values occur. For example, the 95th percentile is the value which is greater than 95% of the observed values and the 50th percentile is the MEDIAN. +```esql FROM employees | STATS p0 = PERCENTILE(salary, 0) , p50 = PERCENTILE(salary, 50) , p99 = PERCENTILE(salary, 99) +``` + PERCENTILE is (usually) approximateeditThere are many different algorithms to calculate percentiles. The naive implementation simply stores all the values in a sorted array. To find the 50th percentile, you simply find the value that is at my_array[count(my_array) * 0.5].Clearly, the naive implementation does not scale — the sorted array grows diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pi.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pi.txt index 169af57566903..ade48755e280c 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pi.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pi.txt @@ -2,4 +2,6 @@ PI The ratio of a circle’s circumference to its diameter. +```esql ROW PI() +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pow.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pow.txt index d74c58b7e0b6a..56f1e48b73833 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pow.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-pow.txt @@ -4,10 +4,16 @@ POW Returns the value of a base (first argument) raised to the power of an exponent (second argument). Both arguments must be numeric. The output is always a double. Note that it is still possible to overflow a double result here; in that case, null will be returned. +```esql ROW base = 2.0, exponent = 2 | EVAL result = POW(base, exponent) +``` + Fractional exponentseditThe exponent can be a fraction, which is similar to performing a root. For example, the exponent of 0.5 will give the square root of the base: +```esql ROW base = 4, exponent = 0.5 | EVAL s = POW(base, exponent) +``` + Table of supported input and output typeseditFor clarity, the following table describes the output result type for all combinations of numeric input types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rename.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rename.txt index 27ca77b68d0fd..496db07019b7c 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rename.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rename.txt @@ -9,10 +9,15 @@ new_nameX The new name of the column. DescriptionThe RENAME processing command renames one or more columns. If a column with the new name already exists, it will be replaced by the new column.Examples +```esql FROM employees | KEEP first_name, last_name, still_hired | RENAME still_hired AS employed +``` + Multiple columns can be renamed with a single RENAME command: +```esql FROM employees | KEEP first_name, last_name | RENAME first_name AS fn, last_name AS ln +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-replace.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-replace.txt index cf9102ab9471e..859f031fd6398 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-replace.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-replace.txt @@ -2,6 +2,8 @@ REPLACE The function substitutes in the string (1st argument) any match of the regular expression (2nd argument) with the replacement string (3rd argument).If any of the arguments are NULL, the result is NULL. This example replaces an occurrence of the word "World" with the word "Universe": +```esql ROW str = "Hello World" | EVAL str = REPLACE(str, "World", "Universe") | KEEP str +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-right.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-right.txt index 2cd30d32cd7c1..b2e8fd12d3c2c 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-right.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-right.txt @@ -2,9 +2,12 @@ RIGHT Return the substring that extracts length chars from the string starting from the right. +```esql FROM employees | KEEP last_name | EVAL right = RIGHT(last_name, 3) | SORT last_name ASC | LIMIT 5 +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-round.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-round.txt index 8ecb92ecc81be..1047425f67147 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-round.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-round.txt @@ -3,6 +3,8 @@ ROUND Rounds a number to the closest number with the specified number of digits. Defaults to 0 digits if no number of digits is provided. If the specified number of digits is negative, rounds to the number of digits left of the decimal point. +```esql FROM employees | KEEP first_name, last_name, height | EVAL height_ft = ROUND(height * 3.281, 1) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-row.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-row.txt index fa57a1bcc5660..8f60bd96b6bea 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-row.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-row.txt @@ -1,17 +1,35 @@ ROW Syntax +```esql ROW column1 = value1[, ..., columnN = valueN] +``` + Parameters columnX The column name. valueX The value for the column. Can be a literal, an expression, or a function. -DescriptionThe ROW source command produces a row with one or more columns with values +DescriptionThe +```esql +ROW source command produces a row with one or more columns with values +``` + that you specify. This can be useful for testing.Examples +```esql ROW a = 1, b = "two", c = null +``` + Use square brackets to create multi-value columns: +```esql ROW a = [2, 1] +``` + +```esql ROW supports the use of functions: +``` + +```esql ROW a = ROUND(1.23, 0) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rtrim.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rtrim.txt index 63b6c428cadf2..d25ec734fca79 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rtrim.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-rtrim.txt @@ -2,9 +2,12 @@ RTRIM Removes trailing whitespaces from strings. +```esql ROW message = " some text ", color = " red " | EVAL message = RTRIM(message) | EVAL color = RTRIM(color) | EVAL message = CONCAT("'", message, "'") | EVAL color = CONCAT("'", color, "'") +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-show.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-show.txt index cb7fab0300435..dc6b80b9eba49 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-show.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-show.txt @@ -1,15 +1,32 @@ SHOW Syntax +```esql SHOW item +``` + Parameters item Can be INFO or FUNCTIONS. -DescriptionThe SHOW source command returns information about the deployment and +DescriptionThe +```esql +SHOW source command returns information about the deployment and +``` + its capabilities: -Use SHOW INFO to return the deployment’s version, build date and hash. -Use SHOW FUNCTIONS to return a list of all supported functions and a +Use +```esql +SHOW INFO to return the deployment’s version, build date and hash. +``` + +Use +```esql +SHOW FUNCTIONS to return a list of all supported functions and a +``` + synopsis of each function. Examples +```esql SHOW functions | WHERE STARTS_WITH(name, "is_") +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sin.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sin.txt index 1c64c76791ea8..b0e05c95cb186 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sin.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sin.txt @@ -2,6 +2,9 @@ SIN Sine trigonometric function. Input expected in radians. +```esql ROW a=1.8 | EVAL sin=SIN(a) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sinh.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sinh.txt index 7a9d8a0bbcab7..dfa5f203d8f16 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sinh.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sinh.txt @@ -2,6 +2,9 @@ SINH Sine hyperbolic function. +```esql ROW a=1.8 | EVAL sinh=SINH(a) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sort.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sort.txt index e1838ca567241..1f9d4c2527cd8 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sort.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sort.txt @@ -12,18 +12,29 @@ the highest value when sorting descending.By default, null values are treated as an ascending sort order, null values are sorted last, and with a descending sort order, null values are sorted first. You can change that by providing NULLS FIRST or NULLS LAST.Examples +```esql FROM employees | KEEP first_name, last_name, height | SORT height +``` + Explicitly sorting in ascending order with ASC: +```esql FROM employees | KEEP first_name, last_name, height | SORT height DESC +``` + Providing additional sort expressions to act as tie breakers: +```esql FROM employees | KEEP first_name, last_name, height | SORT height DESC, first_name ASC +``` + Sorting null values first using NULLS FIRST: +```esql FROM employees | KEEP first_name, last_name, height | SORT first_name ASC NULLS FIRST +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-split.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-split.txt index 8dbd7e74731e1..834f8a10507ef 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-split.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-split.txt @@ -1,7 +1,10 @@ SPLIT Split a single valued string into multiple strings. For example: +```esql ROW words="foo;bar;baz;qux;quux;corge" | EVAL word = SPLIT(words, ";") +``` + Which splits "foo;bar;baz;qux;quux;corge" on ; and returns an array: Only single byte delimiters are currently supported. diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sqrt.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sqrt.txt index 6b5c8a56a0d43..0fef30ccbdf5d 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sqrt.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sqrt.txt @@ -3,6 +3,9 @@ SQRT Returns the square root of a number. The input can be any numeric value, the return value is always a double.Square roots of negative numbers are NaN. Square roots of infinites are infinite. +```esql ROW d = 100.0 | EVAL s = SQRT(d) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-stats.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-stats.txt index 2a1edb4966d15..971befa8d5626 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-stats.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-stats.txt @@ -31,20 +31,31 @@ Grouping on a single column is currently much more optimized than grouping something like CONCAT and then grouping - that is not going to be faster. ExamplesCalculating a statistic and grouping by the values of another column: +```esql FROM employees | STATS count = COUNT(emp_no) BY languages | SORT languages +``` + Omitting BY returns one row with the aggregations applied over the entire dataset: +```esql FROM employees | STATS avg_lang = AVG(languages) +``` + It’s possible to calculate multiple values: +```esql FROM employees | STATS avg_lang = AVG(languages), max_lang = MAX(languages) +``` + It’s also possible to group by multiple values (only supported for long and keyword family fields): +```esql FROM employees | EVAL hired = DATE_FORMAT("YYYY", hire_date) | STATS avg_salary = AVG(salary) BY hired, languages.long | EVAL avg_salary = ROUND(avg_salary) | SORT hired, languages.long +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-substring.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-substring.txt index a113ad838cc8a..e4a2460485810 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-substring.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-substring.txt @@ -2,16 +2,24 @@ SUBSTRING Returns a substring of a string, specified by a start position and an optional length. This example returns the first three characters of every last name: +```esql FROM employees | KEEP last_name | EVAL ln_sub = SUBSTRING(last_name, 1, 3) +``` + A negative start position is interpreted as being relative to the end of the string. This example returns the last three characters of of every last name: +```esql FROM employees | KEEP last_name | EVAL ln_sub = SUBSTRING(last_name, -3, 3) +``` + If length is omitted, substring returns the remainder of the string. This example returns all characters except for the first: +```esql FROM employees | KEEP last_name | EVAL ln_sub = SUBSTRING(last_name, 2) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sum.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sum.txt index bc24875fce219..36686979ebed6 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sum.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-sum.txt @@ -1,5 +1,7 @@ SUM The sum of a numeric field. +```esql FROM employees | STATS SUM(languages) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-syntax.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-syntax.txt index 8656c63f308f3..7ad197c9480f5 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-syntax.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-syntax.txt @@ -27,24 +27,36 @@ expressions - require quoting if the identifier contains characters other than letters, numbers and `_` and doesn’t start with a letter, `_` or `@`. For instance: // Retain just one field +```esql FROM index | KEEP 1.field +``` + is legal. However, if same field is to be used with an EVAL, it’d have to be quoted: // Copy one field +```esql FROM index | EVAL my_field = `1.field` +``` + Literalsedit ES|QL currently supports numeric and string literals. String literalsedit A string literal is a sequence of unicode characters delimited by double quotes (`"`). // Filter by a string value +```esql FROM index | WHERE first_name == "Georgi" +``` + If the literal string itself contains quotes, these need to be escaped (`\\"`). ES|QL also supports the triple-quotes (`"""`) delimiter, for convenience: +```esql ROW name = """Indiana "Indy" Jones""" +``` + The special characters CR, LF and TAB can be provided with the usual escaping: `\r`, `\n`, `\t`, respectively. Numerical literalsedit @@ -67,11 +79,20 @@ ES|QL uses C++ style comments: double slash `//` for single line comments `/*` and `*/` for block comments // Query the employees index +```esql FROM employees | WHERE height > 2 +``` + +```esql FROM /* Query the employees index */ employees | WHERE height > 2 +``` + +```esql FROM employees +``` + /* Query the * employees * index */ diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tan.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tan.txt index 63b752c8c6248..5706ad3a77f91 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tan.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tan.txt @@ -2,6 +2,9 @@ TAN Tangent trigonometric function. Input expected in radians. +```esql ROW a=1.8 | EVAL tan=TAN(a) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tanh.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tanh.txt index 83493cec93984..02391cb32bf46 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tanh.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tanh.txt @@ -2,6 +2,9 @@ TANH Tangent hyperbolic function. +```esql ROW a=1.8 | EVAL tanh=TANH(a) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tau.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tau.txt index b60a1bde563d2..600c43f47ccf9 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tau.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-tau.txt @@ -2,4 +2,6 @@ TAU The ratio of a circle’s circumference to its radius. +```esql ROW TAU() +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_boolean.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_boolean.txt index a6259f436f076..498f40679b129 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_boolean.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_boolean.txt @@ -4,7 +4,10 @@ Converts an input value to a boolean value.The input can be a single- or multi-v type must be of a string or numeric type.A string value of "true" will be case-insensitive converted to the Boolean true. For anything else, including the empty string, the function will return false. For example: +```esql ROW str = ["true", "TRuE", "false", "", "yes", "1"] | EVAL bool = TO_BOOLEAN(str) +``` + The numerical value of 0 will be converted to false, anything else will be converted to true.Alias: TO_BOOL \ No newline at end of file diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_datetime.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_datetime.txt index d985309c75c62..534175b0824fd 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_datetime.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_datetime.txt @@ -3,8 +3,11 @@ TO_DATETIME Converts an input value to a date value.The input can be a single- or multi-valued field or an expression. The input type must be of a string or numeric type.A string will only be successfully converted if it’s respecting the format yyyy-MM-dd'T'HH:mm:ss.SSS'Z' (to convert dates in other formats, use DATE_PARSE). For example: +```esql ROW string = ["1953-09-02T00:00:00.000Z", "1964-06-02T00:00:00.000Z", "1964-06-02 00:00:00"] | EVAL datetime = TO_DATETIME(string) +``` + Note that in this example, the last value in the source multi-valued field has not been converted. The reason being that if the date format is not respected, the conversion will result in a null value. When this happens a @@ -12,6 +15,9 @@ Warning header is added to the response. The header will provide information on the source of the failure:"Line 1:112: evaluation of [TO_DATETIME(string)] failed, treating result as null. Only first 20 failures recorded."A following header will contain the failure reason and the offending value:"java.lang.IllegalArgumentException: failed to parse date field [1964-06-02 00:00:00] with format [yyyy-MM-dd'T'HH:mm:ss.SSS'Z']"If the input parameter is of a numeric type, its value will be interpreted as milliseconds since the Unix epoch. For example: +```esql ROW int = [0, 1] | EVAL dt = TO_DATETIME(int) +``` + Alias: TO_DT \ No newline at end of file diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_degrees.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_degrees.txt index e6df993088477..ed433509bae03 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_degrees.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_degrees.txt @@ -3,5 +3,7 @@ TO_DEGREES Converts a number in radians to degrees.The input can be a single- or multi-valued field or an expression. The input type must be of a numeric type and result is always double.Example: +```esql ROW rad = [1.57, 3.14, 4.71] | EVAL deg = TO_DEGREES(rad) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_double.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_double.txt index 2e1dd75654abe..c5890745988b1 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_double.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_double.txt @@ -2,8 +2,11 @@ TO_DOUBLE Converts an input value to a double value.The input can be a single- or multi-valued field or an expression. The input type must be of a boolean, date, string or numeric type.Example: +```esql ROW str1 = "5.20128E11", str2 = "foo" | EVAL dbl = TO_DOUBLE("520128000000"), dbl1 = TO_DOUBLE(str1), dbl2 = TO_DOUBLE(str2) +``` + Note that in this example, the last conversion of the string isn’t possible. When this happens, the result is a null value. In this case a Warning header is added to the response. The header will provide information diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_integer.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_integer.txt index eab5669791922..e1a43e83e3995 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_integer.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_integer.txt @@ -2,8 +2,11 @@ TO_INTEGER Converts an input value to an integer value.The input can be a single- or multi-valued field or an expression. The input type must be of a boolean, date, string or numeric type.Example: +```esql ROW long = [5013792, 2147483647, 501379200000] | EVAL int = TO_INTEGER(long) +``` + Note that in this example, the last value of the multi-valued field cannot be converted as an integer. When this happens, the result is a null value. In this case a Warning header is added to the response. The header will diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_ip.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_ip.txt index 0e8f2fd1274a1..23c8422170cfc 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_ip.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_ip.txt @@ -1,9 +1,12 @@ TO_IP Converts an input string to an IP value.The input can be a single- or multi-valued field or an expression.Example: +```esql ROW str1 = "1.1.1.1", str2 = "foo" | EVAL ip1 = TO_IP(str1), ip2 = TO_IP(str2) | WHERE CIDR_MATCH(ip1, "1.0.0.0/8") +``` + Note that in the example above the last conversion of the string isn’t possible. When this happens, the result is a null value. In this case a Warning header is added to the response. The header will provide information diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_long.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_long.txt index 37a73209c7043..802c09d7cf35d 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_long.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_long.txt @@ -2,8 +2,11 @@ TO_LONG Converts an input value to a long value.The input can be a single- or multi-valued field or an expression. The input type must be of a boolean, date, string or numeric type.Example: +```esql ROW str1 = "2147483648", str2 = "2147483648.2", str3 = "foo" | EVAL long1 = TO_LONG(str1), long2 = TO_LONG(str2), long3 = TO_LONG(str3) +``` + Note that in this example, the last conversion of the string isn’t possible. When this happens, the result is a null value. In this case a Warning header is added to the response. The header will provide information diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_radians.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_radians.txt index d0118e1fa0271..9b40d70c52bc8 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_radians.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_radians.txt @@ -3,5 +3,7 @@ TO_RADIANS Converts a number in degrees to radians.The input can be a single- or multi-valued field or an expression. The input type must be of a numeric type and result is always double.Example: +```esql ROW deg = [90.0, 180.0, 270.0] | EVAL rad = TO_RADIANS(deg) +``` diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_string.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_string.txt index 4cb34acc5e054..ec08289046414 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_string.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_string.txt @@ -2,9 +2,15 @@ TO_STRING Converts a field into a string. For example: +```esql ROW a=10 | EVAL j = TO_STRING(a) +``` + It also works fine on multivalued fields: +```esql ROW a=[10, 9, 8] | EVAL j = TO_STRING(a) +``` + Alias: TO_STRSupported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_unsigned_long.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_unsigned_long.txt index ae42a582079b3..22c8a680c8c5b 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_unsigned_long.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_unsigned_long.txt @@ -2,8 +2,11 @@ TO_UNSIGNED_LONG Converts an input value to an unsigned long value.The input can be a single- or multi-valued field or an expression. The input type must be of a boolean, date, string or numeric type.Example: +```esql ROW str1 = "2147483648", str2 = "2147483648.2", str3 = "foo" | EVAL long1 = TO_UNSIGNED_LONG(str1), long2 = TO_ULONG(str2), long3 = TO_UL(str3) +``` + Note that in this example, the last conversion of the string isn’t possible. When this happens, the result is a null value. In this case a Warning header is added to the response. The header will provide information diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_version.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_version.txt index 84ec4214c6279..9e95474fecd05 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_version.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-to_version.txt @@ -2,5 +2,8 @@ TO_VERSION Converts an input string to a version value. For example: +```esql ROW v = TO_VERSION("1.2.3") +``` + The input can be a single- or multi-valued field or an expression.Alias: TO_VERSupported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-trim.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-trim.txt index 5a7e51b0aa2ff..91910162681d9 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-trim.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-trim.txt @@ -2,7 +2,10 @@ TRIM Removes leading and trailing whitespaces from strings. +```esql ROW message = " some text ", color = " red " | EVAL message = TRIM(message) | EVAL color = TRIM(color) +``` + Supported types: diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-where.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-where.txt index f03e351e933f8..49343c329fbcc 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-where.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/esql_docs/esql-where.txt @@ -7,45 +7,69 @@ expression A boolean expression. DescriptionThe WHERE processing command produces a table that contains all the rows from the input table for which the provided condition evaluates to true.Examples +```esql FROM employees | KEEP first_name, last_name, still_hired | WHERE still_hired == true +``` + Which, if still_hired is a boolean field, can be simplified to: +```esql FROM employees | KEEP first_name, last_name, still_hired | WHERE still_hired +``` + WHERE supports various functions. For example the LENGTH function: +```esql FROM employees | KEEP first_name, last_name, height | WHERE LENGTH(first_name) < 4 +``` + For a complete list of all functions, refer to Functions and operators.For NULL comparison, use the IS NULL and IS NOT NULL predicates: +```esql FROM employees | WHERE birth_date IS NULL | KEEP first_name, last_name | SORT first_name | LIMIT 3 +``` + +```esql FROM employees | WHERE is_rehired IS NOT NULL | STATS COUNT(emp_no) +``` + Use LIKE to filter data based on string patterns using wildcards. LIKE usually acts on a field placed on the left-hand side of the operator, but it can also act on a constant (literal) expression. The right-hand side of the operator represents the pattern.The following wildcard characters are supported: * matches zero or more characters. ? matches one character. +```esql FROM employees | WHERE first_name LIKE "?b*" | KEEP first_name, last_name +``` + Use RLIKE to filter data based on string patterns using using regular expressions. RLIKE usually acts on a field placed on the left-hand side of the operator, but it can also act on a constant (literal) expression. The right-hand side of the operator represents the pattern. +```esql FROM employees | WHERE first_name RLIKE ".leja.*" | KEEP first_name, last_name +``` + The IN operator allows testing whether a field or expression equals an element in a list of literals, fields or expressions: +```esql ROW a = 1, b = 4, c = 3 | WHERE c-a IN (3, b / 2, a) +``` + For a complete list of all operators, refer to Operators. \ No newline at end of file diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/index.ts b/x-pack/plugins/observability_ai_assistant/server/functions/esql/index.ts index 5aea8913bf115..41beb01c5af62 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/index.ts @@ -72,7 +72,7 @@ export function registerEsqlFunction({ name: 'execute_query', contexts: ['core'], visibility: FunctionVisibility.User, - description: 'Execute an ES|QL query', + description: 'Execute an ES|QL query.', parameters: { type: 'object', additionalProperties: false, @@ -129,14 +129,36 @@ export function registerEsqlFunction({ const source$ = streamIntoObservable( await client.chat({ connectorId, - messages: withEsqlSystemMessage(), + messages: withEsqlSystemMessage( + `Use the classify_esql function to classify the user's request + and get more information about specific functions and commands + you think are candidates for answering the question. + + + Examples for functions and commands: + Do you need to group data? Request \`STATS\`. + Extract data? Request \`DISSECT\` AND \`GROK\`. + Convert a column based on a set of conditionals? Request \`EVAL\` and \`CASE\`. + + Examples for determining whether the user wants to execute a query: + - "Show me the avg of x" + - "Give me the results of y" + - "Display the sum of z" + + Examples for determining whether the user does not want to execute a query: + - "I want a query that ..." + - "... Just show me the query" + - "Create a query that ..."` + ), signal, stream: true, functions: [ { - name: 'get_esql_info', - description: - 'Use this function to get more information about syntax, commands and examples. Take a deep breath and reason about what commands and functions you expect to use. Do you need to group data? Request `STATS`. Extract data? Request `DISSECT` AND `GROK`. Convert a column based on a set of conditionals? Request `EVAL` and `CASE`.', + name: 'classify_esql', + description: `Use this function to determine: + - what ES|QL functions and commands are candidates for answering the user's question + - whether the user has requested a query, and if so, it they want it to be executed, or just shown. + `, parameters: { type: 'object', properties: { @@ -154,12 +176,17 @@ export function registerEsqlFunction({ }, description: 'A list of functions.', }, + execute: { + type: 'boolean', + description: + 'Whether the user wants to execute a query (true) or just wants the query to be displayed (false)', + }, }, - required: ['commands', 'functions'], + required: ['commands', 'functions', 'execute'], }, }, ], - functionCall: 'get_esql_info', + functionCall: 'classify_esql', }) ).pipe(processOpenAiStream(), concatenateOpenAiChunks()); @@ -168,6 +195,7 @@ export function registerEsqlFunction({ const args = JSON.parse(response.message.function_call.arguments) as { commands: string[]; functions: string[]; + execute: boolean; }; const keywords = args.commands.concat(args.functions).concat('SYNTAX').concat('OVERVIEW'); @@ -254,7 +282,6 @@ export function registerEsqlFunction({ }, ], connectorId, - functions: [], signal, stream: true, }) @@ -294,6 +321,30 @@ export function registerEsqlFunction({ ], }); } + + const esqlQuery = cachedContent.match(/```esql([\s\S]*?)```/)?.[1]; + + if (esqlQuery && args.execute) { + subscriber.next({ + created: 0, + id: '', + model: '', + object: 'chat.completion.chunk', + choices: [ + { + delta: { + function_call: { + name: 'execute_query', + arguments: JSON.stringify({ query: esqlQuery }), + }, + }, + index: 0, + finish_reason: null, + }, + ], + }); + } + subscriber.complete(); }, error: (error) => { diff --git a/x-pack/plugins/observability_ai_assistant/server/functions/esql/system_message.txt b/x-pack/plugins/observability_ai_assistant/server/functions/esql/system_message.txt index 7dca13c490180..d9ce66038f170 100644 --- a/x-pack/plugins/observability_ai_assistant/server/functions/esql/system_message.txt +++ b/x-pack/plugins/observability_ai_assistant/server/functions/esql/system_message.txt @@ -11,9 +11,8 @@ processing. This source command is then followed by one or more processing commands, which can transform the data returned by the previous command. -ES|QL is not Elasticsearch SQL, nor is it anything like SQL. SQL -commands are not available in ES|QL. Make sure you write a query -using ONLY commands specified in this conversation. +Make sure you write a query using ONLY commands specified in this +conversation. # Syntax @@ -168,6 +167,7 @@ one or more aggregated values over the grouped rows. This commands only Here are some example queries: +```esql FROM employees | WHERE still_hired == true | EVAL hired = DATE_FORMAT("YYYY", hire_date) @@ -179,34 +179,48 @@ FROM employees | KEEP avg_salary, lang | SORT avg_salary ASC | LIMIT 3 +``` +```esql FROM employees | EVAL trunk_worked_seconds = avg_worked_seconds / 100000000 * 100000000 | STATS c = count(languages.long) BY languages.long, trunk_worked_seconds | SORT c desc, languages.long, trunk_worked_seconds +``` +```esql ROW a = "2023-01-23T12:15:00.000Z - some text - 127.0.0.1" | DISSECT a "%{date} - %{msg} - %{ip}" | KEEP date, msg, ip | EVAL date = TO_DATETIME(date) +``` +```esql FROM employees | WHERE first_name LIKE "?b*" | KEEP first_name, last_name +``` +```esql FROM employees | WHERE hire_date >= "1985-01-01T00:00:00Z" AND hire_date < "1986-01-01T00:00:00Z" | EVAL bucket = AUTO_BUCKET(hire_date, 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") | STATS AVG(salary) BY bucket | SORT bucket +``` +```esql ROW a = 1, b = "two", c = null +``` +```esql FROM employees | EVAL is_recent_hire = CASE(hire_date <= "2023-01-01T00:00:00Z", 1, 0) | STATS total_recent_hires = SUM(is_recent_hire), total_hires = COUNT(*) BY country | EVAL recent_hiring_rate = total_recent_hires / total_hires +``` +```esql FROM logs-* | WHERE @timestamp <= NOW() - 24 hours // divide data in 1 hour buckets @@ -217,4 +231,4 @@ FROM logs-* | STATS total_events = COUNT(*), total_failures = SUM(is_5xx) BY host.hostname, bucket | EVAL failure_rate_per_host = total_failures / total_events | DROP total_events, total_failures - +``` diff --git a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts index f8da02ad0666d..b9680d6472691 100644 --- a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts +++ b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts @@ -33,6 +33,9 @@ export const EMPTY_RESPONSE: RuleRegistrySearchResponse = { export const RULE_SEARCH_STRATEGY_NAME = 'privateRuleRegistryAlertsSearchStrategy'; +// these are deprecated types should never show up in any alert table +const EXCLUDED_RULE_TYPE_IDS = ['siem.notifications']; + export const ruleRegistrySearchStrategyProvider = ( data: PluginStart, alerting: AlertingStart, @@ -85,14 +88,16 @@ export const ruleRegistrySearchStrategyProvider = ( featureIds.length > 0 ? await authorization.getAuthorizedRuleTypes(AlertingAuthorizationEntity.Alert, fIds) : []; + return { space, authzFilter, authorizedRuleTypes }; }; return from(getAsync(request.featureIds)).pipe( mergeMap(({ space, authzFilter, authorizedRuleTypes }) => { - const indices = alerting.getAlertIndicesAlias( - authorizedRuleTypes.map((art: { id: any }) => art.id), - space?.id + const allRuleTypes = authorizedRuleTypes.map((art: { id: string }) => art.id); + const ruleTypes = (allRuleTypes ?? []).filter( + (ruleTypeId: string) => !EXCLUDED_RULE_TYPE_IDS.includes(ruleTypeId) ); + const indices = alerting.getAlertIndicesAlias(ruleTypes, space?.id); if (indices.length === 0) { return of(EMPTY_RESPONSE); } diff --git a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_key_flyout.tsx b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_key_flyout.tsx index d2346147da3d1..18bc6db281939 100644 --- a/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_key_flyout.tsx +++ b/x-pack/plugins/security/public/management/api_keys/api_keys_grid/api_key_flyout.tsx @@ -18,28 +18,31 @@ import { EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, - EuiFormFieldset, EuiFormRow, EuiHorizontalRule, + EuiIcon, + EuiPanel, EuiSkeletonText, EuiSpacer, EuiSwitch, EuiText, EuiTitle, + useEuiTheme, } from '@elastic/eui'; import { Form, FormikProvider, useFormik } from 'formik'; import moment from 'moment-timezone'; import type { FunctionComponent } from 'react'; -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import useAsyncFn from 'react-use/lib/useAsyncFn'; import { CodeEditorField } from '@kbn/code-editor'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; +import { FormattedDate, FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import type { KibanaServerError } from '@kbn/kibana-utils-plugin/public'; import type { CategorizedApiKey } from './api_keys_grid_page'; -import { ApiKeyBadge, ApiKeyStatus, TimeToolTip, UsernameWithIcon } from './api_keys_grid_page'; +import { ApiKeyBadge, ApiKeyStatus, TimeToolTip } from './api_keys_grid_page'; import type { ApiKeyRoleDescriptors } from '../../../../common/model'; import { DocLink } from '../../../components/doc_link'; import { FormField } from '../../../components/form_field'; @@ -56,6 +59,27 @@ import type { UpdateAPIKeyResult, } from '../api_keys_api_client'; +const TypeLabel = () => ( + +); + +const NameLabel = () => ( + +); + +const invalidJsonError = i18n.translate( + 'xpack.security.management.apiKeys.apiKeyFlyout.invalidJsonError', + { + defaultMessage: 'Enter valid JSON.', + } +); + export interface ApiKeyFormValues { name: string; type: string; @@ -89,10 +113,10 @@ export type ApiKeyFlyoutProps = ExclusiveUnion = ({ canManageCrossClusterApiKeys = false, readOnly = false, }) => { + const { euiTheme } = useEuiTheme(); const { services } = useKibana(); const { value: currentUser, loading: isLoadingCurrentUser } = useCurrentUser(); const [{ value: roles, loading: isLoadingRoles }, getRoles] = useAsyncFn( () => new RolesAPIClient(services.http!).getRoles(), [services.http] ); + const [responseError, setResponseError] = useState(undefined); const formik = useFormik({ onSubmit: async (values) => { @@ -143,7 +169,9 @@ export const ApiKeyFlyout: FunctionComponent = ({ onSuccess?.(createApiKeyResponse); } + setResponseError(undefined); } catch (error) { + setResponseError(error.body); throw error; } }, @@ -209,6 +237,12 @@ export const ApiKeyFlyout: FunctionComponent = ({ values: { isSubmitting: formik.isSubmitting }, }); + let expirationDate: Date | undefined; + if (formik.values.customExpiration) { + expirationDate = new Date(); + expirationDate.setDate(expirationDate.getDate() + parseInt(formik.values.expiration, 10)); + } + return ( @@ -223,6 +257,22 @@ export const ApiKeyFlyout: FunctionComponent = ({ + {responseError && ( + <> + + } + > + {responseError.message} + + + + )} {apiKey && !readOnly ? ( !isOwner ? ( <> @@ -252,243 +302,406 @@ export const ApiKeyFlyout: FunctionComponent = ({ ) : null ) : null} - - - } - fullWidth - > - - - - {apiKey ? ( - <> - - - - - } - > + + {apiKey ? ( + <> + +

+ +

+
+ + + + + + + + + + {apiKey.name} + + + + + + + + + + + + + + + + {apiKey.username} + + + + + + + + + + + + + + -
-
- - - } - > - - - - - - } - > + +
+ + + + + + + + + + + - - - - - } - > + + + + + + + + + + + + + - - - - - ) : canManageCrossClusterApiKeys ? ( - - } - fullWidth - > - - - - -

- -

-
- - - - - - } - onChange={() => formik.setFieldValue('type', 'rest')} - checked={formik.values.type === 'rest'} +
+
+ + ) : ( + <> + + + + + + +

+ +

+
+
+
+ + +

+ +

+
+ + } fullWidth> + -
- - + {canManageCrossClusterApiKeys ? ( + } fullWidth> + + + + +

+ +

+
+ + + + + + } + onChange={() => formik.setFieldValue('type', 'rest')} + checked={formik.values.type === 'rest'} + /> +
+ + + +

+ +

+
+ + + + + + } + onChange={() => formik.setFieldValue('type', 'cross_cluster')} + checked={formik.values.type === 'cross_cluster'} + /> +
+
+
+ ) : ( + }> + + + )} + + )} + + + {!apiKey && ( + <> + +
+ - -

- -

-
- - + +

- - +

+
} - onChange={() => formik.setFieldValue('type', 'cross_cluster')} - checked={formik.values.type === 'cross_cluster'} + checked={Boolean(formik.values.customExpiration)} + disabled={readOnly || !!apiKey} + onChange={(e) => formik.setFieldValue('customExpiration', e.target.checked)} /> - - - - ) : ( - - } - > - - + + +

+ +

+
+
+ {formik.values.customExpiration && ( + <> + + + + + ), + }} + /> + } + > + + + + )} +
+ + )} - - {formik.values.type === 'cross_cluster' ? ( - - } - helpText={ - + +
+ + + + + + +

+ {i18n.translate( + 'xpack.security.accountManagement.apiKeyFlyout.accessPermissions.title', + { + defaultMessage: 'Access Permissions', + } + )} +

+
+
+
+
+ -
- } - fullWidth - > - formik.setFieldValue('access', value)} - validate={(value: string) => { - if (!value) { - return i18n.translate( - 'xpack.security.management.apiKeys.apiKeyFlyout.accessRequired', - { - defaultMessage: 'Enter access permissions or disable this option.', - } - ); + } + helpText={ + + + + } + fullWidth + > + formik.setFieldValue('access', value)} + validate={(value: string) => { + if (!value) { + return i18n.translate( + 'xpack.security.management.apiKeys.apiKeyFlyout.accessRequired', + { + defaultMessage: 'Enter access permissions or disable this option.', + } + ); + } + try { + JSON.parse(value); + } catch (e) { + return invalidJsonError; + } + }} + fullWidth + languageId="xjson" + height={200} + /> +
+ + ) : ( + +
+ +

+ {i18n.translate( + 'xpack.security.accountManagement.apiKeyFlyout.privileges.title', + { + defaultMessage: 'Control security privileges', + } + )} +

+ } - try { - JSON.parse(value); - } catch (e) { - return i18n.translate( - 'xpack.security.management.apiKeys.apiKeyFlyout.invalidJsonError', + checked={formik.values.customPrivileges} + data-test-subj="apiKeysRoleDescriptorsSwitch" + onChange={(e) => formik.setFieldValue('customPrivileges', e.target.checked)} + disabled={readOnly || (apiKey && !canEdit)} + /> + + +

+ {i18n.translate( + 'xpack.security.accountManagement.apiKeyFlyout.privileges.description', { - defaultMessage: 'Enter valid JSON.', + defaultMessage: + 'Control access to specific Elasticsearch APIs and resources using predefined roles or custom privileges per API key.', } - ); - } - }} - fullWidth - languageId="xjson" - height={200} - /> - - ) : ( - - - } - checked={formik.values.customPrivileges} - data-test-subj="apiKeysRoleDescriptorsSwitch" - onChange={(e) => formik.setFieldValue('customPrivileges', e.target.checked)} - disabled={readOnly || (apiKey && !canEdit)} - /> + )} +

+
+
{formik.values.customPrivileges && ( <> - + = ({ try { JSON.parse(value); } catch (e) { - return i18n.translate( - 'xpack.security.management.apiKeys.apiKeyFlyout.invalidJsonError', - { - defaultMessage: 'Enter valid JSON.', - } - ); + return invalidJsonError; } }} fullWidth @@ -543,89 +751,42 @@ export const ApiKeyFlyout: FunctionComponent = ({ height={200} /> - )} - +
)} - - {!apiKey && ( - <> - - - - } - checked={formik.values.customExpiration} - onChange={(e) => formik.setFieldValue('customExpiration', e.target.checked)} - disabled={readOnly || !!apiKey} - data-test-subj="apiKeyCustomExpirationSwitch" - /> - {formik.values.customExpiration && ( - <> - - - } - fullWidth - > - + +
+ +

+ - - - - )} - - - )} - - - - } - data-test-subj="apiKeysMetadataSwitch" - checked={formik.values.includeMetadata} - disabled={readOnly || (apiKey && !canEdit)} - onChange={(e) => formik.setFieldValue('includeMetadata', e.target.checked)} - /> +

+ + } + data-test-subj="apiKeysMetadataSwitch" + checked={formik.values.includeMetadata} + disabled={readOnly || (apiKey && !canEdit)} + onChange={(e) => formik.setFieldValue('includeMetadata', e.target.checked)} + /> + + +

+ +

+
+
{formik.values.includeMetadata && ( <> - + = ({ try { JSON.parse(value); } catch (e) { - return i18n.translate( - 'xpack.security.management.apiKeys.apiKeyFlyout.invalidJsonError', - { - defaultMessage: 'Enter valid JSON.', - } - ); + return invalidJsonError; } }} fullWidth @@ -679,10 +835,9 @@ export const ApiKeyFlyout: FunctionComponent = ({ height={200} /> - )} -
+ diff --git a/x-pack/plugins/security/tsconfig.json b/x-pack/plugins/security/tsconfig.json index 0b54e40c228e7..5a28a341b94da 100644 --- a/x-pack/plugins/security/tsconfig.json +++ b/x-pack/plugins/security/tsconfig.json @@ -3,7 +3,12 @@ "compilerOptions": { "outDir": "target/types", }, - "include": ["common/**/*", "public/**/*", "server/**/*", "__mocks__/**/*"], + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + "__mocks__/**/*" + ], "kbn_references": [ "@kbn/cloud-plugin", "@kbn/features-plugin", @@ -66,6 +71,7 @@ "@kbn/security-plugin-types-common", "@kbn/security-plugin-types-public", "@kbn/security-plugin-types-server", + "@kbn/kibana-utils-plugin", "@kbn/code-editor", "@kbn/code-editor-mock", ], diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 0402ed1a09923..e454048b52f1e 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -104,6 +104,13 @@ export const allowedExperimentalValues = Object.freeze({ **/ newUserDetailsFlyout: false, + /* + * Enables the Managed User section inside the new user details flyout. + * To see this section you also need newUserDetailsFlyout flag enabled. + * + **/ + newUserDetailsFlyoutManagedUser: false, + /* * Enables the new host details flyout displayed on the Alerts table. * diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx index d1322fd76a91f..c58d05ce81b8f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.test.tsx @@ -41,11 +41,12 @@ describe('useInstalledIntegrations', () => { return wrapper; }; - const render = () => + const render = ({ skip } = { skip: false }) => renderHook( () => useInstalledIntegrations({ packages: [], + skip, }), { wrapper: createReactQueryWrapper(), @@ -68,6 +69,17 @@ describe('useInstalledIntegrations', () => { ); }); + it('does not call the API when skip is true', async () => { + const fetchInstalledIntegrations = jest.spyOn( + fleetIntegrationsApi, + 'fetchInstalledIntegrations' + ); + + render({ skip: true }); + + expect(fetchInstalledIntegrations).toHaveBeenCalledTimes(0); + }); + it('fetches data from the API', async () => { const { result, waitForNextUpdate } = render(); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx index 1d6fe71d65afe..01b7d5fe6e613 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_installed_integrations.tsx @@ -16,9 +16,13 @@ const ONE_MINUTE = 60000; export interface UseInstalledIntegrationsArgs { packages?: string[]; + skip?: boolean; } -export const useInstalledIntegrations = ({ packages }: UseInstalledIntegrationsArgs) => { +export const useInstalledIntegrations = ({ + packages, + skip = false, +}: UseInstalledIntegrationsArgs) => { // const { addError } = useAppToasts(); return useQuery( @@ -38,6 +42,7 @@ export const useInstalledIntegrations = ({ packages }: UseInstalledIntegrationsA { keepPreviousData: true, staleTime: ONE_MINUTE * 5, + enabled: !skip, onError: (e) => { // Suppressing for now to prevent excessive errors when fleet isn't configured // addError(e, { title: i18n.INTEGRATIONS_FETCH_FAILURE }); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx index 89844f3faece7..3567e01074edb 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx @@ -8,6 +8,7 @@ import { EuiHorizontalRule } from '@elastic/eui'; import React from 'react'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { AssetCriticalitySelector } from '../../../entity_analytics/components/asset_criticality/asset_criticality_selector'; import { OBSERVED_USER_QUERY_ID } from '../../../explore/users/containers/users/observed_details'; @@ -45,6 +46,7 @@ export const UserPanelContent = ({ openDetailsPanel, }: UserPanelContentProps) => { const observedFields = useObservedUserItems(observedUser); + const isManagedUserEnable = useIsExperimentalFeatureEnabled('newUserDetailsFlyoutManagedUser'); return ( @@ -68,12 +70,14 @@ export const UserPanelContent = ({ queryId={OBSERVED_USER_QUERY_ID} /> - + {isManagedUserEnable && ( + + )} ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx index 9961b3ea086e2..6d5bcc4019c3c 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.test.tsx @@ -45,6 +45,11 @@ jest.mock('./hooks/use_observed_user', () => ({ useObservedUser: () => mockedUseObservedUser(), })); +const mockedUseIsExperimentalFeatureEnabled = jest.fn().mockReturnValue(true); +jest.mock('../../../common/hooks/use_experimental_features', () => ({ + useIsExperimentalFeatureEnabled: () => mockedUseIsExperimentalFeatureEnabled(), +})); + describe('UserPanel', () => { beforeEach(() => { mockedUseRiskScore.mockReturnValue(mockRiskScoreState); @@ -95,6 +100,18 @@ describe('UserPanel', () => { expect(getByTestId('securitySolutionFlyoutLoading')).toBeInTheDocument(); }); + it('does not render managed user when experimental flag is disabled', () => { + mockedUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('managedUser-accordion-button')).not.toBeInTheDocument(); + }); + it('renders loading state when managed user is loading', () => { mockedUseManagedUser.mockReturnValue({ ...mockManagedUserData, diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_managed_user.ts b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_managed_user.ts index c3001c30d8cc2..6eb7e385ea0b1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_managed_user.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/hooks/use_managed_user.ts @@ -6,6 +6,8 @@ */ import { useEffect, useMemo } from 'react'; + +import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import type { ManagedUserHits } from '../../../../../../common/search_strategy/security_solution/users/managed_details'; import { useInstalledIntegrations } from '../../../../../detections/components/rules/related_integrations/use_installed_integrations'; import { UsersQueries } from '../../../../../../common/search_strategy'; @@ -35,6 +37,7 @@ export const useManagedUser = ( email: string[] | undefined, isLoading?: boolean ): ManagedUserData => { + const skip = useIsExperimentalFeatureEnabled('newUserDetailsFlyoutManagedUser'); const { to, from, isInitializing, deleteQuery, setQuery } = useGlobalTime(); const spaceId = useSpaceId(); const { @@ -57,17 +60,18 @@ export const useManagedUser = ( ); useEffect(() => { - if (!isInitializing && defaultIndex.length > 0 && !isLoading && userName) { + if (!isInitializing && defaultIndex.length > 0 && !isLoading && userName && !skip) { search({ defaultIndex, userEmail: email, userName, }); } - }, [from, search, to, isInitializing, defaultIndex, userName, isLoading, email]); + }, [from, search, to, isInitializing, defaultIndex, userName, isLoading, email, skip]); const { data: installedIntegrations, isLoading: loadingIntegrations } = useInstalledIntegrations({ packages, + skip, }); useQueryInspector({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 2f6ea38b40b81..0459636ff75ca 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -46,7 +46,7 @@ import { } from '../../../../../common/api/detection_engine/signals_migration/mocks'; // eslint-disable-next-line no-restricted-imports -import type { LegacyRuleNotificationAlertType } from '../../rule_actions_legacy'; +import type { LegacyRuleNotificationRuleType } from '../../rule_actions_legacy'; import type { RuleAlertType, RuleParams } from '../../rule_schema'; import { getQueryRuleParams } from '../../rule_schema/mocks'; @@ -520,7 +520,7 @@ export const legacyGetNotificationResult = ({ }: { id?: string; ruleId?: string; -} = {}): LegacyRuleNotificationAlertType => ({ +} = {}): LegacyRuleNotificationRuleType => ({ id, name: 'Notification for Rule Test', tags: [], @@ -567,7 +567,7 @@ export const legacyGetNotificationResult = ({ */ export const legacyGetFindNotificationsResultWithSingleHit = ( ruleId = '123' -): FindHit => ({ +): FindHit => ({ page: 1, perPage: 1, total: 1, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts index df2c4bb3366b9..518ece11dbefe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts @@ -14,7 +14,7 @@ import { legacyUpdateOrCreateRuleActionsSavedObject } from '../../logic/rule_act // eslint-disable-next-line no-restricted-imports import { legacyReadNotifications } from '../../logic/notifications/legacy_read_notifications'; // eslint-disable-next-line no-restricted-imports -import type { LegacyRuleNotificationAlertTypeParams } from '../../logic/notifications/legacy_types'; +import type { LegacyRuleNotificationRuleTypeParams } from '../../logic/notifications/legacy_types'; // eslint-disable-next-line no-restricted-imports import { legacyCreateNotifications } from '../../logic/notifications/legacy_create_notifications'; import { UPDATE_OR_CREATE_LEGACY_ACTIONS } from '../../../../../../common/constants'; @@ -75,7 +75,7 @@ export const legacyCreateLegacyNotificationRoute = ( ruleAlertId, }); if (notification != null) { - await rulesClient.update({ + await rulesClient.update({ id: notification.id, data: { tags: [], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/index.ts index fddf872583040..e577d0ac5355a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/index.ts @@ -8,13 +8,13 @@ export * from './api/register_routes'; // eslint-disable-next-line no-restricted-imports -export { legacyRulesNotificationAlertType } from './logic/notifications/legacy_rules_notification_alert_type'; +export { legacyRulesNotificationRuleType } from './logic/notifications/legacy_rules_notification_rule_type'; // eslint-disable-next-line no-restricted-imports -export { legacyIsNotificationAlertExecutor } from './logic/notifications/legacy_types'; +export { isLegacyNotificationRuleExecutor } from './logic/notifications/legacy_types'; // eslint-disable-next-line no-restricted-imports export type { - LegacyRuleNotificationAlertType, - LegacyRuleNotificationAlertTypeParams, + LegacyRuleNotificationRuleType, + LegacyRuleNotificationRuleTypeParams, } from './logic/notifications/legacy_types'; export type { NotificationRuleTypeParams } from './logic/notifications/schedule_notification_actions'; export { scheduleNotificationActions } from './logic/notifications/schedule_notification_actions'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.ts index 983519404b222..34428140e9a12 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_create_notifications.ts @@ -10,7 +10,7 @@ import { SERVER_APP_ID, LEGACY_NOTIFICATIONS_ID } from '../../../../../../common // eslint-disable-next-line no-restricted-imports import type { CreateNotificationParams, - LegacyRuleNotificationAlertTypeParams, + LegacyRuleNotificationRuleTypeParams, } from './legacy_types'; /** @@ -23,8 +23,8 @@ export const legacyCreateNotifications = async ({ ruleAlertId, interval, name, -}: CreateNotificationParams): Promise> => - rulesClient.create({ +}: CreateNotificationParams): Promise> => + rulesClient.create({ data: { name, tags: [], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.ts index 187cde7ce8c9d..fda0b6b45ca56 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_read_notifications.ts @@ -9,7 +9,7 @@ import type { RuleTypeParams, SanitizedRule } from '@kbn/alerting-plugin/common' // eslint-disable-next-line no-restricted-imports import type { LegacyReadNotificationParams } from './legacy_types'; // eslint-disable-next-line no-restricted-imports -import { legacyIsAlertType } from './legacy_types'; +import { isLegacyRuleType } from './legacy_types'; // eslint-disable-next-line no-restricted-imports import { legacyFindNotifications } from './legacy_find_notifications'; @@ -24,7 +24,7 @@ export const legacyReadNotifications = async ({ if (id != null) { try { const notification = await rulesClient.get({ id }); - if (legacyIsAlertType(notification)) { + if (isLegacyRuleType(notification)) { return notification; } else { return null; @@ -43,10 +43,7 @@ export const legacyReadNotifications = async ({ filter: `alert.attributes.params.ruleAlertId: "${ruleAlertId}"`, page: 1, }); - if ( - notificationFromFind.data.length === 0 || - !legacyIsAlertType(notificationFromFind.data[0]) - ) { + if (notificationFromFind.data.length === 0 || !isLegacyRuleType(notificationFromFind.data[0])) { return null; } else { return notificationFromFind.data[0]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.test.ts similarity index 57% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.test.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.test.ts index 0f0eeece6f8f6..e3a5e24bd14c2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.test.ts @@ -12,7 +12,7 @@ import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common'; import { getRuleMock } from '../../../routes/__mocks__/request_responses'; // eslint-disable-next-line no-restricted-imports -import { legacyRulesNotificationAlertType } from './legacy_rules_notification_alert_type'; +import { legacyRulesNotificationRuleType } from './legacy_rules_notification_rule_type'; import { buildSignalsSearchQuery } from './build_signals_query'; // eslint-disable-next-line no-restricted-imports import type { LegacyNotificationExecutorOptions } from './legacy_types'; @@ -26,12 +26,123 @@ import { getQueryRuleParams } from '../../../rule_schema/mocks'; jest.mock('./build_signals_query'); +const reported = { + actionGroup: 'default', + context: { + alerts: [ + { + '@timestamp': expect.any(String), + destination: { + ip: '127.0.0.1', + }, + someKey: 'someValue', + source: { + ip: '127.0.0.1', + }, + }, + ], + results_link: + '/app/security/detections/rules/id/rule-id?timerange=(global:(linkTo:!(timeline),timerange:(from:1576255233400,kind:absolute,to:1576341633400)),timeline:(linkTo:!(global),timerange:(from:1576255233400,kind:absolute,to:1576341633400)))', + rule: { + alert_suppression: undefined, + author: ['Elastic'], + building_block_type: 'default', + data_view_id: undefined, + description: 'Detecting root and admin users', + exceptions_list: [ + { + id: 'some_uuid', + list_id: 'list_id_single', + namespace_type: 'single', + type: 'detection', + }, + { + id: 'endpoint_list', + list_id: 'endpoint_list', + namespace_type: 'agnostic', + type: 'endpoint', + }, + ], + false_positives: [], + filters: [ + { + query: { + match_phrase: { + 'host.name': 'some-host', + }, + }, + }, + ], + from: 'now-6m', + id: 'rule-id', + immutable: false, + index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + investigation_fields: undefined, + language: 'kuery', + license: 'Elastic License', + max_signals: 10000, + name: 'Detect Root/Admin Users', + namespace: undefined, + note: '# Investigative notes', + output_index: '.siem-signals', + query: 'user.name: root or user.name: admin', + references: ['http://example.com', 'https://example.com'], + related_integrations: [], + required_fields: [], + response_actions: undefined, + risk_score: 50, + risk_score_mapping: [], + rule_id: 'rule-1', + rule_name_override: undefined, + saved_id: undefined, + setup: '', + severity: 'high', + severity_mapping: [], + threat: [ + { + framework: 'MITRE ATT&CK', + tactic: { + id: 'TA0000', + name: 'test tactic', + reference: 'https://attack.mitre.org/tactics/TA0000/', + }, + technique: [ + { + id: 'T0000', + name: 'test technique', + reference: 'https://attack.mitre.org/techniques/T0000/', + subtechnique: [ + { + id: 'T0000.000', + name: 'test subtechnique', + reference: 'https://attack.mitre.org/techniques/T0000/000/', + }, + ], + }, + ], + }, + ], + timeline_id: 'some-timeline-id', + timeline_title: 'some-timeline-title', + timestamp_override: undefined, + timestamp_override_fallback_disabled: undefined, + to: 'now', + type: 'query', + version: 1, + }, + }, + id: '1111', + state: { + signals_count: 1, + }, +}; + /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -describe('legacyRules_notification_alert_type', () => { +describe('legacyRules_notification_rule_type', () => { let payload: LegacyNotificationExecutorOptions; - let alert: ReturnType; + let rule: ReturnType; let logger: ReturnType; let alertServices: RuleExecutorServicesMock; @@ -78,7 +189,7 @@ describe('legacyRules_notification_alert_type', () => { }, }; - alert = legacyRulesNotificationAlertType({ + rule = legacyRulesNotificationRuleType({ logger, }); }); @@ -91,7 +202,7 @@ describe('legacyRules_notification_alert_type', () => { type: 'type', references: [], }); - await alert.executor(payload); + await rule.executor(payload); expect(logger.error).toHaveBeenCalledWith( `Security Solution notification (Legacy) saved object for alert ${payload.params.ruleAlertId} was not found with id: \"1111\". space id: \"\" This indicates a dangling (Legacy) notification alert. You should delete this rule through \"Kibana UI -> Stack Management -> Rules and Connectors\" to remove this error message.` ); @@ -109,7 +220,7 @@ describe('legacyRules_notification_alert_type', () => { sampleDocSearchResultsWithSortId() ); - await alert.executor(payload); + await rule.executor(payload); expect(buildSignalsSearchQuery).toHaveBeenCalledWith( expect.objectContaining({ @@ -135,17 +246,8 @@ describe('legacyRules_notification_alert_type', () => { sampleDocSearchResultsWithSortId() ); - await alert.executor(payload); - expect(alertServices.alertFactory.create).toHaveBeenCalled(); - - const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results; - expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith( - 'default', - expect.objectContaining({ - results_link: - '/app/security/detections/rules/id/rule-id?timerange=(global:(linkTo:!(timeline),timerange:(from:1576255233400,kind:absolute,to:1576341633400)),timeline:(linkTo:!(global),timerange:(from:1576255233400,kind:absolute,to:1576341633400)))', - }) - ); + await rule.executor(payload); + expect(alertServices.alertsClient.report).toHaveBeenCalledWith(reported); }); it('should resolve results_link when meta is an empty object to use "/app/security"', async () => { @@ -160,17 +262,11 @@ describe('legacyRules_notification_alert_type', () => { alertServices.scopedClusterClient.asCurrentUser.search.mockResponse( sampleDocSearchResultsWithSortId() ); - await alert.executor(payload); - expect(alertServices.alertFactory.create).toHaveBeenCalled(); - - const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results; - expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith( - 'default', - expect.objectContaining({ - results_link: - '/app/security/detections/rules/id/rule-id?timerange=(global:(linkTo:!(timeline),timerange:(from:1576255233400,kind:absolute,to:1576341633400)),timeline:(linkTo:!(global),timerange:(from:1576255233400,kind:absolute,to:1576341633400)))', - }) - ); + await rule.executor(payload); + expect(alertServices.alertsClient.report).toHaveBeenCalledWith({ + ...reported, + context: { ...reported.context, rule: { ...reported.context.rule, meta: {} } }, + }); }); it('should resolve results_link to custom kibana link when given one', async () => { @@ -187,20 +283,24 @@ describe('legacyRules_notification_alert_type', () => { alertServices.scopedClusterClient.asCurrentUser.search.mockResponse( sampleDocSearchResultsWithSortId() ); - await alert.executor(payload); - expect(alertServices.alertFactory.create).toHaveBeenCalled(); - - const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results; - expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith( - 'default', - expect.objectContaining({ + await rule.executor(payload); + expect(alertServices.alertsClient.report).toHaveBeenCalledWith({ + ...reported, + context: { + ...reported.context, results_link: 'http://localhost/detections/rules/id/rule-id?timerange=(global:(linkTo:!(timeline),timerange:(from:1576255233400,kind:absolute,to:1576341633400)),timeline:(linkTo:!(global),timerange:(from:1576255233400,kind:absolute,to:1576341633400)))', - }) - ); + rule: { + ...reported.context.rule, + meta: { + kibana_siem_app_url: 'http://localhost', + }, + }, + }, + }); }); - it('should not call alertFactory.create if signalsCount was 0', async () => { + it('should not call alertsClient.report if signalsCount was 0', async () => { const ruleAlert = getRuleMock(getQueryRuleParams()); alertServices.savedObjectsClient.get.mockResolvedValue({ id: 'id', @@ -212,9 +312,9 @@ describe('legacyRules_notification_alert_type', () => { sampleEmptyDocSearchResults() ); - await alert.executor(payload); + await rule.executor(payload); - expect(alertServices.alertFactory.create).not.toHaveBeenCalled(); + expect(alertServices.alertsClient.report).not.toHaveBeenCalled(); }); it('should call scheduleActions if signalsCount was greater than 0', async () => { @@ -229,22 +329,32 @@ describe('legacyRules_notification_alert_type', () => { sampleDocSearchResultsNoSortIdNoVersion() ); - await alert.executor(payload); - - expect(alertServices.alertFactory.create).toHaveBeenCalled(); + await rule.executor(payload); - const [{ value: alertInstanceMock }] = alertServices.alertFactory.create.mock.results; - expect(alertInstanceMock.replaceState).toHaveBeenCalledWith( - expect.objectContaining({ signals_count: 100 }) - ); - expect(alertInstanceMock.scheduleActions).toHaveBeenCalledWith( - 'default', - expect.objectContaining({ - rule: expect.objectContaining({ - name: ruleAlert.name, - }), - }) - ); + expect(alertServices.alertsClient.report).toHaveBeenCalledWith({ + ...reported, + context: { + ...reported.context, + alerts: [ + { + '@timestamp': expect.any(String), + someKey: 'someValue', + }, + ], + results_link: + '/app/security/detections/rules/id/id?timerange=(global:(linkTo:!(timeline),timerange:(from:1576255233400,kind:absolute,to:1576341633400)),timeline:(linkTo:!(global),timerange:(from:1576255233400,kind:absolute,to:1576341633400)))', + rule: { + ...reported.context.rule, + id: 'id', + meta: { + someMeta: 'someField', + }, + }, + }, + state: { + signals_count: 100, + }, + }); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.ts similarity index 85% rename from x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts rename to x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.ts index 206444e82d7aa..5e237f8564559 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.ts @@ -5,9 +5,11 @@ * 2.0. */ +import { mapKeys, snakeCase } from 'lodash/fp'; import type { Logger } from '@kbn/core/server'; import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; +import { AlertsClientError, DEFAULT_AAD_CONFIG } from '@kbn/alerting-plugin/server'; import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE, LEGACY_NOTIFICATIONS_ID, @@ -15,12 +17,12 @@ import { } from '../../../../../../common/constants'; // eslint-disable-next-line no-restricted-imports -import type { LegacyNotificationAlertTypeDefinition } from './legacy_types'; +import type { LegacyNotificationRuleTypeDefinition } from './legacy_types'; // eslint-disable-next-line no-restricted-imports import { legacyRulesNotificationParams } from './legacy_types'; import type { AlertAttributes } from '../../../rule_types/types'; import { siemRuleActionGroups } from '../../../rule_types/utils/siem_rule_action_groups'; -import { scheduleNotificationActions } from './schedule_notification_actions'; +import { formatAlertsForNotificationActions } from './schedule_notification_actions'; import { getNotificationResultsLink } from './utils'; import { getSignals } from './get_signals'; // eslint-disable-next-line no-restricted-imports @@ -31,11 +33,11 @@ import { legacyInjectReferences } from './legacy_saved_object_references/legacy_ /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export const legacyRulesNotificationAlertType = ({ +export const legacyRulesNotificationRuleType = ({ logger, }: { logger: Logger; -}): LegacyNotificationAlertTypeDefinition => ({ +}): LegacyNotificationRuleTypeDefinition => ({ id: LEGACY_NOTIFICATIONS_ID, name: 'Security Solution notification (Legacy)', actionGroups: siemRuleActionGroups, @@ -52,6 +54,7 @@ export const legacyRulesNotificationAlertType = ({ }, minimumLicenseRequired: 'basic', isExportable: false, + alerts: DEFAULT_AAD_CONFIG, async executor({ startedAt, previousStartedAt, @@ -60,6 +63,11 @@ export const legacyRulesNotificationAlertType = ({ params, spaceId, }) { + const { alertsClient } = services; + if (!alertsClient) { + throw new AlertsClientError(); + } + const ruleAlertSavedObject = await services.savedObjectsClient.get( 'alert', params.ruleAlertId @@ -127,13 +135,17 @@ export const legacyRulesNotificationAlertType = ({ ); if (signalsCount !== 0) { - const alertInstance = services.alertFactory.create(ruleId); - scheduleNotificationActions({ - alertInstance, - signalsCount, - resultsLink, - ruleParams, - signals, + alertsClient.report({ + id: ruleId, + actionGroup: 'default', + state: { + signals_count: signalsCount, + }, + context: { + results_link: resultsLink, + rule: mapKeys(snakeCase, ruleParams), + alerts: formatAlertsForNotificationActions(signals), + }, }); } }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/README.md b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/README.md index 22e1da8dff5b3..09792ae0441bf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/README.md +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/README.md @@ -2,7 +2,7 @@ This is where you add code when you have rules which contain saved object refere when you have "joins" in the saved objects between one saved object and another one. This can be a 1 to M (1 to many) relationship for example where you have a rule which contains the "id" of another saved object. -NOTE: This is the "legacy saved object references" and should only be for the "legacy_rules_notification_alert_type". +NOTE: This is the "legacy saved object references" and should only be for the "legacy_rules_notification_rule_type". The legacy notification system is being phased out and deprecated in favor of using the newer alerting notification system. It would be considered wrong to see additional code being added here at this point. However, maintenance should be expected until we have all users moved away from the legacy system. diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.ts index 069017fcabbcb..c388422aedcf9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_saved_object_references/legacy_extract_references.ts @@ -30,7 +30,7 @@ import { legacyExtractRuleId } from './legacy_extract_rule_id'; * Optionally you can remove any parameters you do not want to store within the Saved Object here: * const paramsWithoutSavedObjectReferences = { removeParam, ...otherParams }; * - * If you do remove params, then update the types in: security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.ts + * If you do remove params, then update the types in: security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_rule_type.ts * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function * @param logger Kibana injected logger * @param params The params of the base rule(s). diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_types.ts index 2aea76d8c51e1..824ad7573e10c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_types.ts @@ -19,19 +19,20 @@ import type { RuleExecutorOptions, } from '@kbn/alerting-plugin/server'; import type { Rule, RuleAction } from '@kbn/alerting-plugin/common'; +import type { DefaultAlert } from '@kbn/alerts-as-data-utils'; import { LEGACY_NOTIFICATIONS_ID } from '../../../../../../common/constants'; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export interface LegacyRuleNotificationAlertTypeParams extends RuleTypeParams { +export interface LegacyRuleNotificationRuleTypeParams extends RuleTypeParams { ruleAlertId: string; } /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export type LegacyRuleNotificationAlertType = Rule; +export type LegacyRuleNotificationRuleType = Rule; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function @@ -81,35 +82,40 @@ export interface LegacyReadNotificationParams { /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export const legacyIsAlertType = ( - partialAlert: PartialRule -): partialAlert is LegacyRuleNotificationAlertType => { - return partialAlert.alertTypeId === LEGACY_NOTIFICATIONS_ID; +export const isLegacyRuleType = ( + partialRule: PartialRule +): partialRule is LegacyRuleNotificationRuleType => { + return partialRule.alertTypeId === LEGACY_NOTIFICATIONS_ID; }; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ export type LegacyNotificationExecutorOptions = RuleExecutorOptions< - LegacyRuleNotificationAlertTypeParams, + LegacyRuleNotificationRuleTypeParams, RuleTypeState, AlertInstanceState, - AlertInstanceContext + AlertInstanceContext, + 'default', + DefaultAlert >; /** - * This returns true because by default a NotificationAlertTypeDefinition is an AlertType + * This returns true because by default a NotificationRuleTypeDefinition is an RuleType * since we are only increasing the strictness of params. * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export const legacyIsNotificationAlertExecutor = ( - obj: LegacyNotificationAlertTypeDefinition +export const isLegacyNotificationRuleExecutor = ( + obj: LegacyNotificationRuleTypeDefinition ): obj is RuleType< - LegacyRuleNotificationAlertTypeParams, - LegacyRuleNotificationAlertTypeParams, + LegacyRuleNotificationRuleTypeParams, + LegacyRuleNotificationRuleTypeParams, RuleTypeState, AlertInstanceState, - AlertInstanceContext + AlertInstanceContext, + 'default', + never, + DefaultAlert > => { return true; }; @@ -117,14 +123,16 @@ export const legacyIsNotificationAlertExecutor = ( /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export type LegacyNotificationAlertTypeDefinition = Omit< +export type LegacyNotificationRuleTypeDefinition = Omit< RuleType< - LegacyRuleNotificationAlertTypeParams, - LegacyRuleNotificationAlertTypeParams, + LegacyRuleNotificationRuleTypeParams, + LegacyRuleNotificationRuleTypeParams, RuleTypeState, AlertInstanceState, AlertInstanceContext, - 'default' + 'default', + never, + DefaultAlert >, 'executor' > & { @@ -136,17 +144,17 @@ export type LegacyNotificationAlertTypeDefinition = Omit< }; /** - * This is the notification type used within legacy_rules_notification_alert_type for the alert params. + * This is the notification type used within legacy_rules_notification_rule_type for the alert params. * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function - * @see legacy_rules_notification_alert_type + * @see legacy_rules_notification_rule_type */ export const legacyRulesNotificationParams = schema.object({ ruleAlertId: schema.string(), }); /** - * This legacy rules notification type used within legacy_rules_notification_alert_type for the alert params. + * This legacy rules notification type used within legacy_rules_notification_rule_type for the alert params. * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function - * @see legacy_rules_notification_alert_type + * @see legacy_rules_notification_rule_type */ export type LegacyRulesNotificationParams = TypeOf; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/post_legacy_notification.sh b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/post_legacy_notification.sh index f160d1e899a55..317b9d8c0fafc 100755 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/post_legacy_notification.sh +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/post_legacy_notification.sh @@ -20,6 +20,7 @@ NOTIFICATIONS=${2:-./legacy_notifications/one_action.json} curl -s -k \ -H 'Content-Type: application/json' \ -H 'kbn-xsrf: 123' \ + -H 'elastic-api-version: 1' \ -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} \ -X POST ${KIBANA_URL}${SPACE_URL}/internal/api/detection/legacy/notifications?alert_id="$1" \ -d @${NOTIFICATIONS} | jq . diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 27bdcfe796e76..ffe4e7a6e342b 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -73,8 +73,8 @@ import type { } from './lib/detection_engine/rule_types/types'; // eslint-disable-next-line no-restricted-imports import { - legacyIsNotificationAlertExecutor, - legacyRulesNotificationAlertType, + isLegacyNotificationRuleExecutor, + legacyRulesNotificationRuleType, } from './lib/detection_engine/rule_actions_legacy'; import { createSecurityRuleTypeWrapper, @@ -354,9 +354,9 @@ export class Plugin implements ISecuritySolutionPlugin { ); if (plugins.alerting != null) { - const ruleNotificationType = legacyRulesNotificationAlertType({ logger }); + const ruleNotificationType = legacyRulesNotificationRuleType({ logger }); - if (legacyIsNotificationAlertExecutor(ruleNotificationType)) { + if (isLegacyNotificationRuleExecutor(ruleNotificationType)) { plugins.alerting.registerType(ruleNotificationType); } } diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 6f7afd7d12465..a7af8827c0efd 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -7716,6 +7716,40 @@ } } } + }, + "muted_rules_stats": { + "type": "array", + "items": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "section": { + "type": "keyword" + }, + "benchmark_id": { + "type": "keyword" + }, + "benchmark_name": { + "type": "keyword" + }, + "benchmark_version": { + "type": "keyword" + }, + "rule_number": { + "type": "keyword" + }, + "posture_type": { + "type": "keyword" + }, + "version": { + "type": "keyword" + } + } + } } } }, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0d684afb7809c..fcbc20c1a8c79 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -11903,13 +11903,7 @@ "xpack.csp.cloudPosturePage.kspmIntegration.packageNotInstalled.description": "Utilisez notre intégration {integrationFullName} (KSPM) pour détecter les erreurs de configuration de sécurité dans vos clusters Kubernetes.", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed} résultats en échec et {passed} ayant réussi", "xpack.csp.eksIntegration.docsLink": "Lisez {docs} pour en savoir plus", - "xpack.csp.findings..bottomBarLabel": "Voici les {maxItems} premiers résultats correspondant à votre recherche. Veuillez l'affiner pour en voir davantage.", "xpack.csp.findings.distributionBar.showingPageOfTotalLabel": "Affichage de {pageStart}-{pageEnd} sur {total} {type}", - "xpack.csp.findings.findingsTableCell.addFilterButton": "Ajouter un filtre {field}", - "xpack.csp.findings.findingsTableCell.addFilterButtonTooltip": "Ajouter un filtre {field}", - "xpack.csp.findings.findingsTableCell.addNegatedFilterButtonTooltip": "Ajouter un filtre {field} négatif", - "xpack.csp.findings.findingsTableCell.addNegateFilterButton": "Ajouter un filtre {field} négatif", - "xpack.csp.findings.resourceFindings.resourceFindingsPageTitle": "{resourceName} {hyphen} Résultats", "xpack.csp.findingsFlyout.alerts.alertCount": "{alertCount, plural, one {# alerte} many {# alertes} other {Alertes #}}", "xpack.csp.findingsFlyout.alerts.detectionRuleCount": "{ruleCount, plural, one {# règle de détection} many {# règles de détection} other {# règles de détection}}", "xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "La collecte des résultats prend plus de temps que prévu. {docs}.", @@ -11917,15 +11911,7 @@ "xpack.csp.rules.rulesTable.showingPageOfTotalLabel": "Affichage de {pageSize} sur {total, plural, one {# règle} many {# règles bien mises} other {# règles}}", "xpack.csp.subscriptionNotAllowed.promptDescription": "Pour utiliser ces fonctionnalités de sécurité du cloud, vous devez {link}.", "xpack.csp.vulnerabilities.detectionRuleNamePrefix": "Vulnérabilité : {vulnerabilityId}", - "xpack.csp.vulnerabilities.resourceVulnerabilities.vulnerabilitiesPageTitle": "{resourceName} {hyphen} vulnérabilités", - "xpack.csp.vulnerabilities.totalVulnerabilities": "{total, plural, one {# vulnérabilité} many {# vulnérabilités} other {# vulnérabilités}}", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addFilterButton": "Ajouter un filtre {columnId}", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addFilterButtonTooltip": "Ajouter un filtre {columnId}", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addNegatedFilterButtonTooltip": "Ajouter un filtre {columnId} négatif", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addNegateFilterButton": "Ajouter un filtre {columnId} négatif", "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDateText": "{date}", - "xpack.csp.vulnerabilitiesByResource.totalResources": "{total, plural, one {# ressource} many {# ressources} other {# ressources}}", - "xpack.csp.vulnerabilitiesByResource.totalVulnerabilities": "{total, plural, one {# vulnérabilité} many {# vulnérabilités} other {# vulnérabilités}}", "xpack.csp.awsIntegration.accessKeyIdLabel": "ID de clé d'accès", "xpack.csp.awsIntegration.assumeRoleDescription": "Un nom ARN (Amazon Resource Name) de rôle IAM est une identité IAM que vous pouvez créer dans votre compte AWS. Lors de la création d'un rôle IAM, les utilisateurs peuvent définir les autorisations accordées au rôle. Les rôles n'ont pas d'informations d'identification à long terme standard telles que des mots de passe ou des clés d'accès.", "xpack.csp.awsIntegration.assumeRoleLabel": "Assumer un rôle", @@ -12060,15 +12046,10 @@ "xpack.csp.emptyState.readDocsLink": "Lisez les documents", "xpack.csp.emptyState.resetFiltersButton": "Réinitialiser les filtres", "xpack.csp.emptyState.title": "Aucun résultat ne correspond à vos critères de recherche.", - "xpack.csp.expandColumnDescriptionLabel": "Développer", - "xpack.csp.expandColumnNameLabel": "Développer", "xpack.csp.findings.distributionBar.totalFailedLabel": "Échec des résultats", "xpack.csp.findings.distributionBar.totalPassedLabel": "Réussite des résultats", "xpack.csp.findings.errorCallout.pageSearchErrorTitle": "Une erreur s’est produite lors de la récupération des résultats de recherche.", "xpack.csp.findings.errorCallout.showErrorButtonLabel": "Afficher le message d'erreur", - "xpack.csp.findings.findingsByResource.tableRowTypeLabel": "Ressources", - "xpack.csp.findings.findingsByResourceTable.cisSectionsColumnLabel": "Sections CIS", - "xpack.csp.findings.findingsByResourceTable.postureScoreColumnLabel": "Score du niveau", "xpack.csp.findings.findingsErrorToast.searchFailedTitle": "Échec de la recherche", "xpack.csp.findings.findingsFlyout.jsonTabTitle": "JSON", "xpack.csp.findings.findingsFlyout.overviewTab.alertsTitle": "Alertes", @@ -12100,16 +12081,11 @@ "xpack.csp.findings.findingsFlyout.ruleTab.tagsTitle": "Balises", "xpack.csp.findings.findingsFlyout.ruleTabTitle": "Règle", "xpack.csp.findings.findingsFlyout.tableTabTitle": "Tableau", - "xpack.csp.findings.findingsTable.findingsTableColumn.clusterIdColumnLabel": "Appartient à", - "xpack.csp.findings.findingsTable.findingsTableColumn.clusterIdColumnTooltipLabel": "ID de cluster Kubernetes ou nom de compte cloud", "xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel": "Dernière vérification", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnLabel": "ID ressource", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnTooltipLabel": "ID ressource Elastic personnalisée", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel": "Nom de ressource", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel": "Type de ressource", "xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel": "Résultat", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleBenchmarkColumnLabel": "Benchmark applicable", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleBenchmarkColumnTooltipLabel": "Le benchmark utilisé pour évaluer cette ressource", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel": "Nom de règle", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel": "Numéro de règle", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel": "Section CIS", @@ -12120,12 +12096,6 @@ "xpack.csp.findings.groupBySelector.groupByNoneLabel": "Aucun", "xpack.csp.findings.groupBySelector.groupByResourceIdLabel": "Ressource", "xpack.csp.findings.latestFindings.tableRowTypeLabel": "Résultats", - "xpack.csp.findings.resourceFindings.backToResourcesPageButtonLabel": "Retour aux ressources", - "xpack.csp.findings.resourceFindings.tableRowTypeLabel": "Résultats", - "xpack.csp.findings.resourceFindingsSharedValues.cloudAccountName": "Nom du compte cloud", - "xpack.csp.findings.resourceFindingsSharedValues.clusterIdTitle": "ID cluster", - "xpack.csp.findings.resourceFindingsSharedValues.resourceIdTitle": "ID ressource", - "xpack.csp.findings.resourceFindingsSharedValues.resourceTypeTitle": "Type de ressource", "xpack.csp.findings.search.queryErrorToastMessage": "Erreur de requête", "xpack.csp.findings.searchBar.searchPlaceholder": "Rechercher dans les résultats (par ex. rule.section : \"serveur d'API\")", "xpack.csp.findings.tabs.misconfigurations": "Configurations incorrectes", @@ -12240,9 +12210,6 @@ "xpack.csp.vulnerabilities": "Vulnérabilités", "xpack.csp.vulnerabilities.flyoutTabs.fieldLabel": "Champ", "xpack.csp.vulnerabilities.flyoutTabs.fieldValueLabel": "Valeur", - "xpack.csp.vulnerabilities.resourceVulnerabilities.backToResourcesPageButtonLabel": "Retour aux ressources", - "xpack.csp.vulnerabilities.resourceVulnerabilities.regionTitle": "Région", - "xpack.csp.vulnerabilities.resourceVulnerabilities.resourceIdTitle": "ID ressource", "xpack.csp.vulnerabilities.searchBar.placeholder": "Rechercher des vulnérabilités (par exemple vulnerability.severity : \"CRITICAL\" )", "xpack.csp.vulnerabilities.table.filterIn": "Inclure", "xpack.csp.vulnerabilities.table.filterOut": "Exclure", @@ -12265,24 +12232,12 @@ "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDate": "Date de publication", "xpack.csp.vulnerabilitiesByResource.severityMap.tooltipTitle": "Carte des degrés de gravité", "xpack.csp.vulnerability_dashboard.cspPageTemplate.pageTitle": "Gestion des vulnérabilités natives du cloud", - "xpack.csp.vulnerabilityByResourceTable.column.region": "Région", - "xpack.csp.vulnerabilityByResourceTable.column.resourceId": "ID ressource", - "xpack.csp.vulnerabilityByResourceTable.column.resourceName": "Nom de ressource", - "xpack.csp.vulnerabilityByResourceTable.column.severityMap": "Carte des degrés de gravité", - "xpack.csp.vulnerabilityByResourceTable.column.vulnerabilities": "Vulnérabilités", "xpack.csp.vulnerabilityDashboard.trendGraphChart.accountsDropDown.option.allTitle": "Tous", "xpack.csp.vulnerabilityDashboard.trendGraphChart.accountsDropDown.prepend.accountsTitle": "Comptes", "xpack.csp.vulnerabilityDashboard.trendGraphChart.trendBySeverityTitle": "Tendance par degré de gravité", "xpack.csp.vulnerabilityDashboard.viewAllButton.buttonTitle": "Tout afficher", - "xpack.csp.vulnerabilityTable.column.fixVersion": "Version du correctif", - "xpack.csp.vulnerabilityTable.column.package": "Pack", - "xpack.csp.vulnerabilityTable.column.resourceId": "ID ressource", - "xpack.csp.vulnerabilityTable.column.resourceName": "Nom de ressource", - "xpack.csp.vulnerabilityTable.column.severity": "Sévérité", "xpack.csp.vulnerabilityTable.column.sortAscending": "Basse -> Critique", "xpack.csp.vulnerabilityTable.column.sortDescending": "Critique -> Basse", - "xpack.csp.vulnerabilityTable.column.version": "Version", - "xpack.csp.vulnerabilityTable.column.vulnerability": "Vulnérabilité", "xpack.csp.vulnerabilityTable.panel.buttonText": "Afficher toutes les vulnérabilités", "xpack.csp.vulnMgmtIntegration.awsOption.nameTitle": "Amazon Web Services", "xpack.csp.vulnMgmtIntegration.azureOption.nameTitle": "Azure", @@ -30870,11 +30825,7 @@ "xpack.security.accountManagement.apiKeyFlyout.createTitle": "Créer une clé d'API", "xpack.security.accountManagement.apiKeyFlyout.crossClusterTypeDescription": "Autorise les clusters distants à se connecter à votre cluster local.", "xpack.security.accountManagement.apiKeyFlyout.crossClusterTypeLabel": "Clé d'API inter-clusters", - "xpack.security.accountManagement.apiKeyFlyout.customExpirationInputLabel": "Durée de vie", - "xpack.security.accountManagement.apiKeyFlyout.customExpirationLabel": "Délai d'expiration", - "xpack.security.accountManagement.apiKeyFlyout.customPrivilegesLabel": "Limiter les privilèges", "xpack.security.accountManagement.apiKeyFlyout.expirationUnit": "jours", - "xpack.security.accountManagement.apiKeyFlyout.includeMetadataLabel": "Inclure les métadonnées", "xpack.security.accountManagement.apiKeyFlyout.metadataHelpText": "Découvrez comment structurer les métadonnées.", "xpack.security.accountManagement.apiKeyFlyout.nameLabel": "Nom", "xpack.security.accountManagement.apiKeyFlyout.ownerLabel": "Propriétaire", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 90240386985cf..62908af4bd9c1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -11917,13 +11917,7 @@ "xpack.csp.cloudPosturePage.kspmIntegration.packageNotInstalled.description": "{integrationFullName}(CSPM)統合を使用して、Kubernetesクラスターの構成エラーを検出します。", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed}が失敗し、{passed}が調査結果に合格しました", "xpack.csp.eksIntegration.docsLink": "詳細は{docs}をご覧ください", - "xpack.csp.findings..bottomBarLabel": "これらは検索条件に一致した初めの{maxItems}件の調査結果です。他の結果を表示するには検索条件を絞ってください。", "xpack.csp.findings.distributionBar.showingPageOfTotalLabel": "{total} {type}ページ中{pageStart}-{pageEnd}ページを表示中", - "xpack.csp.findings.findingsTableCell.addFilterButton": "{field}フィルターを追加", - "xpack.csp.findings.findingsTableCell.addFilterButtonTooltip": "{field}フィルターを追加", - "xpack.csp.findings.findingsTableCell.addNegatedFilterButtonTooltip": "{field}否定フィルターを追加", - "xpack.csp.findings.findingsTableCell.addNegateFilterButton": "{field}否定フィルターを追加", - "xpack.csp.findings.resourceFindings.resourceFindingsPageTitle": "{resourceName} {hyphen}調査結果", "xpack.csp.findingsFlyout.alerts.alertCount": "{alertCount, plural, other {#件のアラート}}", "xpack.csp.findingsFlyout.alerts.detectionRuleCount": "{ruleCount, plural, other {#検出ルール}}", "xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "調査結果の収集に想定よりも時間がかかっています。{docs}。", @@ -11931,15 +11925,7 @@ "xpack.csp.rules.rulesTable.showingPageOfTotalLabel": "{total, plural, other {#個のルール}} 件中{pageSize}を表示中", "xpack.csp.subscriptionNotAllowed.promptDescription": "これらのクラウドセキュリティ機能を使用するには、{link}する必要があります。", "xpack.csp.vulnerabilities.detectionRuleNamePrefix": "脆弱性:{vulnerabilityId}", - "xpack.csp.vulnerabilities.resourceVulnerabilities.vulnerabilitiesPageTitle": "{resourceName} {hyphen} 脆弱性", - "xpack.csp.vulnerabilities.totalVulnerabilities": "{total, plural, other {#件の脆弱性}}", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addFilterButton": "{columnId}フィルターを追加", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addFilterButtonTooltip": "{columnId}フィルターを追加", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addNegatedFilterButtonTooltip": "{columnId}否定フィルターを追加", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addNegateFilterButton": "{columnId}否定フィルターを追加", "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDateText": "{date}", - "xpack.csp.vulnerabilitiesByResource.totalResources": "{total, plural, other {#個のリソース}}", - "xpack.csp.vulnerabilitiesByResource.totalVulnerabilities": "{total, plural, other {#件の脆弱性}}", "xpack.csp.awsIntegration.accessKeyIdLabel": "アクセスキーID", "xpack.csp.awsIntegration.assumeRoleDescription": "IAMロールAmazon Resource Name(ARN)は、AWSアカウントで作成できるIAM IDです。IAMロールを作成するときには、ユーザーはロールの権限を定義できます。ロールには、パスワードやアクセスキーなどの標準の長期的な資格情報がありません。", "xpack.csp.awsIntegration.assumeRoleLabel": "ロールを想定", @@ -12074,15 +12060,10 @@ "xpack.csp.emptyState.readDocsLink": "ドキュメントを読む", "xpack.csp.emptyState.resetFiltersButton": "フィルターをリセット", "xpack.csp.emptyState.title": "検索条件と一致する結果がありません。", - "xpack.csp.expandColumnDescriptionLabel": "拡張", - "xpack.csp.expandColumnNameLabel": "拡張", "xpack.csp.findings.distributionBar.totalFailedLabel": "失敗した調査結果", "xpack.csp.findings.distributionBar.totalPassedLabel": "合格した調査結果", "xpack.csp.findings.errorCallout.pageSearchErrorTitle": "検索結果の取得中にエラーが発生しました", "xpack.csp.findings.errorCallout.showErrorButtonLabel": "エラーメッセージを表示", - "xpack.csp.findings.findingsByResource.tableRowTypeLabel": "リソース", - "xpack.csp.findings.findingsByResourceTable.cisSectionsColumnLabel": "CISセクション", - "xpack.csp.findings.findingsByResourceTable.postureScoreColumnLabel": "態勢スコア", "xpack.csp.findings.findingsErrorToast.searchFailedTitle": "検索失敗", "xpack.csp.findings.findingsFlyout.jsonTabTitle": "JSON", "xpack.csp.findings.findingsFlyout.overviewTab.alertsTitle": "アラート", @@ -12114,16 +12095,11 @@ "xpack.csp.findings.findingsFlyout.ruleTab.tagsTitle": "タグ", "xpack.csp.findings.findingsFlyout.ruleTabTitle": "ルール", "xpack.csp.findings.findingsFlyout.tableTabTitle": "表", - "xpack.csp.findings.findingsTable.findingsTableColumn.clusterIdColumnLabel": "属します", - "xpack.csp.findings.findingsTable.findingsTableColumn.clusterIdColumnTooltipLabel": "KubernetesクラスターIDまたはクラウドアカウント名", "xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel": "最終確認", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnLabel": "リソースID", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnTooltipLabel": "カスタムElasticリソースID", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel": "リソース名", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel": "リソースタイプ", "xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel": "結果", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleBenchmarkColumnLabel": "適用されるベンチマーク", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleBenchmarkColumnTooltipLabel": "このリソースの評価に使用されるベンチマーク", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel": "ルール名", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel": "ルール番号", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel": "CISセクション", @@ -12134,12 +12110,6 @@ "xpack.csp.findings.groupBySelector.groupByNoneLabel": "なし", "xpack.csp.findings.groupBySelector.groupByResourceIdLabel": "リソース", "xpack.csp.findings.latestFindings.tableRowTypeLabel": "調査結果", - "xpack.csp.findings.resourceFindings.backToResourcesPageButtonLabel": "リソースに戻る", - "xpack.csp.findings.resourceFindings.tableRowTypeLabel": "調査結果", - "xpack.csp.findings.resourceFindingsSharedValues.cloudAccountName": "クラウドアカウント名", - "xpack.csp.findings.resourceFindingsSharedValues.clusterIdTitle": "クラスターID", - "xpack.csp.findings.resourceFindingsSharedValues.resourceIdTitle": "リソースID", - "xpack.csp.findings.resourceFindingsSharedValues.resourceTypeTitle": "リソースタイプ", "xpack.csp.findings.search.queryErrorToastMessage": "クエリエラー", "xpack.csp.findings.searchBar.searchPlaceholder": "検索結果(例:rule.section:\"API Server\")", "xpack.csp.findings.tabs.misconfigurations": "構成エラー", @@ -12254,9 +12224,6 @@ "xpack.csp.vulnerabilities": "脆弱性", "xpack.csp.vulnerabilities.flyoutTabs.fieldLabel": "フィールド", "xpack.csp.vulnerabilities.flyoutTabs.fieldValueLabel": "値", - "xpack.csp.vulnerabilities.resourceVulnerabilities.backToResourcesPageButtonLabel": "リソースに戻る", - "xpack.csp.vulnerabilities.resourceVulnerabilities.regionTitle": "地域", - "xpack.csp.vulnerabilities.resourceVulnerabilities.resourceIdTitle": "リソースID", "xpack.csp.vulnerabilities.searchBar.placeholder": "脆弱性を検索(例:vulnerability.severity :\"CRITICAL\")", "xpack.csp.vulnerabilities.table.filterIn": "フィルタリング", "xpack.csp.vulnerabilities.table.filterOut": "除外", @@ -12279,24 +12246,12 @@ "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDate": "公開日", "xpack.csp.vulnerabilitiesByResource.severityMap.tooltipTitle": "重要度マップ", "xpack.csp.vulnerability_dashboard.cspPageTemplate.pageTitle": "Cloud Native Vulnerability Management", - "xpack.csp.vulnerabilityByResourceTable.column.region": "地域", - "xpack.csp.vulnerabilityByResourceTable.column.resourceId": "リソースID", - "xpack.csp.vulnerabilityByResourceTable.column.resourceName": "リソース名", - "xpack.csp.vulnerabilityByResourceTable.column.severityMap": "重要度マップ", - "xpack.csp.vulnerabilityByResourceTable.column.vulnerabilities": "脆弱性", "xpack.csp.vulnerabilityDashboard.trendGraphChart.accountsDropDown.option.allTitle": "すべて", "xpack.csp.vulnerabilityDashboard.trendGraphChart.accountsDropDown.prepend.accountsTitle": "アカウント", "xpack.csp.vulnerabilityDashboard.trendGraphChart.trendBySeverityTitle": "重要度別傾向", "xpack.csp.vulnerabilityDashboard.viewAllButton.buttonTitle": "すべて表示", - "xpack.csp.vulnerabilityTable.column.fixVersion": "修正バージョン", - "xpack.csp.vulnerabilityTable.column.package": "パッケージ", - "xpack.csp.vulnerabilityTable.column.resourceId": "リソースID", - "xpack.csp.vulnerabilityTable.column.resourceName": "リソース名", - "xpack.csp.vulnerabilityTable.column.severity": "深刻度", "xpack.csp.vulnerabilityTable.column.sortAscending": "低 -> 重大", "xpack.csp.vulnerabilityTable.column.sortDescending": "重大 -> 低", - "xpack.csp.vulnerabilityTable.column.version": "バージョン", - "xpack.csp.vulnerabilityTable.column.vulnerability": "脆弱性", "xpack.csp.vulnerabilityTable.panel.buttonText": "すべての脆弱性を表示", "xpack.csp.vulnMgmtIntegration.awsOption.nameTitle": "Amazon Web Services", "xpack.csp.vulnMgmtIntegration.azureOption.nameTitle": "Azure", @@ -30869,11 +30824,7 @@ "xpack.security.accountManagement.apiKeyFlyout.createTitle": "APIキーを作成", "xpack.security.accountManagement.apiKeyFlyout.crossClusterTypeDescription": "リモートクラスターがローカルクラスターに接続できるようにします。", "xpack.security.accountManagement.apiKeyFlyout.crossClusterTypeLabel": "クラスター横断APIキー", - "xpack.security.accountManagement.apiKeyFlyout.customExpirationInputLabel": "寿命", - "xpack.security.accountManagement.apiKeyFlyout.customExpirationLabel": "時間の後に有効期限切れ", - "xpack.security.accountManagement.apiKeyFlyout.customPrivilegesLabel": "権限を制限", "xpack.security.accountManagement.apiKeyFlyout.expirationUnit": "日", - "xpack.security.accountManagement.apiKeyFlyout.includeMetadataLabel": "メタデータを含む", "xpack.security.accountManagement.apiKeyFlyout.metadataHelpText": "メタデータを構成する方法を参照してください。", "xpack.security.accountManagement.apiKeyFlyout.nameLabel": "名前", "xpack.security.accountManagement.apiKeyFlyout.ownerLabel": "所有者", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 34f09ecbeadf1..c1550eab55885 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -12011,13 +12011,7 @@ "xpack.csp.cloudPosturePage.kspmIntegration.packageNotInstalled.description": "使用我们的 {integrationFullName} (KSPM) 集成可在您的 Kubernetes 集群中检测安全配置错误。", "xpack.csp.complianceScoreBar.tooltipTitle": "{failed} 个失败和 {passed} 个通过的结果", "xpack.csp.eksIntegration.docsLink": "请参阅 {docs} 了解更多详情", - "xpack.csp.findings..bottomBarLabel": "这些是匹配您的搜索的前 {maxItems} 个结果,请优化搜索以查看其他结果。", "xpack.csp.findings.distributionBar.showingPageOfTotalLabel": "正在显示第 {pageStart}-{pageEnd} 个 {type}(共 {total} 个)", - "xpack.csp.findings.findingsTableCell.addFilterButton": "添加 {field} 筛选", - "xpack.csp.findings.findingsTableCell.addFilterButtonTooltip": "添加 {field} 筛选", - "xpack.csp.findings.findingsTableCell.addNegatedFilterButtonTooltip": "添加 {field} 作废筛选", - "xpack.csp.findings.findingsTableCell.addNegateFilterButton": "添加 {field} 作废筛选", - "xpack.csp.findings.resourceFindings.resourceFindingsPageTitle": "{resourceName} {hyphen} 结果", "xpack.csp.findingsFlyout.alerts.alertCount": "{alertCount, plural, other {# 个告警}}", "xpack.csp.findingsFlyout.alerts.detectionRuleCount": "{ruleCount, plural, other {# 个检测规则}}", "xpack.csp.noFindingsStates.indexTimeout.indexTimeoutDescription": "收集结果所需的时间长于预期。{docs}。", @@ -12025,15 +12019,7 @@ "xpack.csp.rules.rulesTable.showingPageOfTotalLabel": "正在显示 {pageSize} 个规则(共 {total, plural, other {# 个规则}})", "xpack.csp.subscriptionNotAllowed.promptDescription": "要使用这些云安全功能,您必须 {link}。", "xpack.csp.vulnerabilities.detectionRuleNamePrefix": "漏洞:{vulnerabilityId}", - "xpack.csp.vulnerabilities.resourceVulnerabilities.vulnerabilitiesPageTitle": "{resourceName} {hyphen} 漏洞", - "xpack.csp.vulnerabilities.totalVulnerabilities": "{total, plural, other {# 个漏洞}}", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addFilterButton": "添加 {columnId} 筛选", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addFilterButtonTooltip": "添加 {columnId} 筛选", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addNegatedFilterButtonTooltip": "添加 {columnId} 作废筛选", - "xpack.csp.vulnerabilities.vulnerabilitiesTableCell.addNegateFilterButton": "添加 {columnId} 作废筛选", "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDateText": "{date}", - "xpack.csp.vulnerabilitiesByResource.totalResources": "{total, plural, other {# 项资源}}", - "xpack.csp.vulnerabilitiesByResource.totalVulnerabilities": "{total, plural, other {# 个漏洞}}", "xpack.csp.awsIntegration.accessKeyIdLabel": "访问密钥 ID", "xpack.csp.awsIntegration.assumeRoleDescription": "IAM 角色 Amazon 资源名称 (ARN) 是您可在 AWS 帐户中创建的 IAM 身份。创建 IAM 角色时,用户可以定义该角色的权限。角色没有标准的长期凭据,如密码或访问密钥。", "xpack.csp.awsIntegration.assumeRoleLabel": "接管角色", @@ -12168,15 +12154,10 @@ "xpack.csp.emptyState.readDocsLink": "阅读文档", "xpack.csp.emptyState.resetFiltersButton": "重置筛选", "xpack.csp.emptyState.title": "没有任何结果匹配您的搜索条件", - "xpack.csp.expandColumnDescriptionLabel": "展开", - "xpack.csp.expandColumnNameLabel": "展开", "xpack.csp.findings.distributionBar.totalFailedLabel": "失败的结果", "xpack.csp.findings.distributionBar.totalPassedLabel": "通过的结果", "xpack.csp.findings.errorCallout.pageSearchErrorTitle": "检索搜索结果时遇到问题", "xpack.csp.findings.errorCallout.showErrorButtonLabel": "显示错误消息", - "xpack.csp.findings.findingsByResource.tableRowTypeLabel": "资源", - "xpack.csp.findings.findingsByResourceTable.cisSectionsColumnLabel": "CIS 部分", - "xpack.csp.findings.findingsByResourceTable.postureScoreColumnLabel": "态势分数", "xpack.csp.findings.findingsErrorToast.searchFailedTitle": "搜索失败", "xpack.csp.findings.findingsFlyout.jsonTabTitle": "JSON", "xpack.csp.findings.findingsFlyout.overviewTab.alertsTitle": "告警", @@ -12208,16 +12189,11 @@ "xpack.csp.findings.findingsFlyout.ruleTab.tagsTitle": "标签", "xpack.csp.findings.findingsFlyout.ruleTabTitle": "规则", "xpack.csp.findings.findingsFlyout.tableTabTitle": "表", - "xpack.csp.findings.findingsTable.findingsTableColumn.clusterIdColumnLabel": "属于", - "xpack.csp.findings.findingsTable.findingsTableColumn.clusterIdColumnTooltipLabel": "Kubernetes 集群 ID 或云帐户名称", "xpack.csp.findings.findingsTable.findingsTableColumn.lastCheckedColumnLabel": "上次检查时间", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnLabel": "资源 ID", - "xpack.csp.findings.findingsTable.findingsTableColumn.resourceIdColumnTooltipLabel": "定制 Elastic 资源 ID", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceNameColumnLabel": "资源名称", "xpack.csp.findings.findingsTable.findingsTableColumn.resourceTypeColumnLabel": "资源类型", "xpack.csp.findings.findingsTable.findingsTableColumn.resultColumnLabel": "结果", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleBenchmarkColumnLabel": "适用基准", - "xpack.csp.findings.findingsTable.findingsTableColumn.ruleBenchmarkColumnTooltipLabel": "用于评估此资源的基准", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNameColumnLabel": "规则名称", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleNumberColumnLabel": "规则编号", "xpack.csp.findings.findingsTable.findingsTableColumn.ruleSectionColumnLabel": "CIS 部分", @@ -12228,12 +12204,6 @@ "xpack.csp.findings.groupBySelector.groupByNoneLabel": "无", "xpack.csp.findings.groupBySelector.groupByResourceIdLabel": "资源", "xpack.csp.findings.latestFindings.tableRowTypeLabel": "结果", - "xpack.csp.findings.resourceFindings.backToResourcesPageButtonLabel": "返回到资源", - "xpack.csp.findings.resourceFindings.tableRowTypeLabel": "结果", - "xpack.csp.findings.resourceFindingsSharedValues.cloudAccountName": "云帐户名称", - "xpack.csp.findings.resourceFindingsSharedValues.clusterIdTitle": "集群 ID", - "xpack.csp.findings.resourceFindingsSharedValues.resourceIdTitle": "资源 ID", - "xpack.csp.findings.resourceFindingsSharedValues.resourceTypeTitle": "资源类型", "xpack.csp.findings.search.queryErrorToastMessage": "查询错误", "xpack.csp.findings.searchBar.searchPlaceholder": "搜索结果(例如,rule.section:“APM 服务器”)", "xpack.csp.findings.tabs.misconfigurations": "错误配置", @@ -12348,9 +12318,6 @@ "xpack.csp.vulnerabilities": "漏洞", "xpack.csp.vulnerabilities.flyoutTabs.fieldLabel": "字段", "xpack.csp.vulnerabilities.flyoutTabs.fieldValueLabel": "值", - "xpack.csp.vulnerabilities.resourceVulnerabilities.backToResourcesPageButtonLabel": "返回到资源", - "xpack.csp.vulnerabilities.resourceVulnerabilities.regionTitle": "地区", - "xpack.csp.vulnerabilities.resourceVulnerabilities.resourceIdTitle": "资源 ID", "xpack.csp.vulnerabilities.searchBar.placeholder": "搜索漏洞(例如,vulnerability.severity:“CRITICAL”)", "xpack.csp.vulnerabilities.table.filterIn": "筛选范围", "xpack.csp.vulnerabilities.table.filterOut": "筛除", @@ -12373,24 +12340,12 @@ "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDate": "发布日期", "xpack.csp.vulnerabilitiesByResource.severityMap.tooltipTitle": "严重性映射", "xpack.csp.vulnerability_dashboard.cspPageTemplate.pageTitle": "云原生漏洞管理", - "xpack.csp.vulnerabilityByResourceTable.column.region": "地区", - "xpack.csp.vulnerabilityByResourceTable.column.resourceId": "资源 ID", - "xpack.csp.vulnerabilityByResourceTable.column.resourceName": "资源名称", - "xpack.csp.vulnerabilityByResourceTable.column.severityMap": "严重性映射", - "xpack.csp.vulnerabilityByResourceTable.column.vulnerabilities": "漏洞", "xpack.csp.vulnerabilityDashboard.trendGraphChart.accountsDropDown.option.allTitle": "全部", "xpack.csp.vulnerabilityDashboard.trendGraphChart.accountsDropDown.prepend.accountsTitle": "帐户", "xpack.csp.vulnerabilityDashboard.trendGraphChart.trendBySeverityTitle": "趋势(按严重性)", "xpack.csp.vulnerabilityDashboard.viewAllButton.buttonTitle": "查看全部", - "xpack.csp.vulnerabilityTable.column.fixVersion": "修复版本", - "xpack.csp.vulnerabilityTable.column.package": "软件包", - "xpack.csp.vulnerabilityTable.column.resourceId": "资源 ID", - "xpack.csp.vulnerabilityTable.column.resourceName": "资源名称", - "xpack.csp.vulnerabilityTable.column.severity": "严重性", "xpack.csp.vulnerabilityTable.column.sortAscending": "低 -> 严重", "xpack.csp.vulnerabilityTable.column.sortDescending": "严重 -> 低", - "xpack.csp.vulnerabilityTable.column.version": "版本", - "xpack.csp.vulnerabilityTable.column.vulnerability": "漏洞", "xpack.csp.vulnerabilityTable.panel.buttonText": "查看所有漏洞", "xpack.csp.vulnMgmtIntegration.awsOption.nameTitle": "Amazon Web Services", "xpack.csp.vulnMgmtIntegration.azureOption.nameTitle": "Azure", @@ -30851,11 +30806,7 @@ "xpack.security.accountManagement.apiKeyFlyout.createTitle": "创建 API 密钥", "xpack.security.accountManagement.apiKeyFlyout.crossClusterTypeDescription": "允许远程集群连接到本地集群。", "xpack.security.accountManagement.apiKeyFlyout.crossClusterTypeLabel": "跨集群 API 密钥", - "xpack.security.accountManagement.apiKeyFlyout.customExpirationInputLabel": "寿命", - "xpack.security.accountManagement.apiKeyFlyout.customExpirationLabel": "有效时间", - "xpack.security.accountManagement.apiKeyFlyout.customPrivilegesLabel": "限制权限", "xpack.security.accountManagement.apiKeyFlyout.expirationUnit": "天", - "xpack.security.accountManagement.apiKeyFlyout.includeMetadataLabel": "包括元数据", "xpack.security.accountManagement.apiKeyFlyout.metadataHelpText": "了解如何结构化元数据。", "xpack.security.accountManagement.apiKeyFlyout.nameLabel": "名称", "xpack.security.accountManagement.apiKeyFlyout.ownerLabel": "所有者", diff --git a/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts b/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts index 8983b139d9462..3d1086ca8b8e4 100644 --- a/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts +++ b/x-pack/test/api_integration/apis/asset_manager/tests/helpers.ts @@ -100,5 +100,5 @@ export function generateHostsData({ return range .interval('1m') .rate(1) - .generator((timestamp, index) => hosts.map((host) => host.metrics().timestamp(timestamp))); + .generator((timestamp, index) => hosts.map((host) => host.cpu().timestamp(timestamp))); } diff --git a/x-pack/test/apm_api_integration/tests/time_range_metadata/many_apm_server_versions.spec.ts b/x-pack/test/apm_api_integration/tests/time_range_metadata/many_apm_server_versions.spec.ts index 7f91aaf93d804..012fa07ca6f6c 100644 --- a/x-pack/test/apm_api_integration/tests/time_range_metadata/many_apm_server_versions.spec.ts +++ b/x-pack/test/apm_api_integration/tests/time_range_metadata/many_apm_server_versions.spec.ts @@ -112,23 +112,48 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, }); - const allHasSummaryField = response.body.sources.every((source) => { - if (source.documentType === 'transactionEvent') { - return true; - } + const allHasSummaryField = response.body.sources + .filter( + (source) => + source.documentType === ApmDocumentType.TransactionMetric && + source.rollupInterval !== RollupInterval.OneMinute + ) + .every((source) => { + return source.hasDurationSummaryField; + }); + expect(allHasSummaryField).to.eql(true); + }); + + it('does not support transaction.duration.summary when the field is not supported by all APM server versions', async () => { + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/time_range_metadata', + params: { + query: { + start: startLegacy.toISOString(), + end: end.toISOString(), + enableContinuousRollups: true, + enableServiceTransactionMetrics: true, + useSpanName: false, + kuery: '', + }, + }, + }); + + const allHasSummaryField = response.body.sources.every((source) => { return source.hasDurationSummaryField; }); - expect(allHasSummaryField).to.eql(true); + expect(allHasSummaryField).to.eql(false); }); - it('does not have latency data for synth-java-legacy service', async () => { + it('does not have latency data for synth-java-legacy', async () => { const res = await getLatencyChartForService({ serviceName: 'synth-java-legacy', start, end, apmApiClient, + useDurationSummary: true, }); expect(res.body.currentPeriod.latencyTimeseries.map(({ y }) => y)).to.eql([ @@ -147,6 +172,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { start, end, apmApiClient, + useDurationSummary: true, }); expect(res.body.currentPeriod.latencyTimeseries.map(({ y }) => y)).to.eql([ @@ -169,11 +195,13 @@ function getLatencyChartForService({ start, end, apmApiClient, + useDurationSummary, }: { serviceName: string; start: moment.Moment; end: moment.Moment; apmApiClient: ApmApiClient; + useDurationSummary: boolean; }) { return apmApiClient.readUser({ endpoint: `GET /internal/apm/services/{serviceName}/transactions/charts/latency`, @@ -189,7 +217,7 @@ function getLatencyChartForService({ documentType: ApmDocumentType.TransactionMetric, rollupInterval: RollupInterval.OneMinute, bucketSizeInSeconds: 60, - useDurationSummary: true, + useDurationSummary, }, }, }); @@ -227,8 +255,9 @@ function generateTraceDataForService({ ); const apmPipeline = (base: Readable) => { - // @ts-expect-error - const defaultPipeline: NodeJS.ReadableStream = synthtrace.getDefaultPipeline()(base); + const defaultPipeline = synthtrace.getDefaultPipeline()( + base + ) as unknown as NodeJS.ReadableStream; return pipeline( defaultPipeline, diff --git a/x-pack/test/apm_api_integration/tests/time_range_metadata/time_range_metadata.spec.ts b/x-pack/test/apm_api_integration/tests/time_range_metadata/time_range_metadata.spec.ts index 32303b7b0bb4c..6de17c22c2309 100644 --- a/x-pack/test/apm_api_integration/tests/time_range_metadata/time_range_metadata.spec.ts +++ b/x-pack/test/apm_api_integration/tests/time_range_metadata/time_range_metadata.spec.ts @@ -11,8 +11,13 @@ import { omit, sortBy } from 'lodash'; import moment, { Moment } from 'moment'; import { ApmDocumentType } from '@kbn/apm-plugin/common/document_type'; import { RollupInterval } from '@kbn/apm-plugin/common/rollup'; -import { deleteSummaryFieldTransform } from '@kbn/apm-synthtrace'; +import { + addObserverVersionTransform, + ApmSynthtraceEsClient, + deleteSummaryFieldTransform, +} from '@kbn/apm-synthtrace'; import { Readable, pipeline } from 'stream'; +import { ToolingLog } from '@kbn/tooling-log'; import { FtrProviderContext } from '../../common/ftr_provider_context'; export default function ApiTest({ getService }: FtrProviderContext) { @@ -85,27 +90,21 @@ export default function ApiTest({ getService }: FtrProviderContext) { const withSummaryFieldEnd = moment(withoutSummaryFieldEnd).add(2, 'hours'); before(async () => { - const previousTxEvents = getTransactionEvents( - withoutSummaryFieldStart, - withoutSummaryFieldEnd - ); - - const apmPipeline = (base: Readable) => { - // @ts-expect-error - const defaultPipeline: NodeJS.ReadableStream = - synthtraceEsClient.getDefaultPipeline()(base); - - return pipeline(defaultPipeline, deleteSummaryFieldTransform(), (err) => { - if (err) { - log.error(err); - } - }); - }; - - await synthtraceEsClient.index(previousTxEvents, apmPipeline); + await getTransactionEvents({ + start: withoutSummaryFieldStart, + end: withoutSummaryFieldEnd, + isLegacy: true, + synthtrace: synthtraceEsClient, + logger: log, + }); - const txEvents = getTransactionEvents(withSummaryFieldStart, withSummaryFieldEnd); - await synthtraceEsClient.index(txEvents); + await getTransactionEvents({ + start: withSummaryFieldStart, + end: withSummaryFieldEnd, + isLegacy: false, + synthtrace: synthtraceEsClient, + logger: log, + }); }); after(() => { @@ -123,7 +122,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { response.sources.filter( (source) => source.documentType === ApmDocumentType.TransactionMetric && - source.hasDurationSummaryField === true + source.hasDurationSummaryField ).length ).to.eql(3); }); @@ -138,9 +137,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { response.sources.filter( (source) => source.documentType === ApmDocumentType.TransactionMetric && - source.hasDurationSummaryField === false + !source.hasDurationSummaryField ).length - ).to.eql(3); + ).to.eql(2); }); }); }); @@ -494,7 +493,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { documentType: ApmDocumentType.TransactionMetric, rollupInterval: RollupInterval.OneMinute, hasDocs: false, - hasDurationSummaryField: false, + hasDurationSummaryField: true, }, { documentType: ApmDocumentType.TransactionMetric, @@ -513,7 +512,19 @@ export default function ApiTest({ getService }: FtrProviderContext) { ); } -function getTransactionEvents(start: Moment, end: Moment) { +function getTransactionEvents({ + start, + end, + synthtrace, + logger, + isLegacy = false, +}: { + start: Moment; + end: Moment; + synthtrace: ApmSynthtraceEsClient; + logger: ToolingLog; + isLegacy?: boolean; +}) { const serviceName = 'synth-go'; const transactionName = 'GET /api/product/list'; const GO_PROD_RATE = 15; @@ -523,7 +534,7 @@ function getTransactionEvents(start: Moment, end: Moment) { .service({ name: serviceName, environment: 'production', agentName: 'go' }) .instance('instance-a'); - return [ + const events = [ timerange(start, end) .interval('1m') .rate(GO_PROD_RATE) @@ -546,4 +557,23 @@ function getTransactionEvents(start: Moment, end: Moment) { .failure() ), ]; + + const apmPipeline = (base: Readable) => { + const defaultPipeline = synthtrace.getDefaultPipeline()( + base + ) as unknown as NodeJS.ReadableStream; + + return pipeline( + defaultPipeline, + addObserverVersionTransform('8.5.0'), + deleteSummaryFieldTransform(), + (err) => { + if (err) { + logger.error(err); + } + } + ); + }; + + return synthtrace.index(events, isLegacy ? apmPipeline : undefined); } diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts index eb7ea67560154..5c42f0e9bf9ae 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/findings_page.ts @@ -12,6 +12,10 @@ import type { FtrProviderContext } from '../ftr_provider_context'; // Defined in CSP plugin const FINDINGS_INDEX = 'logs-cloud_security_posture.findings-default'; const FINDINGS_LATEST_INDEX = 'logs-cloud_security_posture.findings_latest-default'; +export const VULNERABILITIES_INDEX_DEFAULT_NS = + 'logs-cloud_security_posture.vulnerabilities-default'; +export const LATEST_VULNERABILITIES_INDEX_DEFAULT_NS = + 'logs-cloud_security_posture.vulnerabilities_latest-default'; export function FindingsPageProvider({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); @@ -35,49 +39,49 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider log.debug('CSP plugin is initialized'); }); + const deleteByQuery = async (index: string) => { + await es.deleteByQuery({ + index, + query: { + match_all: {}, + }, + ignore_unavailable: true, + refresh: true, + }); + }; + + const insertOperation = (index: string, findingsMock: Array>) => { + return findingsMock.flatMap((doc) => [{ index: { _index: index } }, doc]); + }; + const index = { + remove: () => + Promise.all([deleteByQuery(FINDINGS_INDEX), deleteByQuery(FINDINGS_LATEST_INDEX)]), + add: async (findingsMock: Array>) => { + await es.bulk({ + refresh: true, + operations: [ + ...insertOperation(FINDINGS_INDEX, findingsMock), + ...insertOperation(FINDINGS_LATEST_INDEX, findingsMock), + ], + }); + }, + }; + + const vulnerabilitiesIndex = { remove: () => Promise.all([ - es.deleteByQuery({ - index: FINDINGS_INDEX, - query: { - match_all: {}, - }, - ignore_unavailable: true, - refresh: true, - }), - es.deleteByQuery({ - index: FINDINGS_LATEST_INDEX, - query: { - match_all: {}, - }, - ignore_unavailable: true, - refresh: true, - }), + deleteByQuery(VULNERABILITIES_INDEX_DEFAULT_NS), + deleteByQuery(LATEST_VULNERABILITIES_INDEX_DEFAULT_NS), ]), add: async (findingsMock: Array>) => { - await Promise.all([ - ...findingsMock.map((finding) => - es.index({ - index: FINDINGS_INDEX, - body: { - ...finding, - '@timestamp': finding['@timestamp'] ?? new Date().toISOString(), - }, - refresh: true, - }) - ), - ...findingsMock.map((finding) => - es.index({ - index: FINDINGS_LATEST_INDEX, - body: { - ...finding, - '@timestamp': finding['@timestamp'] ?? new Date().toISOString(), - }, - refresh: true, - }) - ), - ]); + await es.bulk({ + refresh: true, + operations: [ + ...insertOperation(VULNERABILITIES_INDEX_DEFAULT_NS, findingsMock), + ...insertOperation(LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, findingsMock), + ], + }); }, }; @@ -229,122 +233,15 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider }, }); - const createTableObject = (tableTestSubject: string) => ({ - getElement() { - return testSubjects.find(tableTestSubject); - }, - - async getHeaders() { - const element = await this.getElement(); - return await element.findAllByCssSelector('thead tr :is(th,td)'); - }, - - async getColumnIndex(columnName: string) { - const headers = await this.getHeaders(); - const texts = await Promise.all(headers.map((header) => header.getVisibleText())); - const columnIndex = texts.findIndex((i) => i === columnName); - expect(columnIndex).to.be.greaterThan(-1); - return columnIndex + 1; - }, - - async getColumnHeaderCell(columnName: string) { - const headers = await this.getHeaders(); - const headerIndexes = await Promise.all(headers.map((header) => header.getVisibleText())); - const columnIndex = headerIndexes.findIndex((i) => i === columnName); - return headers[columnIndex]; - }, - - async getRowsCount() { - const element = await this.getElement(); - const rows = await element.findAllByCssSelector('tbody tr'); - return rows.length; - }, - - async getFindingsCount(type: 'passed' | 'failed') { - const element = await this.getElement(); - const items = await element.findAllByCssSelector(`span[data-test-subj="${type}_finding"]`); - return items.length; - }, - - async getRowIndexForValue(columnName: string, value: string) { - const values = await this.getColumnValues(columnName); - const rowIndex = values.indexOf(value); - expect(rowIndex).to.be.greaterThan(-1); - return rowIndex + 1; - }, - - async getFilterElementButton(rowIndex: number, columnIndex: number, negated = false) { - const tableElement = await this.getElement(); - const button = negated - ? 'findings_table_cell_add_negated_filter' - : 'findings_table_cell_add_filter'; - const selector = `tbody tr:nth-child(${rowIndex}) td:nth-child(${columnIndex}) button[data-test-subj="${button}"]`; - return tableElement.findByCssSelector(selector); - }, - - async addCellFilter(columnName: string, cellValue: string, negated = false) { - const columnIndex = await this.getColumnIndex(columnName); - const rowIndex = await this.getRowIndexForValue(columnName, cellValue); - const filterElement = await this.getFilterElementButton(rowIndex, columnIndex, negated); - await filterElement.click(); - }, - - async getColumnValues(columnName: string) { - const elementsWithNoFilterCell = ['CIS Section', '@timestamp']; - const tableElement = await this.getElement(); - const columnIndex = await this.getColumnIndex(columnName); - const selector = elementsWithNoFilterCell.includes(columnName) - ? `tbody tr td:nth-child(${columnIndex})` - : `tbody tr td:nth-child(${columnIndex}) div[data-test-subj="filter_cell_value"]`; - const columnCells = await tableElement.findAllByCssSelector(selector); - - return await Promise.all(columnCells.map((cell) => cell.getVisibleText())); - }, - - async hasColumnValue(columnName: string, value: string) { - const values = await this.getColumnValues(columnName); - return values.includes(value); - }, - - async toggleColumnSort(columnName: string, direction: 'asc' | 'desc') { - const element = await this.getColumnHeaderCell(columnName); - const currentSort = await element.getAttribute('aria-sort'); - if (currentSort === 'none') { - // a click is needed to focus on Eui column header - await element.click(); - - // default is ascending - if (direction === 'desc') { - const nonStaleElement = await this.getColumnHeaderCell(columnName); - await nonStaleElement.click(); - } - } - if ( - (currentSort === 'ascending' && direction === 'desc') || - (currentSort === 'descending' && direction === 'asc') - ) { - // Without getting the element again, the click throws an error (stale element reference) - const nonStaleElement = await this.getColumnHeaderCell(columnName); - await nonStaleElement.click(); - } - }, - - async openFlyoutAt(rowIndex: number) { - const table = await this.getElement(); - const flyoutButton = await table.findAllByTestSubject('findings_table_expand_column'); - await flyoutButton[rowIndex].click(); - }, - }); - const navigateToLatestFindingsPage = async () => { await PageObjects.common.navigateToUrl( 'securitySolution', // Defined in Security Solution plugin - 'cloud_security_posture/findings', + 'cloud_security_posture/findings/configurations', { shouldUseHashForSubUrl: false } ); }; - const navigateToVulnerabilities = async () => { + const navigateToLatestVulnerabilitiesPage = async () => { await PageObjects.common.navigateToUrl( 'securitySolution', // Defined in Security Solution plugin 'cloud_security_posture/findings/vulnerabilities', @@ -361,20 +258,8 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider }; const latestFindingsTable = createDataTableObject('latest_findings_table'); - const resourceFindingsTable = createTableObject('resource_findings_table'); - const findingsByResourceTable = { - ...createTableObject('findings_by_resource_table'), - async clickResourceIdLink(resourceId: string, sectionName: string) { - const table = await this.getElement(); - const row = await table.findByCssSelector( - `[data-test-subj="findings_resource_table_row_${resourceId}/${sectionName}"]` - ); - const link = await row.findByCssSelector( - '[data-test-subj="findings_by_resource_table_resource_id_column"' - ); - await link.click(); - }, - }; + const latestVulnerabilitiesTable = createDataTableObject('latest_vulnerabilities_table'); + const notInstalledVulnerabilities = createNotInstalledObject('cnvm-integration-not-installed'); const notInstalledCSP = createNotInstalledObject('cloud_posture_page_package_not_installed'); @@ -463,14 +348,14 @@ export function FindingsPageProvider({ getService, getPageObjects }: FtrProvider return { navigateToLatestFindingsPage, - navigateToVulnerabilities, + navigateToLatestVulnerabilitiesPage, navigateToMisconfigurations, latestFindingsTable, - resourceFindingsTable, - findingsByResourceTable, + latestVulnerabilitiesTable, notInstalledVulnerabilities, notInstalledCSP, index, + vulnerabilitiesIndex, waitForPluginInitialized, distributionBar, vulnerabilityDataGrid, diff --git a/x-pack/test/cloud_security_posture_functional/pages/findings_onboarding.ts b/x-pack/test/cloud_security_posture_functional/pages/findings_onboarding.ts index 4919e4102df87..765dc7fae1370 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/findings_onboarding.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/findings_onboarding.ts @@ -28,7 +28,7 @@ export default ({ getPageObjects }: FtrProviderContext) => { }); it('clicking on the `No integrations installed` prompt action button - `install CNVM`: navigates to the CNVM integration installation page', async () => { - await findings.navigateToVulnerabilities(); + await findings.navigateToLatestVulnerabilitiesPage(); await PageObjects.header.waitUntilLoadingHasFinished(); const element = await notInstalledVulnerabilities.getElement(); expect(element).to.not.be(null); diff --git a/x-pack/test/cloud_security_posture_functional/pages/index.ts b/x-pack/test/cloud_security_posture_functional/pages/index.ts index 9da8cbbeeed54..f4039dc08466f 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/index.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/index.ts @@ -18,5 +18,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./vulnerability_dashboard')); loadTestFile(require.resolve('./cis_integration')); loadTestFile(require.resolve('./findings_old_data')); + loadTestFile(require.resolve('./vulnerabilities')); + loadTestFile(require.resolve('./vulnerabilities_grouping')); }); } diff --git a/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities.ts b/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities.ts new file mode 100644 index 0000000000000..d882d1765f752 --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities.ts @@ -0,0 +1,183 @@ +/* + * 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 expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; +import { vulnerabilitiesLatestMock } from '../mocks/vulnerabilities_latest_mock'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const queryBar = getService('queryBar'); + const filterBar = getService('filterBar'); + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const pageObjects = getPageObjects(['common', 'findings', 'header']); + + const resourceName1 = 'name-ng-1-Node'; + const resourceName2 = 'othername-june12-8-8-0-1'; + + describe('Vulnerabilities Page - DataTable', function () { + this.tags(['cloud_security_posture_vulnerabilities']); + let findings: typeof pageObjects.findings; + let latestVulnerabilitiesTable: typeof findings.latestVulnerabilitiesTable; + + before(async () => { + findings = pageObjects.findings; + latestVulnerabilitiesTable = findings.latestVulnerabilitiesTable; + + // Before we start any test we must wait for cloud_security_posture plugin to complete its initialization + await findings.waitForPluginInitialized(); + + // Prepare mocked findings + await findings.vulnerabilitiesIndex.remove(); + await findings.vulnerabilitiesIndex.add(vulnerabilitiesLatestMock); + + await findings.navigateToLatestVulnerabilitiesPage(); + await retry.waitFor( + 'Findings table to be loaded', + async () => + (await latestVulnerabilitiesTable.getRowsCount()) === vulnerabilitiesLatestMock.length + ); + pageObjects.header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + await findings.vulnerabilitiesIndex.remove(); + }); + + describe('SearchBar', () => { + it('add filter', async () => { + // Filter bar uses the field's customLabel in the DataView + await filterBar.addFilter({ + field: 'Resource Name', + operation: 'is', + value: resourceName1, + }); + + expect(await filterBar.hasFilter('resource.name', resourceName1)).to.be(true); + expect( + await latestVulnerabilitiesTable.hasColumnValue('resource.name', resourceName1) + ).to.be(true); + }); + + it('remove filter', async () => { + await filterBar.removeFilter('resource.name'); + + expect(await filterBar.hasFilter('resource.name', resourceName1)).to.be(false); + expect(await latestVulnerabilitiesTable.getRowsCount()).to.be( + vulnerabilitiesLatestMock.length + ); + }); + + it('set search query', async () => { + await queryBar.setQuery(resourceName1); + await queryBar.submitQuery(); + + expect( + await latestVulnerabilitiesTable.hasColumnValue('resource.name', resourceName1) + ).to.be(true); + expect( + await latestVulnerabilitiesTable.hasColumnValue('resource.name', resourceName2) + ).to.be(false); + + await queryBar.setQuery(''); + await queryBar.submitQuery(); + + expect(await latestVulnerabilitiesTable.getRowsCount()).to.be( + vulnerabilitiesLatestMock.length + ); + }); + }); + + describe('DataTable features', () => { + it('Edit data view field option is Enabled', async () => { + await latestVulnerabilitiesTable.toggleEditDataViewFieldsOption('vulnerability.id'); + expect(await testSubjects.find('gridEditFieldButton')).to.be.ok(); + await latestVulnerabilitiesTable.toggleEditDataViewFieldsOption('vulnerability.id'); + }); + }); + + describe('Vulnerabilities - Fields selector', () => { + const CSP_FIELDS_SELECTOR_MODAL = 'cloudSecurityFieldsSelectorModal'; + const CSP_FIELDS_SELECTOR_OPEN_BUTTON = 'cloudSecurityFieldsSelectorOpenButton'; + const CSP_FIELDS_SELECTOR_RESET_BUTTON = 'cloudSecurityFieldsSelectorResetButton'; + const CSP_FIELDS_SELECTOR_CLOSE_BUTTON = 'cloudSecurityFieldsSelectorCloseButton'; + + it('Add fields to the Vulnerabilities DataTable', async () => { + const fieldsButton = await testSubjects.find(CSP_FIELDS_SELECTOR_OPEN_BUTTON); + await fieldsButton.click(); + await testSubjects.existOrFail(CSP_FIELDS_SELECTOR_MODAL); + + const agentIdCheckbox = await testSubjects.find( + 'cloud-security-fields-selector-item-agent.id' + ); + await agentIdCheckbox.click(); + + const agentNameCheckbox = await testSubjects.find( + 'cloud-security-fields-selector-item-agent.name' + ); + await agentNameCheckbox.click(); + + await testSubjects.existOrFail('dataGridHeaderCell-agent.id'); + await testSubjects.existOrFail('dataGridHeaderCell-agent.name'); + + const closeFieldsButton = await testSubjects.find(CSP_FIELDS_SELECTOR_CLOSE_BUTTON); + await closeFieldsButton.click(); + await testSubjects.missingOrFail(CSP_FIELDS_SELECTOR_MODAL); + }); + + it('Remove fields from the Vulnerabilities DataTable', async () => { + const fieldsButton = await testSubjects.find(CSP_FIELDS_SELECTOR_OPEN_BUTTON); + await fieldsButton.click(); + + const agentIdCheckbox = await testSubjects.find( + 'cloud-security-fields-selector-item-agent.id' + ); + await agentIdCheckbox.click(); + + const agentNameCheckbox = await testSubjects.find( + 'cloud-security-fields-selector-item-agent.name' + ); + await agentNameCheckbox.click(); + + await testSubjects.missingOrFail('dataGridHeaderCell-agent.id'); + await testSubjects.missingOrFail('dataGridHeaderCell-agent.name'); + + const closeFieldsButton = await testSubjects.find(CSP_FIELDS_SELECTOR_CLOSE_BUTTON); + await closeFieldsButton.click(); + await testSubjects.missingOrFail(CSP_FIELDS_SELECTOR_MODAL); + }); + it('Reset fields to default', async () => { + const fieldsButton = await testSubjects.find(CSP_FIELDS_SELECTOR_OPEN_BUTTON); + await fieldsButton.click(); + + const agentIdCheckbox = await testSubjects.find( + 'cloud-security-fields-selector-item-agent.id' + ); + await agentIdCheckbox.click(); + + const agentNameCheckbox = await testSubjects.find( + 'cloud-security-fields-selector-item-agent.name' + ); + await agentNameCheckbox.click(); + + await testSubjects.existOrFail('dataGridHeaderCell-agent.id'); + await testSubjects.existOrFail('dataGridHeaderCell-agent.name'); + + const resetFieldsButton = await testSubjects.find(CSP_FIELDS_SELECTOR_RESET_BUTTON); + await resetFieldsButton.click(); + + await testSubjects.missingOrFail('dataGridHeaderCell-agent.id'); + await testSubjects.missingOrFail('dataGridHeaderCell-agent.name'); + + const closeFieldsButton = await testSubjects.find(CSP_FIELDS_SELECTOR_CLOSE_BUTTON); + await closeFieldsButton.click(); + await testSubjects.missingOrFail(CSP_FIELDS_SELECTOR_MODAL); + }); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities_grouping.ts b/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities_grouping.ts new file mode 100644 index 0000000000000..8e569d27b8a4d --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/pages/vulnerabilities_grouping.ts @@ -0,0 +1,160 @@ +/* + * 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 expect from '@kbn/expect'; +import { asyncForEach } from '@kbn/std'; +import type { FtrProviderContext } from '../ftr_provider_context'; +import { vulnerabilitiesLatestMock } from '../mocks/vulnerabilities_latest_mock'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const queryBar = getService('queryBar'); + const filterBar = getService('filterBar'); + const pageObjects = getPageObjects(['common', 'findings', 'header']); + + const resourceName1 = 'name-ng-1-Node'; + const resourceName2 = 'othername-june12-8-8-0-1'; + + describe('Vulnerabilities Page - Grouping', function () { + this.tags(['cloud_security_posture_findings_grouping']); + let findings: typeof pageObjects.findings; + + before(async () => { + findings = pageObjects.findings; + + // Before we start any test we must wait for cloud_security_posture plugin to complete its initialization + await findings.waitForPluginInitialized(); + + // Prepare mocked findings + await findings.vulnerabilitiesIndex.remove(); + await findings.vulnerabilitiesIndex.add(vulnerabilitiesLatestMock); + + await findings.navigateToLatestVulnerabilitiesPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + const groupSelector = await findings.groupSelector(); + await groupSelector.openDropDown(); + await groupSelector.setValue('None'); + await findings.vulnerabilitiesIndex.remove(); + }); + + describe('Default Grouping', async () => { + it('groups vulnerabilities by resource and sort by compliance score desc', async () => { + const groupSelector = await findings.groupSelector(); + await groupSelector.openDropDown(); + await groupSelector.setValue('Resource'); + + const grouping = await findings.findingsGrouping(); + + const resourceOrder = [ + { + resourceName: resourceName1, + resourceId: vulnerabilitiesLatestMock[0].resource.id, + findingsCount: '1', + }, + { + resourceName: resourceName2, + resourceId: vulnerabilitiesLatestMock[1].resource.id, + findingsCount: '1', + }, + ]; + + await asyncForEach( + resourceOrder, + async ({ resourceName, resourceId, findingsCount }, index) => { + const groupRow = await grouping.getRowAtIndex(index); + expect(await groupRow.getVisibleText()).to.contain(resourceName); + expect(await groupRow.getVisibleText()).to.contain(resourceId); + expect( + await ( + await groupRow.findByTestSubject('vulnerabilities_grouping_counter') + ).getVisibleText() + ).to.be(findingsCount); + } + ); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('2 groups'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('2 vulnerabilities'); + }); + }); + describe('SearchBar', () => { + it('add filter', async () => { + // Filter bar uses the field's customLabel in the DataView + await filterBar.addFilter({ + field: 'Resource Name', + operation: 'is', + value: resourceName1, + }); + expect(await filterBar.hasFilter('resource.name', resourceName1)).to.be(true); + + const grouping = await findings.findingsGrouping(); + + const groupRow = await grouping.getRowAtIndex(0); + expect(await groupRow.getVisibleText()).to.contain(resourceName1); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('1 group'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('1 vulnerability'); + }); + + it('remove filter', async () => { + await filterBar.removeFilter('resource.name'); + + expect(await filterBar.hasFilter('resource.name', resourceName1)).to.be(false); + + const grouping = await findings.findingsGrouping(); + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('2 groups'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('2 vulnerabilities'); + }); + + it('set search query', async () => { + await queryBar.setQuery(resourceName1); + await queryBar.submitQuery(); + + const grouping = await findings.findingsGrouping(); + + const groupRow = await grouping.getRowAtIndex(0); + expect(await groupRow.getVisibleText()).to.contain(resourceName1); + + const groupCount = await grouping.getGroupCount(); + expect(groupCount).to.be('1 group'); + + const unitCount = await grouping.getUnitCount(); + expect(unitCount).to.be('1 vulnerability'); + + await queryBar.setQuery(''); + await queryBar.submitQuery(); + + expect(await grouping.getGroupCount()).to.be('2 groups'); + expect(await grouping.getUnitCount()).to.be('2 vulnerabilities'); + }); + }); + + describe('Group table', async () => { + it('shows vulnerabilities table when expanding', async () => { + const grouping = await findings.findingsGrouping(); + const firstRow = await grouping.getRowAtIndex(0); + await (await firstRow.findByCssSelector('button')).click(); + const latestFindingsTable = findings.createDataTableObject('latest_vulnerabilities_table'); + expect(await latestFindingsTable.getRowsCount()).to.be(1); + expect(await latestFindingsTable.hasColumnValue('resource.name', resourceName1)).to.be( + true + ); + }); + }); + }); +} diff --git a/x-pack/test/fleet_api_integration/apis/agents/list.ts b/x-pack/test/fleet_api_integration/apis/agents/list.ts index 4bf7e84d70e7f..91796d5a9b9dd 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/list.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/list.ts @@ -17,10 +17,8 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); let elasticAgentpkgVersion: string; - // Failing: See https://github.com/elastic/kibana/issues/170690 - // Failing: See https://github.com/elastic/kibana/issues/170690 - // Failing: See https://github.com/elastic/kibana/issues/170690 - describe.skip('fleet_list_agent', () => { + + describe('fleet_list_agent', () => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/fleet/agents'); const getPkRes = await supertest @@ -159,6 +157,7 @@ export default function ({ getService }: FtrProviderContext) { dataset: 'elastic_agent.elastic_agent', }, elastic_agent: { id: 'agent1', process: 'elastic_agent' }, + component: { id: 'component1' }, system: { process: { memory: { @@ -179,6 +178,7 @@ export default function ({ getService }: FtrProviderContext) { document: { '@timestamp': new Date(now - 1 * 60 * 1000).toISOString(), elastic_agent: { id: 'agent1', process: 'elastic_agent' }, + component: { id: 'component2' }, data_stream: { namespace: 'default', type: 'metrics', diff --git a/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts b/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts index 06a67a13e425c..a257ff97933d9 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/data_stream.ts @@ -41,43 +41,46 @@ export default function (providerContext: FtrProviderContext) { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); + const writeMetricsDoc = (namespace: string) => + es.transport.request( + { + method: 'POST', + path: `/${metricsTemplateName}-${namespace}/_doc?refresh=true`, + body: { + '@timestamp': new Date().toISOString(), + logs_test_name: 'test', + data_stream: { + dataset: `${pkgName}.test_metrics`, + namespace, + type: 'metrics', + }, + }, + }, + { meta: true } + ); + + const writeLogsDoc = (namespace: string) => + es.transport.request( + { + method: 'POST', + path: `/${logsTemplateName}-${namespace}/_doc?refresh=true`, + body: { + '@timestamp': new Date().toISOString(), + logs_test_name: 'test', + data_stream: { + dataset: `${pkgName}.test_logs`, + namespace, + type: 'logs', + }, + }, + }, + { meta: true } + ); beforeEach(async () => { await installPackage(pkgName, pkgVersion); await Promise.all( namespaces.map(async (namespace) => { - const createLogsRequest = es.transport.request( - { - method: 'POST', - path: `/${logsTemplateName}-${namespace}/_doc`, - body: { - '@timestamp': '2015-01-01', - logs_test_name: 'test', - data_stream: { - dataset: `${pkgName}.test_logs`, - namespace, - type: 'logs', - }, - }, - }, - { meta: true } - ); - const createMetricsRequest = es.transport.request( - { - method: 'POST', - path: `/${metricsTemplateName}-${namespace}/_doc`, - body: { - '@timestamp': '2015-01-01', - logs_test_name: 'test', - data_stream: { - dataset: `${pkgName}.test_metrics`, - namespace, - type: 'metrics', - }, - }, - }, - { meta: true } - ); - return Promise.all([createLogsRequest, createMetricsRequest]); + return Promise.all([writeLogsDoc(namespace), writeMetricsDoc(namespace)]); }) ); }); @@ -141,7 +144,11 @@ export default function (providerContext: FtrProviderContext) { it('after update, it should have rolled over logs datastream because mappings are not compatible and not metrics', async function () { await installPackage(pkgName, pkgUpdateVersion); + await asyncForEach(namespaces, async (namespace) => { + // write doc as rollover is lazy + await writeLogsDoc(namespace); + await writeMetricsDoc(namespace); const resLogsDatastream = await es.transport.request( { method: 'GET', @@ -266,6 +273,8 @@ export default function (providerContext: FtrProviderContext) { }) .expect(200); + // Write a doc to trigger lazy rollover + await writeLogsDoc('default'); // Datastream should have been rolled over expect(await getLogsDefaultBackingIndicesLength()).to.be(2); }); @@ -303,26 +312,29 @@ export default function (providerContext: FtrProviderContext) { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); - beforeEach(async () => { - await installPackage(pkgName, pkgVersion); - - // Create a sample document so the data stream is created - await es.transport.request( + const writeMetricDoc = (body: any = {}) => + es.transport.request( { method: 'POST', - path: `/${metricsTemplateName}-${namespace}/_doc`, + path: `/${metricsTemplateName}-${namespace}/_doc?refresh=true`, body: { - '@timestamp': '2015-01-01', + '@timestamp': new Date().toISOString(), logs_test_name: 'test', data_stream: { dataset: `${pkgName}.test_logs`, namespace, type: 'logs', }, + ...body, }, }, { meta: true } ); + beforeEach(async () => { + await installPackage(pkgName, pkgVersion); + + // Create a sample document so the data stream is created + await writeMetricDoc(); }); afterEach(async () => { @@ -340,6 +352,10 @@ export default function (providerContext: FtrProviderContext) { it('rolls over data stream when index_mode: time_series is set in the updated package version', async () => { await installPackage(pkgName, pkgUpdateVersion); + // Write a doc so lazy rollover can happen + await writeMetricDoc({ + some_field: 'test', + }); const resMetricsDatastream = await es.transport.request( { method: 'GET', diff --git a/x-pack/test/fleet_api_integration/apis/epm/get.ts b/x-pack/test/fleet_api_integration/apis/epm/get.ts index 045a6d034a0a0..7b79272bbef0b 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/get.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/get.ts @@ -13,6 +13,7 @@ import { FtrProviderContext } from '../../../api_integration/ftr_provider_contex import { skipIfNoDockerRegistry } from '../../helpers'; import { setupFleetAndAgents } from '../agents/services'; import { testUsers } from '../test_users'; +import { bundlePackage, removeBundledPackages } from './install_bundled'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; @@ -22,6 +23,7 @@ export default function (providerContext: FtrProviderContext) { const testPkgName = 'apache'; const testPkgVersion = '0.1.4'; + const log = getService('log'); const uninstallPackage = async (name: string, version: string) => { await supertest.delete(`/api/fleet/epm/packages/${name}/${version}`).set('kbn-xsrf', 'xxxx'); @@ -38,8 +40,7 @@ export default function (providerContext: FtrProviderContext) { '../fixtures/direct_upload_packages/apache_0.1.4.zip' ); - // FLAKY: https://github.com/elastic/kibana/issues/163203 - describe.skip('EPM - get', () => { + describe('EPM - get', () => { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); @@ -114,6 +115,7 @@ export default function (providerContext: FtrProviderContext) { before(async () => { await installPackage(testPkgName, testPkgVersion); await installPackage('experimental', '0.1.0'); + await bundlePackage('endpoint-8.6.1'); await installPackage('endpoint', '8.6.1'); }); after(async () => { @@ -121,6 +123,9 @@ export default function (providerContext: FtrProviderContext) { await uninstallPackage('experimental', '0.1.0'); await uninstallPackage('endpoint', '8.6.1'); }); + after(async () => { + await removeBundledPackages(log); + }); it('Allows the fetching of installed packages', async () => { const res = await supertest.get(`/api/fleet/epm/packages/installed`).expect(200); const packages = res.body.items; diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts b/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts index 3fdb609129994..4b91e8ac88e54 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_bundled.ts @@ -9,58 +9,59 @@ import expect from '@kbn/expect'; import fs from 'fs/promises'; import path from 'path'; +import { ToolingLog } from '@kbn/tooling-log'; import { BUNDLED_PACKAGE_DIR } from '../../config.base'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { skipIfNoDockerRegistry } from '../../helpers'; import { setupFleetAndAgents } from '../agents/services'; -export default function (providerContext: FtrProviderContext) { - const { getService } = providerContext; - const supertest = getService('supertest'); - const log = getService('log'); - - const BUNDLED_PACKAGE_FIXTURES_DIR = path.join( - path.dirname(__filename), - '../fixtures/bundled_packages' +const BUNDLED_PACKAGE_FIXTURES_DIR = path.join( + path.dirname(__filename), + '../fixtures/bundled_packages' +); + +export const bundlePackage = async (name: string) => { + try { + await fs.access(BUNDLED_PACKAGE_DIR); + } catch (error) { + await fs.mkdir(BUNDLED_PACKAGE_DIR); + } + + await fs.copyFile( + path.join(BUNDLED_PACKAGE_FIXTURES_DIR, `${name}.zip`), + path.join(BUNDLED_PACKAGE_DIR, `${name}.zip`) ); +}; - const bundlePackage = async (name: string) => { - try { - await fs.access(BUNDLED_PACKAGE_DIR); - } catch (error) { - await fs.mkdir(BUNDLED_PACKAGE_DIR); - } - - await fs.copyFile( - path.join(BUNDLED_PACKAGE_FIXTURES_DIR, `${name}.zip`), - path.join(BUNDLED_PACKAGE_DIR, `${name}.zip`) - ); - }; +export const removeBundledPackages = async (log: ToolingLog) => { + try { + const files = await fs.readdir(BUNDLED_PACKAGE_DIR); - const removeBundledPackages = async () => { - try { - const files = await fs.readdir(BUNDLED_PACKAGE_DIR); + for (const file of files) { + const isFixtureFile = !!(await fs.readFile(path.join(BUNDLED_PACKAGE_FIXTURES_DIR, file))); - for (const file of files) { - const isFixtureFile = !!(await fs.readFile(path.join(BUNDLED_PACKAGE_FIXTURES_DIR, file))); - - // Only remove fixture files - leave normal bundled packages in place - if (isFixtureFile) { - await fs.unlink(path.join(BUNDLED_PACKAGE_DIR, file)); - } + // Only remove fixture files - leave normal bundled packages in place + if (isFixtureFile) { + await fs.unlink(path.join(BUNDLED_PACKAGE_DIR, file)); } - } catch (error) { - log.error('Error removing bundled packages'); - log.error(error); } - }; + } catch (error) { + log.error('Error removing bundled packages'); + log.error(error); + } +}; + +export default function (providerContext: FtrProviderContext) { + const { getService } = providerContext; + const supertest = getService('supertest'); + const log = getService('log'); describe('installing bundled packages', async () => { skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); afterEach(async () => { - await removeBundledPackages(); + await removeBundledPackages(log); }); describe('without registry', () => { diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_endpoint.ts b/x-pack/test/fleet_api_integration/apis/epm/install_endpoint.ts index 892f89f7c2bb6..a4f313383f06c 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_endpoint.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_endpoint.ts @@ -9,14 +9,14 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; import { skipIfNoDockerRegistry } from '../../helpers'; import { setupFleetAndAgents } from '../agents/services'; +import { bundlePackage, removeBundledPackages } from './install_bundled'; export default function (providerContext: FtrProviderContext) { /** * There are a few features that are only currently supported for the Endpoint * package due to security concerns. */ - // Failing: See https://github.com/elastic/kibana/issues/156941 - describe.skip('Install endpoint package', () => { + describe('Install endpoint package', () => { const { getService } = providerContext; skipIfNoDockerRegistry(providerContext); setupFleetAndAgents(providerContext); @@ -25,8 +25,9 @@ export default function (providerContext: FtrProviderContext) { const dockerServers = getService('dockerServers'); const server = dockerServers.get('registry'); const es = getService('es'); + const log = getService('log'); const pkgName = 'endpoint'; - let pkgVersion: string; + const pkgVersion = '8.6.1'; const transforms = [ { @@ -39,12 +40,21 @@ export default function (providerContext: FtrProviderContext) { }, ]; + const installPackage = async (name: string, version: string) => { + await supertest + .post(`/api/fleet/epm/packages/${name}/${version}`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true }); + }; + before(async () => { if (!server.enabled) return; - // The latest endpoint package is already installed by default in our FTR config, - // just get the most recent version number. - const getResp = await supertest.get(`/api/fleet/epm/packages/${pkgName}`).expect(200); - pkgVersion = getResp.body.response.version; + await bundlePackage('endpoint-8.6.1'); + await installPackage('endpoint', '8.6.1'); + }); + after(async () => { + await uninstallPackage('endpoint', '8.6.1'); + await removeBundledPackages(log); }); describe('install', () => { diff --git a/x-pack/test/fleet_api_integration/apis/epm/install_hidden_datastreams.ts b/x-pack/test/fleet_api_integration/apis/epm/install_hidden_datastreams.ts index 2fe976352944a..2ec6fb92000e3 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/install_hidden_datastreams.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/install_hidden_datastreams.ts @@ -34,46 +34,50 @@ export default function (providerContext: FtrProviderContext) { .send({ force: true }) .expect(200); - await es.index({ - index: 'metrics-apm.service_summary.10m-default', - document: { - '@timestamp': '2023-05-30T07:50:00.000Z', - agent: { - name: 'go', - }, - data_stream: { - dataset: 'apm.service_summary.10m', - namespace: 'default', - type: 'metrics', - }, - ecs: { - version: '8.6.0-dev', - }, - event: { - agent_id_status: 'missing', - ingested: '2023-05-30T07:57:12Z', - }, - metricset: { - interval: '10m', - name: 'service_summary', - }, - observer: { - hostname: '047e282994fb', - type: 'apm-server', - version: '8.7.0', - }, - processor: { - event: 'metric', - name: 'metric', - }, - service: { - language: { + const writeDoc = () => + es.index({ + refresh: true, + index: 'metrics-apm.service_summary.10m-default', + document: { + '@timestamp': '2023-05-30T07:50:00.000Z', + agent: { name: 'go', }, - name: '___main_elastic_cloud_87_ilm_fix', + data_stream: { + dataset: 'apm.service_summary.10m', + namespace: 'default', + type: 'metrics', + }, + ecs: { + version: '8.6.0-dev', + }, + event: { + agent_id_status: 'missing', + ingested: '2023-05-30T07:57:12Z', + }, + metricset: { + interval: '10m', + name: 'service_summary', + }, + observer: { + hostname: '047e282994fb', + type: 'apm-server', + version: '8.7.0', + }, + processor: { + event: 'metric', + name: 'metric', + }, + service: { + language: { + name: 'go', + }, + name: '___main_elastic_cloud_87_ilm_fix', + }, }, - }, - }); + }); + + await writeDoc(); await supertest .post(`/api/fleet/epm/packages/apm/8.8.0`) @@ -81,6 +85,8 @@ export default function (providerContext: FtrProviderContext) { .send({ force: true }) .expect(200); + // Rollover are lazy need to write a new doc + await writeDoc(); const ds = await es.indices.get({ index: 'metrics-apm.service_summary*', expand_wildcards: ['open', 'hidden'], diff --git a/x-pack/test/fleet_api_integration/apis/epm/list.ts b/x-pack/test/fleet_api_integration/apis/epm/list.ts index e07c215e4ad9f..6bccbc37a678c 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/list.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/list.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../../api_integration/ftr_provider_contex import { skipIfNoDockerRegistry } from '../../helpers'; import { setupFleetAndAgents } from '../agents/services'; import { testUsers } from '../test_users'; +import { bundlePackage, removeBundledPackages } from './install_bundled'; export default function (providerContext: FtrProviderContext) { const { getService } = providerContext; @@ -21,9 +22,9 @@ export default function (providerContext: FtrProviderContext) { // because `this` has to point to the Mocha context // see https://mochajs.org/#arrow-functions - // FLAKY: https://github.com/elastic/kibana/issues/167188 - describe.skip('EPM - list', async function () { + describe('EPM - list', async function () { skipIfNoDockerRegistry(providerContext); + const log = getService('log'); before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); @@ -32,6 +33,9 @@ export default function (providerContext: FtrProviderContext) { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/fleet/empty_fleet_server'); }); + after(async () => { + await removeBundledPackages(log); + }); describe('list api tests', async () => { it('lists all packages from the registry', async function () { @@ -47,6 +51,7 @@ export default function (providerContext: FtrProviderContext) { }); it('lists all limited packages from the registry', async function () { + await bundlePackage('endpoint-8.6.1'); const fetchLimitedPackageList = async () => { const response = await supertest .get('/api/fleet/epm/packages/limited') diff --git a/x-pack/test/fleet_api_integration/apis/fixtures/bundled_packages/endpoint-8.6.1.zip b/x-pack/test/fleet_api_integration/apis/fixtures/bundled_packages/endpoint-8.6.1.zip new file mode 100644 index 0000000000000..4c20854aee729 Binary files /dev/null and b/x-pack/test/fleet_api_integration/apis/fixtures/bundled_packages/endpoint-8.6.1.zip differ diff --git a/x-pack/test/functional/apps/api_keys/home_page.ts b/x-pack/test/functional/apps/api_keys/home_page.ts index 316a2e32c47fd..7eb37c4665554 100644 --- a/x-pack/test/functional/apps/api_keys/home_page.ts +++ b/x-pack/test/functional/apps/api_keys/home_page.ts @@ -170,9 +170,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('Update API key'); - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); + // Verify name input box is not present + expect(await pageObjects.apiKeys.isApiKeyNamePresent()).to.be(false); // Status should be displayed const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); @@ -278,9 +277,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('API key details'); - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); + // Verify name input box is not present + expect(await pageObjects.apiKeys.isApiKeyNamePresent()).to.be(false); // Status should be displayed const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); @@ -324,9 +322,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('API key details'); - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); + // Verify name input box is not present + expect(await pageObjects.apiKeys.isApiKeyNamePresent()).to.be(false); // Status should be displayed const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); @@ -365,9 +362,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('API key details'); - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); + // Verify name input box is not present + expect(await pageObjects.apiKeys.isApiKeyNamePresent()).to.be(false); // Status should be displayed const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); diff --git a/x-pack/test/functional/apps/index_management/index_templates_tab/create_index_template.ts b/x-pack/test/functional/apps/index_management/index_templates_tab/create_index_template.ts index 9b9d869fb9980..68b75fa86a0c5 100644 --- a/x-pack/test/functional/apps/index_management/index_templates_tab/create_index_template.ts +++ b/x-pack/test/functional/apps/index_management/index_templates_tab/create_index_template.ts @@ -32,8 +32,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Complete required fields from step 1 await testSubjects.setValue('nameField', INDEX_TEMPLATE_NAME); await testSubjects.setValue('indexPatternsField', 'test-1'); - // Enable data stream - await testSubjects.click('dataStreamField > input'); // Enable data retention await testSubjects.click('dataRetentionToggle > input'); // Set the retention to 7 hours diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index 13657713faac7..fc1750e1867d5 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -122,7 +122,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await retry.waitFor( 'wait for table and KPI charts to load', async () => - (await pageObjects.infraHostsView.isHostTableLoading()) && + (await pageObjects.infraHostsView.isHostTableLoaded()) && (await pageObjects.infraHostsView.isKPIChartsLoaded()) ); diff --git a/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts b/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts index 1f09b68fbf4f2..0dd8ebe13e805 100644 --- a/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts +++ b/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts @@ -72,7 +72,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: undefined, extraText: 'Maximum of bytes 19,986', value: '5,727.322', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingTrendline: false, showingBar: false, @@ -138,7 +138,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '5,727.322', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingTrendline: false, showingBar: false, diff --git a/x-pack/test/functional/apps/lens/group6/index.ts b/x-pack/test/functional/apps/lens/group6/index.ts index bc59c2878805e..60b9ce859b07f 100644 --- a/x-pack/test/functional/apps/lens/group6/index.ts +++ b/x-pack/test/functional/apps/lens/group6/index.ts @@ -80,8 +80,9 @@ export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext loadTestFile(require.resolve('./inspector')); // 1m 19s loadTestFile(require.resolve('./error_handling')); // 1m 8s loadTestFile(require.resolve('./lens_tagging')); // 1m 9s + loadTestFile(require.resolve('./workspace_size')); + // keep these last in the group in this order because they are messing with the default saved objects loadTestFile(require.resolve('./lens_reporting')); // 3m - // keep these two last in the group in this order because they are messing with the default saved objects loadTestFile(require.resolve('./rollup')); // 1m 30s loadTestFile(require.resolve('./no_data')); // 36s }); diff --git a/x-pack/test/functional/apps/lens/group6/metric.ts b/x-pack/test/functional/apps/lens/group6/metric.ts index e1e2644907096..14e46705d6d6b 100644 --- a/x-pack/test/functional/apps/lens/group6/metric.ts +++ b/x-pack/test/functional/apps/lens/group6/metric.ts @@ -127,8 +127,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: 'Average of bytes', extraText: 'Average of bytes 19,755', value: '19,755', - color: 'rgba(245, 247, 250, 1)', - trendlineColor: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', + trendlineColor: 'rgba(255, 255, 255, 1)', showingTrendline: true, showingBar: false, }, @@ -137,8 +137,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: 'Average of bytes', extraText: 'Average of bytes 18,994', value: '18,994', - color: 'rgba(245, 247, 250, 1)', - trendlineColor: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', + trendlineColor: 'rgba(255, 255, 255, 1)', showingTrendline: true, showingBar: false, }, @@ -147,8 +147,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: 'Average of bytes', extraText: 'Average of bytes 17,246', value: '17,246', - color: 'rgba(245, 247, 250, 1)', - trendlineColor: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', + trendlineColor: 'rgba(255, 255, 255, 1)', showingTrendline: true, showingBar: false, }, @@ -157,8 +157,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: 'Average of bytes', extraText: 'Average of bytes 15,687', value: '15,687', - color: 'rgba(245, 247, 250, 1)', - trendlineColor: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', + trendlineColor: 'rgba(255, 255, 255, 1)', showingTrendline: true, showingBar: false, }, @@ -167,8 +167,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: 'Average of bytes', extraText: 'Average of bytes 15,614.333', value: '15,614.333', - color: 'rgba(245, 247, 250, 1)', - trendlineColor: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', + trendlineColor: 'rgba(255, 255, 255, 1)', showingTrendline: true, showingBar: false, }, @@ -177,8 +177,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { subtitle: 'Average of bytes', extraText: 'Average of bytes 5,722.775', value: '5,722.775', - color: 'rgba(245, 247, 250, 1)', - trendlineColor: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', + trendlineColor: 'rgba(255, 255, 255, 1)', showingTrendline: true, showingBar: false, }, diff --git a/x-pack/test/functional/apps/lens/group6/workspace_size.ts b/x-pack/test/functional/apps/lens/group6/workspace_size.ts new file mode 100644 index 0000000000000..165b429b03733 --- /dev/null +++ b/x-pack/test/functional/apps/lens/group6/workspace_size.ts @@ -0,0 +1,254 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['visualize', 'lens', 'common']); + const browser = getService('browser'); + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const log = getService('log'); + + describe('lens workspace size', () => { + let originalWindowSize: { + height: number; + width: number; + x: number; + y: number; + }; + + const DEFAULT_WINDOW_SIZE = [1400, 900]; + + before(async () => { + originalWindowSize = await browser.getWindowSize(); + + await PageObjects.visualize.navigateToNewVisualization(); + await PageObjects.visualize.clickVisType('lens'); + await PageObjects.lens.goToTimeRange(); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', + operation: 'average', + field: 'bytes', + }); + }); + + beforeEach(async () => { + await browser.setWindowSize(DEFAULT_WINDOW_SIZE[0], DEFAULT_WINDOW_SIZE[1]); + }); + + after(async () => { + await browser.setWindowSize(originalWindowSize.width, originalWindowSize.height); + }); + + const pxToN = (pixels: string) => Number(pixels.substring(0, pixels.length - 2)); + + const assertWorkspaceDimensions = async (expectedWidth: string, expectedHeight: string) => { + const tolerance = 1; + + await retry.try(async () => { + const { width, height } = await PageObjects.lens.getWorkspaceVisContainerDimensions(); + + expect(pxToN(width)).to.within( + pxToN(expectedWidth) - tolerance, + pxToN(expectedWidth) + tolerance + ); + expect(pxToN(height)).to.within( + pxToN(expectedHeight) - tolerance, + pxToN(expectedHeight) + tolerance + ); + }); + }; + + const assertWorkspaceAspectRatio = async (expectedRatio: number) => { + const tolerance = 0.05; + + await retry.try(async () => { + const { width, height } = await PageObjects.lens.getWorkspaceVisContainerDimensions(); + + expect(pxToN(width) / pxToN(height)).to.within( + expectedRatio - tolerance, + expectedRatio + tolerance + ); + }); + }; + + const assertWorkspaceStyles = async (expectedStyles: { + aspectRatio: string; + minHeight: string; + minWidth: string; + maxHeight: string; + maxWidth: string; + }) => { + const actualStyles = await PageObjects.lens.getWorkspaceVisContainerStyles(); + + expect(actualStyles).to.eql(expectedStyles); + }; + + const VERTICAL_16_9 = 16 / 9; + const outerWorkspaceDimensions = { width: 690, height: 400 }; + const UNCONSTRAINED = outerWorkspaceDimensions.width / outerWorkspaceDimensions.height; + + it('workspace size recovers from special vis types', async () => { + /** + * This list is specifically designed to test dimension transitions. + * + * I have attempted to order the vis types to maximize the number of transitions. + * + * Excluding XY charts since they are tested separately. + */ + const visTypes: Array<{ + id: string; + searchText?: string; + expectedHeight?: string; + expectedWidth?: string; + aspectRatio?: number; + }> = [ + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'lnsDatatable', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'lnsLegacyMetric', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'donut', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'mosaic', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'pie', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'treemap', aspectRatio: UNCONSTRAINED }, + { + id: 'lnsMetric', + expectedWidth: '300px', + expectedHeight: '300px', + }, + { id: 'waffle', aspectRatio: UNCONSTRAINED }, + // { id: 'heatmap', ...UNCONSTRAINED }, // heatmap blocks render unless it's given two dimensions. This stops the expression renderer from requesting new dimensions. + // { id: 'lnsChoropleth', ...UNCONSTRAINED }, // choropleth currently erases all dimensions + // { id: 'lnsTagcloud', ...UNCONSTRAINED }, // tag cloud currently erases all dimensions + ]; + + while (visTypes.length) { + const vis = visTypes.pop()!; + await retry.try(async () => { + await PageObjects.lens.switchToVisualization(vis.id, vis.searchText); + }); + + log.debug(`Testing ${vis.id}... expecting ${vis.expectedWidth}x${vis.expectedHeight}`); + + if (vis.aspectRatio) { + await assertWorkspaceAspectRatio(vis.aspectRatio); + } else { + await assertWorkspaceDimensions(vis.expectedWidth!, vis.expectedHeight!); + } + } + }); + + it('metric size (absolute pixels)', async () => { + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('lnsMetric'); + }); + + await assertWorkspaceDimensions('300px', '300px'); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsMetric_breakdownByDimensionPanel > lns-empty-dimension', + operation: 'terms', + field: 'ip', + }); + + await assertWorkspaceDimensions('600px', '400px'); + + await PageObjects.lens.openDimensionEditor('lnsMetric_breakdownByDimensionPanel'); + await testSubjects.setValue('lnsMetric_max_cols', '2'); + + await assertWorkspaceDimensions('400px', '400px'); + }); + + it('gauge size (absolute pixels)', async () => { + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('horizontalBullet', 'gauge'); + }); + + await assertWorkspaceDimensions('600px', '300px'); + + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('verticalBullet', 'gauge'); + }); + + // this height is below the requested 600px + // that is because the window size isn't large enough to fit the requested dimensions + // and the chart is forced to shrink. + // + // this is a good thing because it makes this a test case for that scenario + await assertWorkspaceDimensions('300px', '400px'); + }); + + it('XY chart size', async () => { + // XY charts should have 100% width and 100% height unless they are a vertical chart with a time dimension + await retry.try(async () => { + // not important that this is specifically a line chart + await PageObjects.lens.switchToVisualization('line'); + }); + + await assertWorkspaceStyles({ + aspectRatio: 'auto', + minHeight: 'auto', + minWidth: 'auto', + maxHeight: '100%', + maxWidth: '100%', + }); + + await PageObjects.lens.configureDimension({ + dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension', + operation: 'date_histogram', + field: '@timestamp', + }); + + await assertWorkspaceStyles({ + aspectRatio: '16 / 9', + minHeight: '300px', + minWidth: '100%', + maxHeight: 'none', + maxWidth: 'none', + }); + + await assertWorkspaceAspectRatio(VERTICAL_16_9); + + await retry.try(async () => { + await PageObjects.lens.switchToVisualization('bar_horizontal_stacked'); + }); + + await assertWorkspaceAspectRatio(UNCONSTRAINED); + }); + }); +} diff --git a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts index 55cb376db2e24..d9152af7411ba 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/goal.ts @@ -48,7 +48,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '140.05%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -80,7 +80,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '131,040,360.81%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -112,7 +112,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14.37%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -156,7 +156,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,047,486.03', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -166,7 +166,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '66,144,823.35', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -176,7 +176,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,933,477.76', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -186,7 +186,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,157,898.23', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, @@ -196,7 +196,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '65,365,950.93', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: true, showingTrendline: false, diff --git a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts index 89cb1d7880baa..632af7eed9f98 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/metric.ts @@ -49,7 +49,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14,005', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -80,7 +80,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '13,104,036,080.615', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -111,7 +111,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '1,437', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -166,7 +166,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,228,964,670.613', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -176,7 +176,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,186,695,551.251', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -186,7 +186,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,073,190,186.423', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -196,7 +196,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,031,579,645.108', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, @@ -206,7 +206,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,009,497,206.823', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', trendlineColor: undefined, showingBar: false, showingTrendline: false, diff --git a/x-pack/test/functional/page_objects/api_keys_page.ts b/x-pack/test/functional/page_objects/api_keys_page.ts index 0875774470018..8f74f927b976f 100644 --- a/x-pack/test/functional/page_objects/api_keys_page.ts +++ b/x-pack/test/functional/page_objects/api_keys_page.ts @@ -45,6 +45,10 @@ export function ApiKeysPageProvider({ getService }: FtrProviderContext) { return await testSubjects.find('apiKeyNameInput'); }, + async isApiKeyNamePresent() { + return await testSubjects.exists('apiKeyNameInput'); + }, + async setApiKeyCustomExpiration(expirationTime: string) { return await testSubjects.setValue('apiKeyCustomExpirationInput', expirationTime); }, diff --git a/x-pack/test/functional/page_objects/infra_hosts_view.ts b/x-pack/test/functional/page_objects/infra_hosts_view.ts index 0c3004acc4fe8..60c4f0727e7c0 100644 --- a/x-pack/test/functional/page_objects/infra_hosts_view.ts +++ b/x-pack/test/functional/page_objects/infra_hosts_view.ts @@ -49,11 +49,11 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) { // Table async getHostsTable() { - return testSubjects.find('hostsView-table'); + return testSubjects.find('hostsView-table-loaded'); }, - async isHostTableLoading() { - return !(await testSubjects.exists('tbody[class*=euiBasicTableBodyLoading]')); + async isHostTableLoaded() { + return !(await testSubjects.exists('hostsView-table-loading')); }, async getHostsTableData() { diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index 2af514b4a1fdc..747767a71befe 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -1947,5 +1947,28 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await this.closeDimensionEditor(); }, + + async getWorkspaceVisContainerDimensions() { + const visContainer = await testSubjects.find('lnsWorkspacePanelWrapper__innerContent'); + const [width, height] = await Promise.all([ + visContainer.getComputedStyle('width'), + visContainer.getComputedStyle('height'), + ]); + + return { width, height }; + }, + + async getWorkspaceVisContainerStyles() { + const visContainer = await testSubjects.find('lnsWorkspacePanelWrapper__innerContent'); + const [maxWidth, maxHeight, minWidth, minHeight, aspectRatio] = await Promise.all([ + visContainer.getComputedStyle('max-width'), + visContainer.getComputedStyle('max-height'), + visContainer.getComputedStyle('min-width'), + visContainer.getComputedStyle('min-height'), + visContainer.getComputedStyle('aspect-ratio'), + ]); + + return { maxWidth, maxHeight, minWidth, minHeight, aspectRatio }; + }, }); } diff --git a/x-pack/test/functional/services/cases/navigation.ts b/x-pack/test/functional/services/cases/navigation.ts index 8d3ba0e73a24c..f0d4fb52ba5e4 100644 --- a/x-pack/test/functional/services/cases/navigation.ts +++ b/x-pack/test/functional/services/cases/navigation.ts @@ -22,8 +22,9 @@ export function CasesNavigationProvider({ getPageObject, getService }: FtrProvid await common.clickAndValidate('configure-case-button', 'case-configure-title'); }, - async navigateToSingleCase(app: string = 'cases', caseId: string) { - await common.navigateToUrlWithBrowserHistory(app, caseId); + async navigateToSingleCase(app: string = 'cases', caseId: string, tabId?: string) { + const search = tabId != null ? `?tabId=${tabId}` : ''; + await common.navigateToUrlWithBrowserHistory(app, caseId, search); }, }; } diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts b/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts index 6979c45f867ba..cab3cc82e8a4b 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/group1/view_case.ts @@ -46,7 +46,10 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { it('should show the case view page correctly', async () => { await testSubjects.existOrFail('case-view-title'); await testSubjects.existOrFail('header-page-supplements'); + await testSubjects.existOrFail('case-action-bar-wrapper'); + await testSubjects.existOrFail('case-view-tabs'); + await testSubjects.existOrFail('case-view-tab-title-alerts'); await testSubjects.existOrFail('case-view-tab-title-activity'); await testSubjects.existOrFail('case-view-tab-title-files'); await testSubjects.existOrFail('description'); @@ -1013,11 +1016,26 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { describe('Tabs', () => { createOneCaseBeforeDeleteAllAfter(getPageObject, getService); + it('renders tabs correctly', async () => { + await testSubjects.existOrFail('case-view-tab-title-activity'); + await testSubjects.existOrFail('case-view-tab-title-files'); + await testSubjects.existOrFail('case-view-tab-title-alerts'); + }); + it('shows the "activity" tab by default', async () => { await testSubjects.existOrFail('case-view-tab-title-activity'); await testSubjects.existOrFail('case-view-tab-content-activity'); }); + it("shows the 'activity' tab when clicked", async () => { + // Go to the files tab first + await testSubjects.click('case-view-tab-title-files'); + await testSubjects.existOrFail('case-view-tab-content-files'); + + await testSubjects.click('case-view-tab-title-activity'); + await testSubjects.existOrFail('case-view-tab-content-activity'); + }); + it("shows the 'alerts' tab when clicked", async () => { await testSubjects.click('case-view-tab-title-alerts'); await testSubjects.existOrFail('case-view-tab-content-alerts'); @@ -1027,6 +1045,36 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { await testSubjects.click('case-view-tab-title-files'); await testSubjects.existOrFail('case-view-tab-content-files'); }); + + describe('Query params', () => { + it('renders the activity tab when the query parameter tabId=activity', async () => { + const theCase = await createAndNavigateToCase(getPageObject, getService); + + await cases.navigation.navigateToSingleCase('cases', theCase.id, 'activity'); + await testSubjects.existOrFail('case-view-tab-title-activity'); + }); + + it('renders the activity tab when the query parameter tabId=alerts', async () => { + const theCase = await createAndNavigateToCase(getPageObject, getService); + + await cases.navigation.navigateToSingleCase('cases', theCase.id, 'alerts'); + await testSubjects.existOrFail('case-view-tab-title-activity'); + }); + + it('renders the activity tab when the query parameter tabId=files', async () => { + const theCase = await createAndNavigateToCase(getPageObject, getService); + + await cases.navigation.navigateToSingleCase('cases', theCase.id, 'files'); + await testSubjects.existOrFail('case-view-tab-content-files'); + }); + + it('renders the activity tab when the query parameter tabId has an unknown value', async () => { + const theCase = await createAndNavigateToCase(getPageObject, getService); + + await cases.navigation.navigateToSingleCase('cases', theCase.id, 'fake'); + await testSubjects.existOrFail('case-view-tab-title-activity'); + }); + }); }); describe('Files', () => { diff --git a/x-pack/test/screenshot_creation/apps/response_ops_docs/maintenance_windows/create_window.ts b/x-pack/test/screenshot_creation/apps/response_ops_docs/maintenance_windows/create_window.ts index 00cc131bca2c5..b53ae05bc867c 100644 --- a/x-pack/test/screenshot_creation/apps/response_ops_docs/maintenance_windows/create_window.ts +++ b/x-pack/test/screenshot_creation/apps/response_ops_docs/maintenance_windows/create_window.ts @@ -26,7 +26,17 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'create-maintenance-window', screenshotDirectories, 1400, - 1024 + 1600 + ); + const filterAlerts = await find.byCssSelector( + '[data-test-subj="maintenanceWindowScopedQuerySwitch"] .euiSwitch__button' + ); + await filterAlerts.click(); + await commonScreenshots.takeScreenshot( + 'create-maintenance-window-filter', + screenshotDirectories, + 1400, + 1600 ); const cancelButton = await testSubjects.find('cancelMaintenanceWindow'); await cancelButton.click(); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/legacy_actions/get_legacy_action_notifications_so_by_id.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/legacy_actions/get_legacy_action_notifications_so_by_id.ts index 3d92779e010d2..bed1197fc91ee 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/legacy_actions/get_legacy_action_notifications_so_by_id.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/legacy_actions/get_legacy_action_notifications_so_by_id.ts @@ -9,9 +9,9 @@ import type { Client } from '@elastic/elasticsearch'; import type { SearchResponse } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ALERTING_CASES_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; import { SavedObjectReference } from '@kbn/core/server'; -import { LegacyRuleNotificationAlertTypeParams } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions_legacy'; +import { LegacyRuleNotificationRuleTypeParams } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_actions_legacy'; -interface LegacyActionNotificationSO extends LegacyRuleNotificationAlertTypeParams { +interface LegacyActionNotificationSO extends LegacyRuleNotificationRuleTypeParams { references: SavedObjectReference[]; } diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/custom_saved_query_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/custom_saved_query_rule.cy.ts index 5a87350b730da..913218797fd76 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/custom_saved_query_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/custom_saved_query_rule.cy.ts @@ -51,8 +51,7 @@ const savedQueryName = 'custom saved query'; const savedQueryQuery = 'process.name: test'; const savedQueryFilterKey = 'testAgent.value'; -// TODO: https://github.com/elastic/kibana/issues/161539 -describe('Saved query rules', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +describe('Saved query rules', { tags: ['@ess', '@serverless'] }, () => { describe('Custom saved_query detection rule creation', () => { beforeEach(() => { login(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts index b2b000803e6c4..9ce0bbb5be44a 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts @@ -115,8 +115,7 @@ import { deleteAlertsAndRules } from '../../../../tasks/api_calls/common'; const DEFAULT_THREAT_MATCH_QUERY = '@timestamp >= "now-30d/d"'; -// TODO: https://github.com/elastic/kibana/issues/161539 -describe('indicator match', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +describe('indicator match', { tags: ['@ess', '@serverless'] }, () => { describe('Detection rules, Indicator Match', () => { const expectedUrls = getNewThreatIndicatorRule().references?.join(''); const expectedFalsePositives = getNewThreatIndicatorRule().false_positives?.join(''); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/enable_risk_score_redirect.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/enable_risk_score_redirect.cy.ts index 91488eeb57506..ebff5204d4981 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/enable_risk_score_redirect.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/enable_risk_score_redirect.cy.ts @@ -18,7 +18,6 @@ import { RiskScoreEntity } from '../../../tasks/risk_scores/common'; import { ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; import { PAGE_TITLE } from '../../../screens/entity_analytics_management'; -// FLAKY: https://github.com/elastic/kibana/issues/165644 describe('Enable risk scores from dashboard', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics.cy.ts index f586105483b9c..332da13af4359 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboards/entity_analytics.cy.ts @@ -51,11 +51,10 @@ import { kqlSearch } from '../../../tasks/security_header'; import { setEndDate, setStartDate, updateDates } from '../../../tasks/date_picker'; import { enableJob, + mockRiskEngineEnabled, navigateToNextPage, waitForAnomaliesToBeLoaded, } from '../../../tasks/entity_analytics'; -import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; -import { enableRiskEngine } from '../../../tasks/entity_analytics'; const TEST_USER_ALERTS = 1; const TEST_USER_NAME = 'test'; @@ -68,8 +67,6 @@ const OLDEST_DATE = moment('2019-01-19T16:22:56.217Z').format(DATE_FORMAT); describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () => { before(() => { cy.task('esArchiverLoad', { archiveName: 'auditbeat_multiple' }); - login(); - deleteRiskEngineConfiguration(); }); after(() => { @@ -328,225 +325,207 @@ describe('Entity Analytics Dashboard', { tags: ['@ess', '@serverless'] }, () => }); }); - describe('Risk Score enabled but still no data', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_scores_new_no_data' }); - }); - - beforeEach(() => { - login(); - enableRiskEngine(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); - - afterEach(() => { - deleteRiskEngineConfiguration(); - }); - - after(() => { - cy.task('esArchiverUnload', 'risk_scores_new_no_data'); - }); - - it('shows no data detected prompt for host and user risk scores', () => { - cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); - cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); - }); - }); - - describe('With host risk data', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); - login(); - enableRiskEngine(); - }); - + describe('When risk engine is enabled', () => { beforeEach(() => { login(); + mockRiskEngineEnabled(); visitWithTimeRange(ENTITY_ANALYTICS_URL); }); - after(() => { - cy.task('esArchiverUnload', 'risk_scores_new'); - deleteRiskEngineConfiguration(); - }); - - it('renders donut chart', () => { - cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); - }); - - it('renders table', () => { - cy.get(HOSTS_TABLE).should('be.visible'); - cy.get(HOSTS_TABLE_ROWS).should('have.length', 5); - }); - - it('renders alerts column', () => { - cy.get(HOSTS_TABLE_ALERT_CELL).should('have.length', 5); - }); - - it('filters by risk level', () => { - cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); - openRiskTableFilterAndSelectTheCriticalOption(); - - cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); - cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); - - removeCriticalFilterAndCloseRiskTableFilter(); - }); + describe('Without data (before the risk engine runs for the first time)', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new_no_data' }); + }); - it('filters the host risk table with KQL search bar query', () => { - kqlSearch(`host.name : ${SIEM_KIBANA_HOST_NAME}{enter}`); + after(() => { + cy.task('esArchiverUnload', 'risk_scores_new_no_data'); + }); - cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); - cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); + it('shows no data detected prompt for host and user risk scores', () => { + cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + }); }); - describe('With alerts data', () => { + describe('With host risk data', () => { before(() => { - createRule(getNewRule()); - }); - - beforeEach(() => { - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); }); after(() => { - deleteAlertsAndRules(); + cy.task('esArchiverUnload', 'risk_scores_new'); }); - it('populates alerts column', () => { - cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', SIEM_KIBANA_HOST_ALERTS); + it('renders donut chart', () => { + cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); }); - it('filters the alerts count with time range', () => { - setEndDate(DATE_BEFORE_ALERT_CREATION); - updateDates(); + it('renders table', () => { + cy.get(HOSTS_TABLE).should('be.visible'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 5); + }); - cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', 0); + it('renders alerts column', () => { + cy.get(HOSTS_TABLE_ALERT_CELL).should('have.length', 5); }); - it('filters risk scores with time range', () => { - const now = moment().format(DATE_FORMAT); - setStartDate(now); - updateDates(); + it('filters by risk level', () => { + cy.get(HOSTS_DONUT_CHART).should('include.text', '6Total'); + openRiskTableFilterAndSelectTheCriticalOption(); - cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); - // CLEAR DATES - setStartDate(OLDEST_DATE); - updateDates(); + removeCriticalFilterAndCloseRiskTableFilter(); }); - it('opens alerts page when alerts count is clicked', () => { - clickOnFirstHostsAlerts(); - cy.url().should('include', ALERTS_URL); + it('filters the host risk table with KQL search bar query', () => { + kqlSearch(`host.name : ${SIEM_KIBANA_HOST_NAME}{enter}`); - cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); - cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); - cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'Host'); - cy.get(OPTION_LIST_VALUES(1)).should('include.text', SIEM_KIBANA_HOST_NAME); + cy.get(HOSTS_DONUT_CHART).should('include.text', '1Total'); + cy.get(HOSTS_TABLE_ROWS).should('have.length', 1); }); - }); - }); - describe('With user risk data', () => { - before(() => { - cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); - login(); - enableRiskEngine(); + describe('With alerts data', () => { + before(() => { + createRule(getNewRule()); + }); + + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); + + after(() => { + deleteAlertsAndRules(); + }); + + it('populates alerts column', () => { + cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', SIEM_KIBANA_HOST_ALERTS); + }); + + it('filters the alerts count with time range', () => { + setEndDate(DATE_BEFORE_ALERT_CREATION); + updateDates(); + + cy.get(HOSTS_TABLE_ALERT_CELL).first().should('include.text', 0); + }); + + it('filters risk scores with time range', () => { + const now = moment().format(DATE_FORMAT); + setStartDate(now); + updateDates(); + + cy.get(HOST_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + + // CLEAR DATES + setStartDate(OLDEST_DATE); + updateDates(); + }); + + it('opens alerts page when alerts count is clicked', () => { + clickOnFirstHostsAlerts(); + cy.url().should('include', ALERTS_URL); + + cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); + cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); + cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'Host'); + cy.get(OPTION_LIST_VALUES(1)).should('include.text', SIEM_KIBANA_HOST_NAME); + }); + }); }); - beforeEach(() => { - login(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + describe('With user risk data', () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); + }); - after(() => { - cy.task('esArchiverUnload', 'risk_scores_new'); - deleteRiskEngineConfiguration(); - }); + after(() => { + cy.task('esArchiverUnload', 'risk_scores_new'); + }); - it('renders donut chart', () => { - cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); - }); + it('renders donut chart', () => { + cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); + }); - it('renders table', () => { - cy.get(USERS_TABLE).should('be.visible'); - cy.get(USERS_TABLE_ROWS).should('have.length', 5); - }); + it('renders table', () => { + cy.get(USERS_TABLE).should('be.visible'); + cy.get(USERS_TABLE_ROWS).should('have.length', 5); + }); - it('renders alerts column', () => { - cy.get(USERS_TABLE_ALERT_CELL).should('have.length', 5); - }); + it('renders alerts column', () => { + cy.get(USERS_TABLE_ALERT_CELL).should('have.length', 5); + }); - it('filters by risk level', () => { - cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); + it('filters by risk level', () => { + cy.get(USERS_DONUT_CHART).should('include.text', '7Total'); - openUserRiskTableFilterAndSelectTheLowOption(1); + openUserRiskTableFilterAndSelectTheLowOption(1); - cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); - cy.get(USERS_TABLE_ROWS).should('have.length', 1); + cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); + cy.get(USERS_TABLE_ROWS).should('have.length', 1); - removeLowFilterAndCloseUserRiskTableFilter(); - }); - - it('filters the host risk table with KQL search bar query', () => { - kqlSearch(`user.name : ${TEST_USER_NAME}{enter}`); + removeLowFilterAndCloseUserRiskTableFilter(); + }); - cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); - cy.get(USERS_TABLE_ROWS).should('have.length', 1); - }); + it('filters the host risk table with KQL search bar query', () => { + kqlSearch(`user.name : ${TEST_USER_NAME}{enter}`); - describe('With alerts data', () => { - before(() => { - createRule(getNewRule()); + cy.get(USERS_DONUT_CHART).should('include.text', '1Total'); + cy.get(USERS_TABLE_ROWS).should('have.length', 1); }); - beforeEach(() => { - login(); - visitWithTimeRange(ALERTS_URL); - waitForAlertsToPopulate(); - visitWithTimeRange(ENTITY_ANALYTICS_URL); - }); + describe('With alerts data', () => { + before(() => { + createRule(getNewRule()); + }); - after(() => { - deleteAlertsAndRules(); - }); + beforeEach(() => { + login(); + visitWithTimeRange(ALERTS_URL); + waitForAlertsToPopulate(); + visitWithTimeRange(ENTITY_ANALYTICS_URL); + }); - it('populates alerts column', () => { - cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', TEST_USER_ALERTS); - }); + after(() => { + deleteAlertsAndRules(); + }); - it('filters the alerts count with time range', () => { - setEndDate(DATE_BEFORE_ALERT_CREATION); - updateDates(); + it('populates alerts column', () => { + cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', TEST_USER_ALERTS); + }); - cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', 0); - }); + it('filters the alerts count with time range', () => { + setEndDate(DATE_BEFORE_ALERT_CREATION); + updateDates(); - it('filters risk scores with time range', () => { - const now = moment().format(DATE_FORMAT); - setStartDate(now); - updateDates(); + cy.get(USERS_TABLE_ALERT_CELL).first().should('include.text', 0); + }); - cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); + it('filters risk scores with time range', () => { + const now = moment().format(DATE_FORMAT); + setStartDate(now); + updateDates(); - // CLEAR DATES - setStartDate(OLDEST_DATE); - updateDates(); - }); + cy.get(USER_RISK_SCORE_NO_DATA_DETECTED).should('be.visible'); - it('opens alerts page when alerts count is clicked', () => { - clickOnFirstUsersAlerts(); + // CLEAR DATES + setStartDate(OLDEST_DATE); + updateDates(); + }); - cy.url().should('include', ALERTS_URL); + it('opens alerts page when alerts count is clicked', () => { + clickOnFirstUsersAlerts(); - cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); - cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); - cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'User'); - cy.get(OPTION_LIST_VALUES(1)).should('include.text', TEST_USER_NAME); + cy.url().should('include', ALERTS_URL); + + cy.get(OPTION_LIST_LABELS).eq(0).should('include.text', 'Status'); + cy.get(OPTION_LIST_VALUES(0)).should('include.text', 'open'); + cy.get(OPTION_LIST_LABELS).eq(1).should('include.text', 'User'); + cy.get(OPTION_LIST_VALUES(1)).should('include.text', TEST_USER_NAME); + }); }); }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts index ecffa9285c228..acb38b4dcefff 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/enrichments.cy.ts @@ -29,8 +29,7 @@ import { login } from '../../tasks/login'; import { visitWithTimeRange } from '../../tasks/navigation'; import { ALERTS_URL } from '../../urls/navigation'; -import { deleteRiskEngineConfiguration } from '../../tasks/api_calls/risk_engine'; -import { enableRiskEngine } from '../../tasks/entity_analytics'; +import { mockRiskEngineEnabled } from '../../tasks/entity_analytics'; const CURRENT_HOST_RISK_LEVEL = 'Current host risk level'; const ORIGINAL_HOST_RISK_LEVEL = 'Original host risk level'; @@ -54,7 +53,6 @@ describe('Enrichment', { tags: ['@ess', '@serverless'] }, () => { deleteAlertsAndRules(); createRule(getNewRule({ rule_id: 'rule1' })); login(); - deleteRiskEngineConfiguration(); visitWithTimeRange(ALERTS_URL); waitForAlertsToPopulate(); }); @@ -94,7 +92,7 @@ describe('Enrichment', { tags: ['@ess', '@serverless'] }, () => { deleteAlertsAndRules(); createRule(getNewRule({ rule_id: 'rule1' })); login(); - enableRiskEngine(); + mockRiskEngineEnabled(); visitWithTimeRange(ALERTS_URL); waitForAlertsToPopulate(); }); @@ -102,7 +100,6 @@ describe('Enrichment', { tags: ['@ess', '@serverless'] }, () => { afterEach(() => { cy.task('esArchiverUnload', 'risk_scores_new'); cy.task('esArchiverUnload', 'risk_scores_new_updated'); - deleteRiskEngineConfiguration(); }); it('Should has enrichment fields from legacy risk', function () { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/host_risk_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/host_risk_tab.cy.ts index e0ea108e38a00..a45fcbfb53e0d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/host_risk_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/host_risk_tab.cy.ts @@ -20,15 +20,12 @@ import { login } from '../../../tasks/login'; import { visitWithTimeRange } from '../../../tasks/navigation'; import { hostsUrl } from '../../../urls/navigation'; import { kqlSearch } from '../../../tasks/security_header'; -import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; -import { enableRiskEngine } from '../../../tasks/entity_analytics'; +import { mockRiskEngineEnabled } from '../../../tasks/entity_analytics'; // Tracked by https://github.com/elastic/security-team/issues/7696 describe('risk tab', { tags: ['@ess', '@serverless'] }, () => { describe('with legacy risk score', () => { before(() => { - login(); - deleteRiskEngineConfiguration(); cy.task('esArchiverLoad', { archiveName: 'risk_hosts' }); }); @@ -53,7 +50,7 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => { cy.get(HOST_BY_RISK_TABLE_CELL).eq(7).should('have.text', 'Low'); }); - it.skip('filters the table', () => { + it('filters the table', () => { openRiskTableFilterAndSelectTheCriticalOption(); cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('not.have.text', 'siem-kibana'); @@ -61,8 +58,7 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => { removeCriticalFilterAndCloseRiskTableFilter(); }); - // Flaky - it.skip('should be able to change items count per page', () => { + it('should be able to change items count per page', () => { selectFiveItemsPerPageOption(); cy.get(HOST_BY_RISK_TABLE_HOSTNAME_CELL).should('have.length', 5); @@ -77,12 +73,11 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => { describe('with new risk score', () => { before(() => { cy.task('esArchiverLoad', { archiveName: 'risk_scores_new' }); - login(); - enableRiskEngine(); }); beforeEach(() => { login(); + mockRiskEngineEnabled(); visitWithTimeRange(hostsUrl('allHosts')); // by some reason after navigate to host risk, page is sometimes is reload or go to all host tab // this fix wait until we fave host in all host table, and then we go to risk tab @@ -92,7 +87,6 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => { after(() => { cy.task('esArchiverUnload', 'risk_scores_new'); - deleteRiskEngineConfiguration(); }); it('renders the table', () => { @@ -103,7 +97,7 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => { cy.get(HOST_BY_RISK_TABLE_CELL).eq(7).should('have.text', 'Critical'); }); - it.skip('filters the table', () => { + it('filters the table', () => { openRiskTableFilterAndSelectTheCriticalOption(); cy.get(HOST_BY_RISK_TABLE_CELL).eq(3).should('not.have.text', 'siem-kibana'); @@ -112,7 +106,7 @@ describe('risk tab', { tags: ['@ess', '@serverless'] }, () => { }); // Flaky - it.skip('should be able to change items count per page', () => { + it('should be able to change items count per page', () => { selectFiveItemsPerPageOption(); cy.get(HOST_BY_RISK_TABLE_HOSTNAME_CELL).should('have.length', 5); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/hosts_risk_column.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/hosts_risk_column.cy.ts index 4b034d77ed07d..15e62f274145f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/hosts_risk_column.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/hosts/hosts_risk_column.cy.ts @@ -11,8 +11,7 @@ import { visitWithTimeRange } from '../../../tasks/navigation'; import { hostsUrl } from '../../../urls/navigation'; import { TABLE_CELL } from '../../../screens/alerts_details'; import { kqlSearch } from '../../../tasks/security_header'; -import { deleteRiskEngineConfiguration } from '../../../tasks/api_calls/risk_engine'; -import { enableRiskEngine } from '../../../tasks/entity_analytics'; +import { mockRiskEngineEnabled } from '../../../tasks/entity_analytics'; describe('All hosts table', { tags: ['@ess', '@serverless'] }, () => { describe('with legacy risk score', () => { @@ -23,7 +22,6 @@ describe('All hosts table', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); - deleteRiskEngineConfiguration(); }); after(() => { @@ -47,12 +45,11 @@ describe('All hosts table', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); - enableRiskEngine(); + mockRiskEngineEnabled(); }); after(() => { cy.task('esArchiverUnload', 'risk_scores_new'); - deleteRiskEngineConfiguration(); }); it('it renders risk column', () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts index a4e0eafc0018a..5abdf689b1c52 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts @@ -69,12 +69,20 @@ export const mockRiskEngineEnabled = () => { }).as('riskIndexStatus'); }; -export const enableRiskEngine = () => { - cy.visit(ENTITY_ANALYTICS_MANAGEMENT_URL); - cy.get(RISK_SCORE_STATUS).should('have.text', 'Off'); - riskEngineStatusChange(); - cy.get(RISK_SCORE_STATUS).should('have.text', 'On'); -}; +/** + * @deprecated + * At the moment there isn't a way to clean all assets created by the risk engine enablement. + * We can't clean assets after each tests and we can't call this function from the `after` hook (cypress good practice). + * Reintroduce this task when we can safely delete the risk engine data. + * + * Please use `mockRiskEngineEnabled` instead. + */ +// const enableRiskEngine = () => { +// cy.visit(ENTITY_ANALYTICS_MANAGEMENT_URL); +// cy.get(RISK_SCORE_STATUS).should('have.text', 'Off'); +// riskEngineStatusChange(); +// cy.get(RISK_SCORE_STATUS).should('have.text', 'On'); +// }; export const updateRiskEngine = () => { cy.get(RISK_SCORE_UPDATE_BUTTON).click(); diff --git a/x-pack/test/security_solution_cypress/es_archives/threat_indicator/mappings.json b/x-pack/test/security_solution_cypress/es_archives/threat_indicator/mappings.json index bc5f6e3db9169..e22f719255fe5 100644 --- a/x-pack/test/security_solution_cypress/es_archives/threat_indicator/mappings.json +++ b/x-pack/test/security_solution_cypress/es_archives/threat_indicator/mappings.json @@ -811,10 +811,6 @@ }, "settings": { "index": { - "lifecycle": { - "name": "filebeat", - "rollover_alias": "filebeat-7.12.0" - }, "mapping": { "total_fields": { "limit": "10000" diff --git a/x-pack/test_serverless/functional/config.base.ts b/x-pack/test_serverless/functional/config.base.ts index 501a23c258046..51227434fd377 100644 --- a/x-pack/test_serverless/functional/config.base.ts +++ b/x-pack/test_serverless/functional/config.base.ts @@ -107,6 +107,9 @@ export function createTestConfig(options: CreateTestConfigOptions) { pathname: '/app/dev_tools', hash: '/searchprofiler', }, + maintenanceWindows: { + pathname: '/app/management/insightsAndAlerting/maintenanceWindows', + }, }, // choose where screenshots should be saved screenshots: { diff --git a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts index 6092473ad27bc..7d591ade32c3c 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/index_management/index_templates.ts @@ -16,8 +16,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const es = getService('es'); const retry = getService('retry'); + const log = getService('log'); const TEST_TEMPLATE = 'a_test_template'; + const INDEX_PATTERN = `index_pattern_${Math.random()}`; describe('Index Templates', function () { before(async () => { @@ -32,6 +34,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => { + log.debug('Cleaning up created template'); + + try { + await es.indices.deleteIndexTemplate({ name: TEST_TEMPLATE }, { ignore: [404] }); + } catch (e) { + log.debug('[Setup error] Error creating test policy'); + throw e; + } + await pageObjects.svlCommonPage.forceLogout(); }); @@ -45,7 +56,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await es.indices.putIndexTemplate({ name: TEST_TEMPLATE, body: { - index_patterns: ['test*'], + index_patterns: [INDEX_PATTERN], }, }); }); @@ -85,7 +96,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('createTemplateButton'); await testSubjects.setValue('nameField', TEST_TEMPLATE_NAME); - await testSubjects.setValue('indexPatternsField', 'test*'); + await testSubjects.setValue('indexPatternsField', INDEX_PATTERN); // Click form summary step and then the submit button await testSubjects.click('formWizardStep-5'); diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts index 5de789198f420..01f655af00a1f 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts @@ -50,7 +50,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '140.05%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: true, showingTrendline: false, }, @@ -77,7 +77,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '131,040,360.81%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: true, showingTrendline: false, }, @@ -105,7 +105,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14.37%', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: true, showingTrendline: false, }, @@ -133,7 +133,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,228,964,670.613', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -142,7 +142,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,186,695,551.251', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -151,7 +151,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,073,190,186.423', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -160,7 +160,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,031,579,645.108', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, @@ -169,7 +169,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: 'Average machine.ram', extraText: '', value: '13,009,497,206.823', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingTrendline: false, showingBar: true, }, diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts index abd44aefe4d5a..9bd990484cc81 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/metric.ts @@ -46,7 +46,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '14,005', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: false, showingTrendline: false, }, @@ -72,7 +72,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '13,104,036,080.615', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: false, showingTrendline: false, }, @@ -99,7 +99,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { subtitle: undefined, extraText: '', value: '1,437', - color: 'rgba(245, 247, 250, 1)', + color: 'rgba(255, 255, 255, 1)', showingBar: false, showingTrendline: false, }, diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts index 92dfb107dd440..f9c410acd70a9 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts @@ -36,7 +36,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await retry.waitFor( 'wait for table and KPI charts to load', async () => - (await pageObjects.infraHostsView.isHostTableLoading()) && + (await pageObjects.infraHostsView.isHostTableLoaded()) && (await pageObjects.infraHostsView.isKPIChartsLoaded()) ); diff --git a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/index.ts b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/index.ts index 10b33b5fc944d..a8da8791a972a 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/index.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/index.ts @@ -27,5 +27,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./cases')); loadTestFile(require.resolve('./connectors')); + loadTestFile(require.resolve('./maintenance_windows')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/maintenance_windows/create_window.ts b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/maintenance_windows/create_window.ts new file mode 100644 index 0000000000000..db43127a0adcf --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/maintenance_windows/create_window.ts @@ -0,0 +1,57 @@ +/* + * 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 { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects(['common', 'header', 'svlCommonPage']); + const svlCommonScreenshots = getService('svlCommonScreenshots'); + const screenshotDirectories = ['response_ops_docs', 'observability_maintenace_windows']; + const find = getService('find'); + const testSubjects = getService('testSubjects'); + + describe('create window', function () { + beforeEach(async () => { + await pageObjects.svlCommonPage.login(); + }); + + after(async () => { + await pageObjects.svlCommonPage.forceLogout(); + }); + + it('create maintenance window screenshot', async () => { + await pageObjects.common.navigateToApp('maintenanceWindows'); + await pageObjects.header.waitUntilLoadingHasFinished(); + const createButton = await find.byCssSelector( + '[data-test-subj="mw-empty-prompt"] .euiButton' + ); + await createButton.click(); + await svlCommonScreenshots.takeScreenshot( + 'create-maintenance-window', + screenshotDirectories, + 1400, + 1600 + ); + const filterAlerts = await find.byCssSelector( + '[data-test-subj="maintenanceWindowScopedQuerySwitch"] .euiSwitch__button' + ); + await filterAlerts.click(); + const radioGroup = await testSubjects.find('maintenanceWindowCategorySelectionRadioGroup'); + const label = await radioGroup.findByCssSelector(`label[for="observability"]`); + await label.click(); + await testSubjects.setValue('queryInput', 'kibana.alert.rule.name: custom-threshold-rule-1'); + await svlCommonScreenshots.takeScreenshot( + 'create-maintenance-window-filter', + screenshotDirectories, + 1400, + 1600 + ); + const cancelButton = await testSubjects.find('cancelMaintenanceWindow'); + await cancelButton.click(); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/maintenance_windows/index.ts b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/maintenance_windows/index.ts new file mode 100644 index 0000000000000..f7c95d53f0206 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/screenshot_creation/response_ops_docs/maintenance_windows/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../../ftr_provider_context'; + +export default function ({ loadTestFile, getService }: FtrProviderContext) { + const browser = getService('browser'); + + describe('observability maintenance windows', function () { + before(async () => { + await browser.setWindowSize(1920, 1080); + }); + + loadTestFile(require.resolve('./create_window')); + }); +} diff --git a/yarn.lock b/yarn.lock index 08473482ff924..45dce47febdcf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11872,12 +11872,12 @@ axe-core@^4.8.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae" integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g== -axios@^1.3.4, axios@^1.6.0, axios@^1.6.5: - version "1.6.5" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.5.tgz#2c090da14aeeab3770ad30c3a1461bc970fb0cd8" - integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg== +axios@^1.3.4, axios@^1.6.0, axios@^1.6.3: + version "1.6.3" + resolved "https://registry.npmjs.org/axios/-/axios-1.6.3.tgz#7f50f23b3aa246eff43c54834272346c396613f4" + integrity sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww== dependencies: - follow-redirects "^1.15.4" + follow-redirects "^1.15.0" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -17255,10 +17255,10 @@ folktale@2.3.2: resolved "https://registry.yarnpkg.com/folktale/-/folktale-2.3.2.tgz#38231b039e5ef36989920cbf805bf6b227bf4fd4" integrity sha512-+8GbtQBwEqutP0v3uajDDoN64K2ehmHd0cjlghhxh0WpcfPzAIjPA03e1VvHlxL02FVGR0A6lwXsNQKn3H1RNQ== -follow-redirects@^1.0.0, follow-redirects@^1.15.4: - version "1.15.4" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" - integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== +follow-redirects@^1.0.0, follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== font-awesome@4.7.0: version "4.7.0"