diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5f7502062abdc..62c41894801c1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -495,6 +495,7 @@ x-pack/examples/third_party_maps_source_example @elastic/kibana-gis src/plugins/maps_ems @elastic/kibana-gis x-pack/plugins/maps @elastic/kibana-gis x-pack/packages/maps/vector_tile_utils @elastic/kibana-gis +x-pack/plugins/metrics_data_access @elastic/infra-monitoring-ui x-pack/packages/ml/agg_utils @elastic/ml-ui x-pack/packages/ml/anomaly_utils @elastic/ml-ui x-pack/packages/ml/category_validator @elastic/ml-ui diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 74c2df42d3ebe..8e756b1d28ad9 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: 2023-09-13 +date: 2023-09-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 2b846854e3332..b877ec225405a 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.devdocs.json b/api_docs/aiops.devdocs.json index 7d557f4d3c601..9ac0267216277 100644 --- a/api_docs/aiops.devdocs.json +++ b/api_docs/aiops.devdocs.json @@ -676,6 +676,20 @@ "path": "x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "aiops", + "id": "def-public.AiopsAppDependencies.isServerless", + "type": "CompoundType", + "tags": [], + "label": "isServerless", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -759,6 +773,22 @@ "path": "x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "aiops", + "id": "def-public.ChangePointDetectionAppStateProps.isServerless", + "type": "CompoundType", + "tags": [], + "label": "isServerless", + "description": [ + "Optional flag to indicate whether kibana is running in serverless" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -842,6 +872,22 @@ "path": "x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "aiops", + "id": "def-public.LogCategorizationAppStateProps.isServerless", + "type": "CompoundType", + "tags": [], + "label": "isServerless", + "description": [ + "Optional flag to indicate whether kibana is running in serverless" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -941,6 +987,22 @@ "path": "x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "aiops", + "id": "def-public.LogRateAnalysisAppStateProps.isServerless", + "type": "CompoundType", + "tags": [], + "label": "isServerless", + "description": [ + "Optional flag to indicate whether kibana is running in serverless" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1172,6 +1234,22 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "aiops", + "id": "def-public.LogRateAnalysisContentWrapperProps.isServerless", + "type": "CompoundType", + "tags": [], + "label": "isServerless", + "description": [ + "Optional flag to indicate whether kibana is running in serverless" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 7080314757917..dbd0522754a70 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.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 | |-------------------|-----------|------------------------|-----------------| -| 61 | 1 | 3 | 1 | +| 66 | 1 | 4 | 1 | ## Client diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 49ebca6cd544b..12be54e13e36c 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: 2023-09-13 +date: 2023-09-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 0321e08da232e..3566f956e5fd3 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: 2023-09-13 +date: 2023-09-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 ccc6dae388e7c..af6b2a8e7d3c6 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: 2023-09-13 +date: 2023-09-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 2bad7c5caf69e..168e97feec649 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: 2023-09-13 +date: 2023-09-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 b7b359acda646..e8e186955453f 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: 2023-09-13 +date: 2023-09-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 9f3e7bacf423f..32726ac5619e9 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: 2023-09-13 +date: 2023-09-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 35c31f24455e0..52726f2aabe72 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: 2023-09-13 +date: 2023-09-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 c4ea980bdfd40..0a4bded6ea63f 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: 2023-09-13 +date: 2023-09-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 aaf83ded16c82..eb33584a298c6 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.devdocs.json b/api_docs/cloud.devdocs.json index ea1d5a9f36d07..c9f43718fec8d 100644 --- a/api_docs/cloud.devdocs.json +++ b/api_docs/cloud.devdocs.json @@ -191,7 +191,7 @@ "label": "serverless", "description": [], "signature": [ - "{ project_id: string; } | undefined" + "{ project_id: string; project_name?: string | undefined; } | undefined" ], "path": "x-pack/plugins/cloud/public/plugin.tsx", "deprecated": false, @@ -454,7 +454,7 @@ "\nServerless configuration" ], "signature": [ - "{ projectId?: string | undefined; }" + "{ projectId?: string | undefined; projectName?: string | undefined; }" ], "path": "x-pack/plugins/cloud/public/types.ts", "deprecated": false, @@ -790,7 +790,7 @@ "\nServerless configuration" ], "signature": [ - "{ projectId?: string | undefined; }" + "{ projectId?: string | undefined; projectName?: string | undefined; }" ], "path": "x-pack/plugins/cloud/public/types.ts", "deprecated": false, @@ -1053,7 +1053,7 @@ "\nServerless configuration.\n" ], "signature": [ - "{ projectId?: string | undefined; }" + "{ projectId?: string | undefined; projectName?: string | undefined; }" ], "path": "x-pack/plugins/cloud/server/plugin.ts", "deprecated": false, diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 8baed658a86d9..b330798e85280 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_chat.mdx b/api_docs/cloud_chat.mdx index 2da12d342ced2..705e89f0625cd 100644 --- a/api_docs/cloud_chat.mdx +++ b/api_docs/cloud_chat.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChat title: "cloudChat" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChat plugin -date: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_chat_provider.mdx b/api_docs/cloud_chat_provider.mdx index cfefd3c8175fe..ac0893a0d1c8e 100644 --- a/api_docs/cloud_chat_provider.mdx +++ b/api_docs/cloud_chat_provider.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChatProvider title: "cloudChatProvider" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChatProvider plugin -date: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChatProvider'] --- import cloudChatProviderObj from './cloud_chat_provider.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index ad12a3d3293e5..fa27678979388 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: 2023-09-13 +date: 2023-09-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 07ba774eeb694..ea543570fc6c5 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.devdocs.json b/api_docs/cloud_experiments.devdocs.json index d08957de16642..da90785517ae6 100644 --- a/api_docs/cloud_experiments.devdocs.json +++ b/api_docs/cloud_experiments.devdocs.json @@ -117,7 +117,7 @@ "\nFetch the configuration assigned to variation `configKey`. If nothing is found, fallback to `defaultValue`." ], "signature": [ - "(featureFlagName: \"security-solutions.add-integrations-url\", defaultValue: Data) => Promise" + "(featureFlagName: \"security-solutions.add-integrations-url\" | \"security-solutions.guided-onboarding-content\", defaultValue: Data) => Promise" ], "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", "deprecated": false, @@ -126,14 +126,14 @@ { "parentPluginId": "cloudExperiments", "id": "def-common.CloudExperimentsPluginStart.getVariation.$1", - "type": "string", + "type": "CompoundType", "tags": [], "label": "featureFlagName", "description": [ "The name of the key to find the config variation. {@link CloudExperimentsFeatureFlagNames }." ], "signature": [ - "\"security-solutions.add-integrations-url\"" + "\"security-solutions.add-integrations-url\" | \"security-solutions.guided-onboarding-content\"" ], "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", "deprecated": false, @@ -227,7 +227,7 @@ "\nThe names of the feature flags declared in Kibana.\nValid keys are defined in {@link FEATURE_FLAG_NAMES}. When using a new feature flag, add the name to the list.\n" ], "signature": [ - "\"security-solutions.add-integrations-url\"" + "\"security-solutions.add-integrations-url\" | \"security-solutions.guided-onboarding-content\"" ], "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", "deprecated": false, diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index 77d1d81611094..5cc4ae7c1de24 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: 2023-09-13 +date: 2023-09-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 fa344b8cd1e08..b9dce36c9438a 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: 2023-09-13 +date: 2023-09-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 a5647838823c2..9dcd49377e9ae 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: 2023-09-13 +date: 2023-09-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 678f4bc4d01d6..974eaf7db8aec 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: 2023-09-13 +date: 2023-09-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 6222fdddf3101..5996c17cdae0b 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: 2023-09-13 +date: 2023-09-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 ed8b09b8aa01d..0033170c5976a 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: 2023-09-13 +date: 2023-09-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 29e6604854c95..8e89cd3bacc87 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: 2023-09-13 +date: 2023-09-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 d0984d0dba3e1..7a119db49a26d 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: 2023-09-13 +date: 2023-09-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 84b3aa93242c4..9e9f9e9eff6bb 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -5147,36 +5147,31 @@ }, { "parentPluginId": "data", - "id": "def-public.parseSearchSourceJSON", + "id": "def-public.OpenIncompleteResultsModalButton", "type": "Function", "tags": [], - "label": "parseSearchSourceJSON", + "label": "OpenIncompleteResultsModalButton", "description": [], "signature": [ - "(searchSourceJSON: string) => ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SerializedSearchSourceFields", - "text": "SerializedSearchSourceFields" - } + "(props: ", + "OpenIncompleteResultsModalButtonProps", + ") => JSX.Element" ], - "path": "src/plugins/data/common/search/search_source/parse_json.ts", + "path": "src/plugins/data/public/incomplete_results_modal/index.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "data", - "id": "def-public.parseSearchSourceJSON.$1", - "type": "string", + "id": "def-public.OpenIncompleteResultsModalButton.$1", + "type": "Object", "tags": [], - "label": "searchSourceJSON", + "label": "props", "description": [], "signature": [ - "string" + "OpenIncompleteResultsModalButtonProps" ], - "path": "src/plugins/data/common/search/search_source/parse_json.ts", + "path": "src/plugins/data/public/incomplete_results_modal/index.tsx", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -5187,31 +5182,36 @@ }, { "parentPluginId": "data", - "id": "def-public.ShardFailureOpenModalButton", + "id": "def-public.parseSearchSourceJSON", "type": "Function", "tags": [], - "label": "ShardFailureOpenModalButton", + "label": "parseSearchSourceJSON", "description": [], "signature": [ - "(props: ", - "ShardFailureOpenModalButtonProps", - ") => JSX.Element" + "(searchSourceJSON: string) => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SerializedSearchSourceFields", + "text": "SerializedSearchSourceFields" + } ], - "path": "src/plugins/data/public/shard_failure_modal/index.tsx", + "path": "src/plugins/data/common/search/search_source/parse_json.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "data", - "id": "def-public.ShardFailureOpenModalButton.$1", - "type": "Object", + "id": "def-public.parseSearchSourceJSON.$1", + "type": "string", "tags": [], - "label": "props", + "label": "searchSourceJSON", "description": [], "signature": [ - "ShardFailureOpenModalButtonProps" + "string" ], - "path": "src/plugins/data/public/shard_failure_modal/index.tsx", + "path": "src/plugins/data/common/search/search_source/parse_json.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -9595,104 +9595,6 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "data", - "id": "def-public.ShardFailureRequest", - "type": "Interface", - "tags": [], - "label": "ShardFailureRequest", - "description": [], - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "data", - "id": "def-public.ShardFailureRequest.docvalue_fields", - "type": "Array", - "tags": [], - "label": "docvalue_fields", - "description": [], - "signature": [ - "string[]" - ], - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-public.ShardFailureRequest._source", - "type": "Unknown", - "tags": [], - "label": "_source", - "description": [], - "signature": [ - "unknown" - ], - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-public.ShardFailureRequest.query", - "type": "Unknown", - "tags": [], - "label": "query", - "description": [], - "signature": [ - "unknown" - ], - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-public.ShardFailureRequest.script_fields", - "type": "Unknown", - "tags": [], - "label": "script_fields", - "description": [], - "signature": [ - "unknown" - ], - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-public.ShardFailureRequest.sort", - "type": "Unknown", - "tags": [], - "label": "sort", - "description": [], - "signature": [ - "unknown" - ], - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-public.ShardFailureRequest.stored_fields", - "type": "Array", - "tags": [], - "label": "stored_fields", - "description": [], - "signature": [ - "string[]" - ], - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false } ], "enums": [ @@ -10152,7 +10054,7 @@ "section": "def-common.TimeRange", "text": "TimeRange" }, - " | undefined; disableShardWarnings?: boolean | undefined; }" + " | undefined; disableWarningToasts?: boolean | undefined; }" ], "path": "src/plugins/data/common/search/expressions/kibana_context_type.ts", "deprecated": false, @@ -13803,18 +13705,6 @@ "plugin": "timelines", "path": "x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts" }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" - }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" - }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/lib/get_fields.ts" - }, { "plugin": "apm", "path": "x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts" @@ -13923,6 +13813,18 @@ "plugin": "graph", "path": "x-pack/plugins/graph/public/state_management/persistence.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" + }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" + }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/lib/get_fields.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/containers/sourcerer/create_sourcerer_data_view.ts" @@ -14812,14 +14714,14 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" - }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/services/persistence/deserialize.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/state_management/datasource.test.ts" @@ -21544,18 +21446,6 @@ "plugin": "timelines", "path": "x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts" }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" - }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" - }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/lib/get_fields.ts" - }, { "plugin": "apm", "path": "x-pack/plugins/apm/server/routes/data_view/create_static_data_view.ts" @@ -21664,6 +21554,18 @@ "plugin": "graph", "path": "x-pack/plugins/graph/public/state_management/persistence.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" + }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/common/index_patterns_utils.ts" + }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/lib/get_fields.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/containers/sourcerer/create_sourcerer_data_view.ts" @@ -22553,14 +22455,14 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" - }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/services/persistence/deserialize.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/lib/search_strategies/strategies/abstract_search_strategy.ts" + }, { "plugin": "graph", "path": "x-pack/plugins/graph/public/state_management/datasource.test.ts" diff --git a/api_docs/data.mdx b/api_docs/data.mdx index e03cb84f065e1..7423ce210e26e 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: 2023-09-13 +date: 2023-09-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 | |-------------------|-----------|------------------------|-----------------| -| 3311 | 33 | 2584 | 26 | +| 3308 | 33 | 2577 | 24 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 94a4d83f941cd..4093a923fd91c 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: 2023-09-13 +date: 2023-09-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 | |-------------------|-----------|------------------------|-----------------| -| 3311 | 33 | 2584 | 26 | +| 3308 | 33 | 2577 | 24 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index ceb9136800672..f3cf4a4662778 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -915,6 +915,75 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-public.SearchResponseIncompleteWarning", + "type": "Interface", + "tags": [], + "label": "SearchResponseIncompleteWarning", + "description": [ + "\nA warning object for a search response with incomplete ES results\nES returns incomplete results when:\n1) Set timeout flag on search and the timeout expires on cluster\n2) Some shard failures on a cluster\n3) skipped remote(s) (skip_unavailable=true)\n a. all shards failed\n b. disconnected/not-connected" + ], + "path": "src/plugins/data/public/search/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-public.SearchResponseIncompleteWarning.type", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "\ntype: for sorting out incomplete warnings" + ], + "signature": [ + "\"incomplete\"" + ], + "path": "src/plugins/data/public/search/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-public.SearchResponseIncompleteWarning.message", + "type": "string", + "tags": [], + "label": "message", + "description": [ + "\nmessage: human-friendly message" + ], + "path": "src/plugins/data/public/search/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-public.SearchResponseIncompleteWarning.clusters", + "type": "Object", + "tags": [], + "label": "clusters", + "description": [ + "\nclusters: cluster details." + ], + "signature": [ + "{ [x: string]: ", + { + "pluginId": "@kbn/es-types", + "scope": "common", + "docId": "kibKbnEsTypesPluginApi", + "section": "def-common.ClusterDetails", + "text": "ClusterDetails" + }, + "; }" + ], + "path": "src/plugins/data/public/search/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-public.SearchSessionInfoProvider", @@ -1448,9 +1517,13 @@ "\nA warning object for a search response with warnings" ], "signature": [ - "SearchResponseTimeoutWarning", - " | ", - "SearchResponseShardFailureWarning" + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataSearchPluginApi", + "section": "def-public.SearchResponseIncompleteWarning", + "text": "SearchResponseIncompleteWarning" + } ], "path": "src/plugins/data/public/search/types.ts", "deprecated": false, @@ -7144,7 +7217,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - " | undefined, abortSignal?: AbortSignal | undefined, searchSessionId?: string | undefined, disableShardFailureWarning?: boolean | undefined) => Promise<", + " | undefined, abortSignal?: AbortSignal | undefined, searchSessionId?: string | undefined, disableWarningToasts?: boolean | undefined) => Promise<", "SearchResponse", "" + "React.FunctionComponent" ], "path": "x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx", "deprecated": false, @@ -489,15 +481,7 @@ "label": "DataVisualizerPluginStart", "description": [], "signature": [ - "{ getFileDataVisualizerComponent: () => Promise<() => React.FC>; getIndexDataVisualizerComponent: () => Promise<() => React.FC<{ getAdditionalLinks?: ", - { - "pluginId": "dataVisualizer", - "scope": "public", - "docId": "kibDataVisualizerPluginApi", - "section": "def-public.GetAdditionalLinks", - "text": "GetAdditionalLinks" - }, - " | undefined; }>>; getDataComparisonComponent: () => Promise<() => React.FC<", + "{ getFileDataVisualizerComponent: () => Promise<() => React.FC>; getIndexDataVisualizerComponent: () => Promise<() => React.FC>; getDataComparisonComponent: () => Promise<() => React.FC<", "DataComparisonDetectionAppStateProps", ">>; getMaxBytesFormatted: () => string; }" ], diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index 45e1f8b045824..75210d466cd5c 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 36e26120e41e0..6df51abca263b 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -18,9 +18,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | ---------------|-----------|-----------| | | ml, stackAlerts | - | | | ruleRegistry, ml, securitySolution, observability, infra, monitoring, stackAlerts, synthetics, transform, uptime | - | -| | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, dataViews, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, visTypeTimeseries, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, data | - | -| | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, dataViews, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, visTypeTimeseries, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, data | - | -| | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, data, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, visTypeTimeseries, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega | - | +| | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, dataViews, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, visTypeTimeseries, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, data | - | +| | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, dataViews, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, visTypeTimeseries, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, data | - | +| | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, data, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, visTypeTimeseries, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega | - | | | home, data, esUiShared, savedObjectsManagement, ml, exploratoryView, fleet, observability, apm, indexLifecycleManagement, observabilityOnboarding, synthetics, upgradeAssistant, uptime, ux, kibanaOverview | - | | | share, uiActions, guidedOnboarding, home, management, spaces, security, savedObjects, indexManagement, serverless, visualizations, controls, dashboard, savedObjectsTagging, expressionXY, lens, expressionMetricVis, expressionGauge, alerting, triggersActionsUi, cases, licenseManagement, advancedSettings, maps, dataVisualizer, aiops, ml, exploratoryView, fleet, observability, infra, profiling, apm, expressionImage, expressionMetric, expressionError, expressionRevealImage, expressionRepeatImage, expressionShape, crossClusterReplication, enterpriseSearch, globalSearchBar, graph, grokdebugger, indexLifecycleManagement, ingestPipelines, logstash, monitoring, observabilityOnboarding, osquery, devTools, painlessLab, remoteClusters, rollup, searchprofiler, newsfeed, securitySolution, snapshotRestore, synthetics, transform, upgradeAssistant, uptime, ux, watcher, cloudDataMigration, console, filesManagement, kibanaOverview, visDefaultEditor, expressionHeatmap, expressionLegacyMetricVis, expressionPartitionVis, expressionTagcloud, visTypeTable, visTypeTimelion, visTypeTimeseries, visTypeVega, visTypeVislib | - | | | encryptedSavedObjects, actions, data, ml, securitySolution, logstash, cloudChat | - | @@ -45,7 +45,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | securitySolution | - | | | securitySolution | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjectsTaggingOss, savedObjectsTagging, securitySolution, lists, upgradeAssistant, savedObjectsManagement, @kbn/core-saved-objects-api-server, @kbn/core-saved-objects-import-export-server-internal, home, canvas, savedObjects, @kbn/core-saved-objects-browser-mocks, @kbn/core-ui-settings-server-internal | - | -| | @kbn/core-saved-objects-migration-server-internal, actions, dataViews, data, alerting, lens, lists, cases, savedObjectsTagging, securitySolution, visualizations, savedSearch, canvas, graph, maps, dashboard, @kbn/core-test-helpers-so-type-serializer | - | +| | @kbn/core-saved-objects-migration-server-internal, actions, dataViews, data, alerting, lens, lists, cases, savedObjectsTagging, securitySolution, savedSearch, canvas, graph, visualizations, maps, dashboard, @kbn/core-test-helpers-so-type-serializer | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | @@ -98,9 +98,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-browser-internal | - | | | home, osquery | - | | | @kbn/core-root-browser-internal, @kbn/core-saved-objects-browser-mocks | - | -| | visTypeTimeseries, graph, dataViewManagement, dataViews | - | -| | visTypeTimeseries, graph, dataViewManagement, dataViews | - | -| | visTypeTimeseries, graph, dataViewManagement | - | +| | graph, visTypeTimeseries, dataViewManagement, dataViews | - | +| | graph, visTypeTimeseries, dataViewManagement, dataViews | - | +| | graph, visTypeTimeseries, dataViewManagement | - | | | visualizations, graph | - | | | @kbn/core, lens, savedObjects | - | | | dataViews, maps | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 0c396bf1c2d0c..666a4ceceed90 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -573,7 +573,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [get_display_value.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/query/filter_manager/lib/get_display_value.ts#:~:text=title), [inspector_stats.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/search_source/inspect/inspector_stats.ts#:~:text=title), [response_writer.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/tabify/response_writer.ts#:~:text=title), [painless_error.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/errors/painless_error.tsx#:~:text=title), [field.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/param_types/field.ts#:~:text=title), [agg_config.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/agg_config.test.ts#:~:text=title), [_terms_other_bucket_helper.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts#:~:text=title), [multi_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts#:~:text=title), [multi_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts#:~:text=title), [rare_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/rare_terms.test.ts#:~:text=title)+ 3 more | - | | | [get_display_value.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/query/filter_manager/lib/get_display_value.ts#:~:text=title), [inspector_stats.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/search_source/inspect/inspector_stats.ts#:~:text=title), [response_writer.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/tabify/response_writer.ts#:~:text=title), [painless_error.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/errors/painless_error.tsx#:~:text=title), [field.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/param_types/field.ts#:~:text=title), [agg_config.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/agg_config.test.ts#:~:text=title), [_terms_other_bucket_helper.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts#:~:text=title), [multi_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts#:~:text=title), [multi_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts#:~:text=title), [rare_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/rare_terms.test.ts#:~:text=title)+ 3 more | - | | | [get_display_value.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/query/filter_manager/lib/get_display_value.ts#:~:text=title), [inspector_stats.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/search_source/inspect/inspector_stats.ts#:~:text=title), [response_writer.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/tabify/response_writer.ts#:~:text=title), [painless_error.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/errors/painless_error.tsx#:~:text=title), [field.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/param_types/field.ts#:~:text=title), [agg_config.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/agg_config.test.ts#:~:text=title), [_terms_other_bucket_helper.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts#:~:text=title), [multi_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts#:~:text=title), [multi_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/multi_terms.test.ts#:~:text=title), [rare_terms.test.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/common/search/aggs/buckets/rare_terms.test.ts#:~:text=title)+ 3 more | - | -| | [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [shard_failure_open_modal_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.tsx#:~:text=toMountPoint), [shard_failure_open_modal_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.tsx#:~:text=toMountPoint), [handle_warnings.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/fetch/handle_warnings.tsx#:~:text=toMountPoint), [handle_warnings.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/fetch/handle_warnings.tsx#:~:text=toMountPoint), [delete_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx#:~:text=toMountPoint), [delete_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx#:~:text=toMountPoint)+ 8 more | - | +| | [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [search_interceptor.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/search_interceptor/search_interceptor.ts#:~:text=toMountPoint), [open_incomplete_results_modal_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/incomplete_results_modal/open_incomplete_results_modal_button.tsx#:~:text=toMountPoint), [open_incomplete_results_modal_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/incomplete_results_modal/open_incomplete_results_modal_button.tsx#:~:text=toMountPoint), [handle_warnings.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/fetch/handle_warnings.tsx#:~:text=toMountPoint), [handle_warnings.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/fetch/handle_warnings.tsx#:~:text=toMountPoint), [delete_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx#:~:text=toMountPoint), [delete_button.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/sessions_mgmt/components/actions/delete_button.tsx#:~:text=toMountPoint)+ 8 more | - | | | [get_columns.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/sessions_mgmt/lib/get_columns.tsx#:~:text=RedirectAppLinks), [get_columns.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/sessions_mgmt/lib/get_columns.tsx#:~:text=RedirectAppLinks), [get_columns.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/sessions_mgmt/lib/get_columns.tsx#:~:text=RedirectAppLinks), [connected_search_session_indicator.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.tsx#:~:text=RedirectAppLinks), [connected_search_session_indicator.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.tsx#:~:text=RedirectAppLinks), [connected_search_session_indicator.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.tsx#:~:text=RedirectAppLinks) | - | | | [session_service.ts](https://github.com/elastic/kibana/tree/main/src/plugins/data/server/search/session/session_service.ts#:~:text=authc) | - | | | [data_table.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx#:~:text=executeTriggerActions), [data_table.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/data/public/utils/table_inspector_view/components/data_table.tsx#:~:text=executeTriggerActions) | - | @@ -1483,7 +1483,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedRowRenderer), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedRowRenderer) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [columns.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx#:~:text=BrowserField), [columns.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx#:~:text=BrowserField), [enrichment_summary.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx#:~:text=BrowserField), [enrichment_summary.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx#:~:text=BrowserField), [use_data_view.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/use_data_view.tsx#:~:text=BrowserField)+ 29 more | - | -| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields)+ 102 more | - | +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields)+ 104 more | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyRequest), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyRequest) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyResponse), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyResponse) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject) | - | @@ -1564,7 +1564,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | ---------------|-----------|-----------| | | [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/server/alert_rules/common.ts#:~:text=alertFactory), [message_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/server/alert_rules/tls_rule/message_utils.ts#:~:text=alertFactory), [tls_rule.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/server/alert_rules/tls_rule/tls_rule.ts#:~:text=alertFactory), [monitor_status_rule.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts#:~:text=alertFactory) | - | | | [stderr_logs.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx#:~:text=indexPatternId) | - | -| | [toast_title.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_list/toast_title.tsx#:~:text=toMountPoint), [toast_title.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_list/toast_title.tsx#:~:text=toMountPoint), [delete_monitor.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx#:~:text=toMountPoint), [delete_monitor.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx#:~:text=toMountPoint), [delete_monitor.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx#:~:text=toMountPoint), [browser_test_results.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx#:~:text=toMountPoint), [browser_test_results.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx#:~:text=toMountPoint), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=toMountPoint), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=toMountPoint), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=toMountPoint)+ 6 more | - | +| | [toast_title.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_list/toast_title.tsx#:~:text=toMountPoint), [toast_title.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/state/monitor_list/toast_title.tsx#:~:text=toMountPoint), [browser_test_results.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx#:~:text=toMountPoint), [browser_test_results.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx#:~:text=toMountPoint), [delete_monitor.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx#:~:text=toMountPoint), [delete_monitor.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx#:~:text=toMountPoint), [delete_monitor.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx#:~:text=toMountPoint), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=toMountPoint), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=toMountPoint), [delete_param.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx#:~:text=toMountPoint)+ 6 more | - | | | [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=RedirectAppLinks), [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=RedirectAppLinks), [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=RedirectAppLinks) | - | | | [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=KibanaThemeProvider), [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=KibanaThemeProvider), [synthetics_app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/synthetics/public/apps/synthetics/synthetics_app.tsx#:~:text=KibanaThemeProvider) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 35aa77b621a4d..948d9758fd928 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 5c28c06fd69c0..d46771ec4eb50 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: 2023-09-13 +date: 2023-09-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 ef5fa29530011..85bffb395b8ea 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: 2023-09-13 +date: 2023-09-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 ff158f6a5a37f..901a23c16fdab 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: 2023-09-13 +date: 2023-09-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 b653fb78036e4..5a987f12690db 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: 2023-09-13 +date: 2023-09-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 70c1b911bda7e..b4a882b8906b2 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: 2023-09-13 +date: 2023-09-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 9217763484b93..7b688dc8655ad 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: 2023-09-13 +date: 2023-09-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 947b0e22a3a51..8af64809ceef5 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: 2023-09-13 +date: 2023-09-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 a203be3c2e59b..1ae48950342a2 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: 2023-09-13 +date: 2023-09-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 025b910b17d62..9406c7a19ca3b 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: 2023-09-13 +date: 2023-09-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 2996d73375ba5..b0b973b5a53e2 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: 2023-09-13 +date: 2023-09-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 252d84810e54b..b36bb65333ccb 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 3fff455b0a940..a94b1f89dc9e4 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: 2023-09-13 +date: 2023-09-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 a7af7966142de..ce623ebeda118 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: 2023-09-13 +date: 2023-09-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 e022424c3bcfd..bd4fc330fcb3e 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 025a92714cb2b..0b9fab98865c6 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: 2023-09-13 +date: 2023-09-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 f77caa84872dd..27483a359f418 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: 2023-09-13 +date: 2023-09-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 df0d244e525e0..a3e2f864cee12 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: 2023-09-13 +date: 2023-09-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 216d05dfda4b5..17ac0774fdedd 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: 2023-09-13 +date: 2023-09-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 7447f9267eeab..7f53d29d838c7 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: 2023-09-13 +date: 2023-09-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 7f318a76a2e2a..53e49358be1c3 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: 2023-09-13 +date: 2023-09-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 fcc3d1cdddc09..4b21c18134a2e 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: 2023-09-13 +date: 2023-09-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 1e57837174182..779fb0f3d146f 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: 2023-09-13 +date: 2023-09-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 4d8583e8c96ed..c83cabc55184c 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: 2023-09-13 +date: 2023-09-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 55b73dc07e946..29974858ad72e 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: 2023-09-13 +date: 2023-09-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 a7ea5594dc7e1..6e82d0d68330d 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: 2023-09-13 +date: 2023-09-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 4fc8bfe7e5077..bbfccbe06ebae 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 8ff4021bced53..f78d59a032851 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index b6ead9d135807..f1adb8a1a2a78 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: 2023-09-13 +date: 2023-09-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 340c879e1b751..0dbcdb0f1444b 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: 2023-09-13 +date: 2023-09-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 b97278b601b79..a8070868105cc 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: 2023-09-13 +date: 2023-09-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 d9370b426ba25..f30fe22999e2b 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: 2023-09-13 +date: 2023-09-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 e2b7e5da3f308..de36533f5766b 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: 2023-09-13 +date: 2023-09-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 a2d2ac414a189..2ed77908e5da4 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: 2023-09-13 +date: 2023-09-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 1e0c1befd77ce..d3f3e107cb2ef 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: 2023-09-13 +date: 2023-09-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 727ef69690db4..55ac70ca30b37 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: 2023-09-13 +date: 2023-09-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 aeebb152ddbb7..d5b5dd62d66f4 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: 2023-09-13 +date: 2023-09-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 30e0ffc11e61b..331ac5c132f79 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: 2023-09-13 +date: 2023-09-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 461076745bfca..6d355e15ee998 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: 2023-09-13 +date: 2023-09-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 10df7ee6b8495..c07d0a6393c68 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.devdocs.json b/api_docs/infra.devdocs.json index 96f62ca88f47d..2e4e16322dc43 100644 --- a/api_docs/infra.devdocs.json +++ b/api_docs/infra.devdocs.json @@ -651,67 +651,6 @@ "path": "x-pack/plugins/infra/server/types.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "infra", - "id": "def-server.InfraPluginStart.getMetricIndices", - "type": "Function", - "tags": [], - "label": "getMetricIndices", - "description": [], - "signature": [ - "(savedObjectsClient: ", - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsClientContract", - "text": "SavedObjectsClientContract" - }, - ", sourceId?: string | undefined) => Promise" - ], - "path": "x-pack/plugins/infra/server/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "infra", - "id": "def-server.InfraPluginStart.getMetricIndices.$1", - "type": "Object", - "tags": [], - "label": "savedObjectsClient", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsClientContract", - "text": "SavedObjectsClientContract" - } - ], - "path": "x-pack/plugins/infra/server/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "infra", - "id": "def-server.InfraPluginStart.getMetricIndices.$2", - "type": "string", - "tags": [], - "label": "sourceId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/infra/server/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] } ], "lifecycle": "start", diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 81c6d278ba6c5..cb5373faeb001 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/inf | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 45 | 0 | 42 | 11 | +| 42 | 0 | 39 | 11 | ## Client diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 05d5cf4824821..6785eebfb44fe 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: 2023-09-13 +date: 2023-09-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 70bd1093402f0..cbd5ba83cf8fd 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: 2023-09-13 +date: 2023-09-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 ced2a0416e5ef..885012240eefe 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 840621476fc4a..88f2a074f774a 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: 2023-09-13 +date: 2023-09-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 30fafa575aa86..95ffd3943b4b9 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: 2023-09-13 +date: 2023-09-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 a50005a3eb4d3..5f3dccc5d0500 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: 2023-09-13 +date: 2023-09-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 087548ae3f2c7..e05c09790975d 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: 2023-09-13 +date: 2023-09-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_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 31dabd1555c9c..57c0dabdc37e4 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: 2023-09-13 +date: 2023-09-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 377eb4a494990..66112759c9db2 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: 2023-09-13 +date: 2023-09-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 ad361f8e3e7c1..a2f9e91b01a66 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.devdocs.json b/api_docs/kbn_analytics_client.devdocs.json index b9707eeb74ff3..54f5709af6432 100644 --- a/api_docs/kbn_analytics_client.devdocs.json +++ b/api_docs/kbn_analytics_client.devdocs.json @@ -750,6 +750,10 @@ "plugin": "infra", "path": "x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "apm", "path": "x-pack/plugins/apm/public/services/telemetry/telemetry_client.ts" @@ -938,6 +942,14 @@ "plugin": "infra", "path": "x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index 7c8bad3bcf0bd..e920beac1ee68 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 612a946dbe6b5..f6e891254503b 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: 2023-09-13 +date: 2023-09-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 29c87b3489d74..e406ba9a34453 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: 2023-09-13 +date: 2023-09-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 d0a75d3834b97..1bff9254bd1b1 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: 2023-09-13 +date: 2023-09-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 c7d43d33f7678..c6ab44aa0cdad 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: 2023-09-13 +date: 2023-09-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_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index 4dd5ec04c8753..67c999ca50b9b 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 16349148ffbdb..95f7e4c74a1f7 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: 2023-09-13 +date: 2023-09-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.mdx b/api_docs/kbn_apm_synthtrace.mdx index 211f858c95038..f25fe28d77197 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 9b59ec8bc69b5..242dfd64769d5 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: 2023-09-13 +date: 2023-09-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 caa146e8e0c55..5ff0fc1225a35 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: 2023-09-13 +date: 2023-09-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 ce33e7094b5d3..2b238ec163d48 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index e154d1876617a..c80f717a1e514 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: 2023-09-13 +date: 2023-09-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 43c2d48d8d503..819dc6dd0a2a4 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: 2023-09-13 +date: 2023-09-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.mdx b/api_docs/kbn_chart_expressions_common.mdx index dc2a22537cfbd..ae3aea69c410e 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 3057e387f2dce..245f1b10cd33c 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: 2023-09-13 +date: 2023-09-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 624246f3f1cbe..b75caeca1fa65 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: 2023-09-13 +date: 2023-09-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 9bc2481809ebc..c52519bcc862c 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: 2023-09-13 +date: 2023-09-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 bed3382b721da..73057b54c2754 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: 2023-09-13 +date: 2023-09-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 e004b83be3ba0..6668d2a5b909b 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: 2023-09-13 +date: 2023-09-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 bcf1edf67f4d6..2d62a0396f5ed 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: 2023-09-13 +date: 2023-09-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_mocks.mdx b/api_docs/kbn_code_editor_mocks.mdx index 0693c819d3639..623b4a136c5f7 100644 --- a/api_docs/kbn_code_editor_mocks.mdx +++ b/api_docs/kbn_code_editor_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mocks title: "@kbn/code-editor-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mocks plugin -date: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mocks'] --- import kbnCodeEditorMocksObj from './kbn_code_editor_mocks.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 837799a3183ab..be78188db5fa9 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: 2023-09-13 +date: 2023-09-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 ea2afb6cebc6e..9a3526f8d55b9 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: 2023-09-13 +date: 2023-09-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 fd1b2b0704e5c..873a116363fe9 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: 2023-09-13 +date: 2023-09-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 fad14faae22ab..132a582a11125 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: 2023-09-13 +date: 2023-09-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 689fffafe3d10..87bb82e4738cf 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: 2023-09-13 +date: 2023-09-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 d60366283c07f..cd35a70520e55 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: 2023-09-13 +date: 2023-09-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 7685973bf5445..fdb62646a9cdc 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: 2023-09-13 +date: 2023-09-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_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index 3e120dd75aa81..945b648152c0b 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: 2023-09-13 +date: 2023-09-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 638a0719fbc92..411546d240dea 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: 2023-09-13 +date: 2023-09-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 38a5af9bca204..8879de82759d4 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: 2023-09-13 +date: 2023-09-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 cdd8ddc274859..7ce12abd81781 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: 2023-09-13 +date: 2023-09-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 b0e98295e3651..3cac1b5073f54 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: 2023-09-13 +date: 2023-09-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 d3fc29b22133c..f867c4dfae03c 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: 2023-09-13 +date: 2023-09-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 f75467bf89bd3..89727ab5ee6c3 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: 2023-09-13 +date: 2023-09-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 83bf6e86b3882..41c667df602e1 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: 2023-09-13 +date: 2023-09-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 3bceef68891e7..449457af36d15 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: 2023-09-13 +date: 2023-09-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 e6e96eac11a67..3216c2512a2d8 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: 2023-09-13 +date: 2023-09-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 e69b9cbd85f31..172aaf75bf395 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: 2023-09-13 +date: 2023-09-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 89677d63998f6..7d650851d2322 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: 2023-09-13 +date: 2023-09-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 1da42e9b40e3b..8a34055163ad9 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: 2023-09-13 +date: 2023-09-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 f089280e74a0e..7e536bb3c80de 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: 2023-09-13 +date: 2023-09-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 3be5e340de76f..69199645c8ee3 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: 2023-09-13 +date: 2023-09-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 fb8a09425d2e4..ae5e42ee30a20 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: 2023-09-13 +date: 2023-09-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 f2e2d4e81d5c0..8dac582596128 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: 2023-09-13 +date: 2023-09-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 799955a5d8168..a6cd17b343ec8 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: 2023-09-13 +date: 2023-09-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 a343df6e423d4..1dbfcd6d01dba 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: 2023-09-13 +date: 2023-09-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 2e0c77ef52b11..510322e9a6851 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: 2023-09-13 +date: 2023-09-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 d002a63d85cb6..17b263646651e 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: 2023-09-13 +date: 2023-09-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 9078dd27a2cd2..b10b633a23449 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: 2023-09-13 +date: 2023-09-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 627a503686bea..51df90e85568c 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: 2023-09-13 +date: 2023-09-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 18c9cf8270f55..1baa1400b72d0 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: 2023-09-13 +date: 2023-09-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 cac16801c9b61..8befdbe4efb5f 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: 2023-09-13 +date: 2023-09-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 ec21285b3e2a8..b13e23c106350 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: 2023-09-13 +date: 2023-09-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 2f5550e57d5d3..c2235048ef18f 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: 2023-09-13 +date: 2023-09-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 4ad9e7c5b741b..f1abfe097a458 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: 2023-09-13 +date: 2023-09-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 dba337f90278c..8a3a85fc1be23 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: 2023-09-13 +date: 2023-09-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 ade37e92fa17b..19d893d30386b 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: 2023-09-13 +date: 2023-09-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 b129f94245a42..c5745aae02aa5 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: 2023-09-13 +date: 2023-09-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 b8426f93d901d..0651025392f4e 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: 2023-09-13 +date: 2023-09-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 b223b8ad24295..289a6cb844d82 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: 2023-09-13 +date: 2023-09-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 94ff3b5d15f66..c78231e1e27d4 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: 2023-09-13 +date: 2023-09-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 85a3df5bd0d3f..e47e915819e46 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: 2023-09-13 +date: 2023-09-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 f65063eff2d64..6f555c7c43324 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: 2023-09-13 +date: 2023-09-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 24a60c23de605..8e40ef1f39af5 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: 2023-09-13 +date: 2023-09-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 ad7bbeba00b9c..f63c1684f07be 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: 2023-09-13 +date: 2023-09-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 e7601e739d8d0..76d3b5851d05e 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: 2023-09-13 +date: 2023-09-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 019dae5622e00..3243a8a3cfd5b 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: 2023-09-13 +date: 2023-09-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 625aea26f97c2..d5f736b5e0d31 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: 2023-09-13 +date: 2023-09-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 bb05db24ec7ee..515512908393f 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: 2023-09-13 +date: 2023-09-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 8d84a1cda3a30..37877d8645e86 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: 2023-09-13 +date: 2023-09-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 2bebe89767c7b..a94052975a2b1 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: 2023-09-13 +date: 2023-09-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 960f0bf180c46..95a882b31a5d7 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: 2023-09-13 +date: 2023-09-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 b129f424bc4d6..2947940248a1e 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: 2023-09-13 +date: 2023-09-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 efc5ffba7900a..0c35fa12a5a69 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: 2023-09-13 +date: 2023-09-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 8f44d2fbc2bf3..fa8fb1925a6af 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: 2023-09-13 +date: 2023-09-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 12fc7c154011e..a7465e7d2d9aa 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: 2023-09-13 +date: 2023-09-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 5d373c4a6d75f..f2abea084144d 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: 2023-09-13 +date: 2023-09-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 fa14ca9284b8e..66aa89fbf9827 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: 2023-09-13 +date: 2023-09-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 04251bcddd9b9..0d0d03a17287f 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: 2023-09-13 +date: 2023-09-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 df8abf49b100c..fe22065d61b1c 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: 2023-09-13 +date: 2023-09-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 b6efb8777a1b2..8c654fbe4e94a 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: 2023-09-13 +date: 2023-09-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 8d820a4a6512c..46bbbd25ffdb4 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: 2023-09-13 +date: 2023-09-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 0a82ff6f4bb98..dc47495962fdd 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: 2023-09-13 +date: 2023-09-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 6f255b40819c5..e014c1f65a5f6 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: 2023-09-13 +date: 2023-09-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 990ac7a7691a4..cee70719510d3 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: 2023-09-13 +date: 2023-09-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 7e3fc0712d744..6a857fc763722 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: 2023-09-13 +date: 2023-09-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 788740f733e54..3533cada95f3f 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: 2023-09-13 +date: 2023-09-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 7620efe9b717b..f12cbb8f560a9 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: 2023-09-13 +date: 2023-09-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 e45995f2ba22f..8ef6928be2d35 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: 2023-09-13 +date: 2023-09-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 edf36ab2b9b30..f9051d4be7d5e 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: 2023-09-13 +date: 2023-09-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 73eaab5107815..5010700af663a 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: 2023-09-13 +date: 2023-09-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 333bc2ef14e47..9632417d97a08 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: 2023-09-13 +date: 2023-09-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 c939eccfa85f0..32371fa3e881f 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: 2023-09-13 +date: 2023-09-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.mdx b/api_docs/kbn_core_http_resources_server.mdx index 75c5bafb6656d..70435e8900fb4 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: 2023-09-13 +date: 2023-09-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 e1a27e29f13d0..62c4d601228b5 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: 2023-09-13 +date: 2023-09-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 1db0150620673..6afe89bf7ec6d 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: 2023-09-13 +date: 2023-09-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 190f4aaba37e2..c192a1f7d34a9 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: 2023-09-13 +date: 2023-09-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 2b6111f5ee4b7..bd17112c851d1 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: 2023-09-13 +date: 2023-09-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 796deb8bd12d2..a21966bd7c9be 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -3703,14 +3703,6 @@ "plugin": "triggersActionsUi", "path": "x-pack/plugins/triggers_actions_ui/server/routes/config.ts" }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/routes/fields.ts" - }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "profiling", "path": "x-pack/plugins/profiling/server/routes/flamechart.ts" @@ -4323,6 +4315,14 @@ "plugin": "indexLifecycleManagement", "path": "x-pack/plugins/index_lifecycle_management/server/routes/api/snapshot_repositories/register_fetch_route.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/routes/fields.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "ingestPipelines", "path": "x-pack/plugins/ingest_pipelines/server/routes/api/get.ts" @@ -6269,14 +6269,6 @@ "plugin": "triggersActionsUi", "path": "x-pack/plugins/triggers_actions_ui/server/data/routes/indices.ts" }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/routes/vis.ts" - }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "profiling", "path": "x-pack/plugins/profiling/server/routes/setup.ts" @@ -6745,6 +6737,14 @@ "plugin": "indexLifecycleManagement", "path": "x-pack/plugins/index_lifecycle_management/server/routes/api/templates/register_add_policy_route.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/routes/vis.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "ingestPipelines", "path": "x-pack/plugins/ingest_pipelines/server/routes/api/create.ts" @@ -7971,10 +7971,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/create_script_route.ts" }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "reporting", "path": "x-pack/plugins/reporting/server/routes/internal/deprecations/deprecations.ts" @@ -8187,6 +8183,10 @@ "plugin": "enterpriseSearch", "path": "x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "ingestPipelines", "path": "x-pack/plugins/ingest_pipelines/server/routes/api/update.ts" @@ -8637,10 +8637,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/pinned_events/persist_pinned_event.ts" }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "enterpriseSearch", "path": "x-pack/plugins/enterprise_search/server/routes/workplace_search/security.ts" @@ -8653,6 +8649,10 @@ "plugin": "enterpriseSearch", "path": "x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "@kbn/core-http-router-server-internal", "path": "packages/core/http/core-http-router-server-internal/src/router.ts" @@ -8999,10 +8999,6 @@ "plugin": "observability", "path": "x-pack/plugins/observability/server/lib/annotations/register_annotation_apis.ts" }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "assetManager", "path": "x-pack/plugins/asset_manager/server/routes/sample_assets.ts" @@ -9155,6 +9151,10 @@ "plugin": "indexLifecycleManagement", "path": "x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_delete_route.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "ingestPipelines", "path": "x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts" @@ -13457,14 +13457,6 @@ "plugin": "@kbn/core-http-router-server-mocks", "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" }, - { - "plugin": "logsShared", - "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/custom_elements/find.ts" @@ -13525,10 +13517,18 @@ "plugin": "cloudSecurityPosture", "path": "x-pack/plugins/cloud_security_posture/server/routes/detection_engine/get_detection_engine_alerts_count_by_rule_tags.ts" }, + { + "plugin": "logsShared", + "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "fileUpload", "path": "x-pack/plugins/file_upload/server/routes.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "kubernetesSecurity", "path": "x-pack/plugins/kubernetes_security/server/routes/aggregate.ts" @@ -13933,14 +13933,6 @@ "plugin": "@kbn/core-http-router-server-mocks", "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" }, - { - "plugin": "logsShared", - "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/custom_elements/update.ts" @@ -13957,6 +13949,14 @@ "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/workpad/update.ts" }, + { + "plugin": "logsShared", + "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "transform", "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" @@ -14681,14 +14681,6 @@ "plugin": "aiops", "path": "x-pack/plugins/aiops/server/routes/log_categorization.ts" }, - { - "plugin": "logsShared", - "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/custom_elements/create.ts" @@ -14705,6 +14697,10 @@ "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/workpad/import.ts" }, + { + "plugin": "logsShared", + "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "fileUpload", "path": "x-pack/plugins/file_upload/server/routes.ts" @@ -14721,6 +14717,10 @@ "plugin": "fileUpload", "path": "x-pack/plugins/file_upload/server/routes.ts" }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "maps", "path": "x-pack/plugins/maps/server/data_indexing/indexing_routes.ts" @@ -15109,14 +15109,6 @@ "plugin": "@kbn/core-http-router-server-mocks", "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" }, - { - "plugin": "logsShared", - "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, - { - "plugin": "infra", - "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" - }, { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/custom_elements/delete.ts" @@ -15125,6 +15117,14 @@ "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/workpad/delete.ts" }, + { + "plugin": "logsShared", + "path": "x-pack/plugins/logs_shared/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, + { + "plugin": "infra", + "path": "x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" + }, { "plugin": "maps", "path": "x-pack/plugins/maps/server/data_indexing/indexing_routes.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 56192d84288a0..70fec81a1600d 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: 2023-09-13 +date: 2023-09-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 fac7054f4bedd..1699938318d95 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: 2023-09-13 +date: 2023-09-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 ebc8c2badc6d4..7fd219d7d3bfa 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: 2023-09-13 +date: 2023-09-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 6793915901fca..68dec69adeac5 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: 2023-09-13 +date: 2023-09-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 297bc703eced0..908cc14e43a5c 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: 2023-09-13 +date: 2023-09-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 f16a926b45ab2..3f7eb040e3d87 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: 2023-09-13 +date: 2023-09-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 5f57f2d579b04..93af3811a6145 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: 2023-09-13 +date: 2023-09-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 f6299a3b0cbe9..236117c87eb00 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: 2023-09-13 +date: 2023-09-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 4d3182846eda3..975887520d9f8 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: 2023-09-13 +date: 2023-09-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 edffd877512c5..32fea123b7185 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: 2023-09-13 +date: 2023-09-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 fd71c7f8d2581..a79d5d95fcd6a 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: 2023-09-13 +date: 2023-09-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 67205cc60f586..c65d53aeed4b2 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: 2023-09-13 +date: 2023-09-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 4cb2b9b7aa27c..00b8c72ea982c 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: 2023-09-13 +date: 2023-09-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 622f94777e1e9..0be2a17f23708 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: 2023-09-13 +date: 2023-09-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 af0d5329fdbe3..351325d6fcb54 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: 2023-09-13 +date: 2023-09-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 70f69fadbc86c..1cfadfaa33598 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: 2023-09-13 +date: 2023-09-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 c0954438f8bbc..12bf6da70cd35 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: 2023-09-13 +date: 2023-09-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 cb285fcbc0817..0603f2c22a481 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: 2023-09-13 +date: 2023-09-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 53d61904513b7..cc29c18b5eccc 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: 2023-09-13 +date: 2023-09-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 c1c6e19ab8a68..0f3288c527f1f 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: 2023-09-13 +date: 2023-09-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 b10208998bcd7..f221890918bce 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: 2023-09-13 +date: 2023-09-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 3ff5150143804..9ef95571d6ec4 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: 2023-09-13 +date: 2023-09-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 c44b0b2117ce5..1bd22908cf05f 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: 2023-09-13 +date: 2023-09-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 55e9bb16959e5..320d3491ddd4e 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: 2023-09-13 +date: 2023-09-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 8fac50c57da1a..eb9b8e61bd789 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: 2023-09-13 +date: 2023-09-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 1b172c825ace1..b32981d8db948 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: 2023-09-13 +date: 2023-09-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 7008beab1738c..600a6ce2c4e85 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: 2023-09-13 +date: 2023-09-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 8b7335baad4bf..5114b5ef550ba 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: 2023-09-13 +date: 2023-09-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 5ddb00dd955e7..eb45e7cd7de56 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: 2023-09-13 +date: 2023-09-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 3f2acf7b4fb3e..51da161fea69a 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: 2023-09-13 +date: 2023-09-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 2ac5493f2b133..0002e4a403d98 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: 2023-09-13 +date: 2023-09-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 90cf4cb1f9fd0..bedc0e434b931 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: 2023-09-13 +date: 2023-09-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 7d88695f51048..309afd3884b3a 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: 2023-09-13 +date: 2023-09-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 94583af89cadb..06b4bab3b2281 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: 2023-09-13 +date: 2023-09-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 8ae081bcb9b1e..7c199f6afde67 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: 2023-09-13 +date: 2023-09-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 3e535f141bc30..9331ff6fd7858 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: 2023-09-13 +date: 2023-09-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 2e20f288f809a..e837bf25fffae 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: 2023-09-13 +date: 2023-09-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_server.mdx b/api_docs/kbn_core_plugins_server.mdx index 724b2e312ed06..383e75f4d39c8 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: 2023-09-13 +date: 2023-09-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 b509c9f5e2c6c..a62bd5154bb4d 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: 2023-09-13 +date: 2023-09-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 43e99414f7c20..c2e152f2185e1 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: 2023-09-13 +date: 2023-09-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 1b35bf41a48fc..74fef18e566bb 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: 2023-09-13 +date: 2023-09-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 3572eec8dc6d7..a18dc730d73ef 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: 2023-09-13 +date: 2023-09-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 280ccbc6fbe40..fcc12071b4f8e 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: 2023-09-13 +date: 2023-09-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 95c7012b86872..6ab54881ab4e7 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: 2023-09-13 +date: 2023-09-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 da17aa9946e86..1f8a78a44b28c 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: 2023-09-13 +date: 2023-09-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 d6855a30e4fcb..46cd8adeec708 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: 2023-09-13 +date: 2023-09-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 641c6f84c886a..e875521f7e729 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: 2023-09-13 +date: 2023-09-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 5ffbe9c75bf4a..ab28fc5d8783c 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: 2023-09-13 +date: 2023-09-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 9d68a4399bdb8..cf4116caf19a9 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: 2023-09-13 +date: 2023-09-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 2169deffd755e..73ee01782a5da 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: 2023-09-13 +date: 2023-09-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 595e680adcd92..b5d748a52e7e1 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: 2023-09-13 +date: 2023-09-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 c8ada6c1d565d..b5ceef2e777ca 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: 2023-09-13 +date: 2023-09-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 9ff3c6997fdad..be9072f0e4529 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: 2023-09-13 +date: 2023-09-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 d237c9e4d649c..fd721c641376f 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: 2023-09-13 +date: 2023-09-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 6e9cd37dd72d1..e8172614844c3 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: 2023-09-13 +date: 2023-09-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 cad186b2dc033..eb7c5acee8d0d 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: 2023-09-13 +date: 2023-09-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 6e1664e89b1bd..b5a906e58f29f 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: 2023-09-13 +date: 2023-09-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 c1f3776997875..78429bd38bef2 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: 2023-09-13 +date: 2023-09-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.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index 2af69eecce1fe..ee9337a701759 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -10555,10 +10555,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts" }, - { - "plugin": "visualizations", - "path": "src/plugins/visualizations/server/saved_objects/visualization.ts" - }, { "plugin": "savedSearch", "path": "src/plugins/saved_search/server/saved_objects/search.ts" @@ -10575,6 +10571,10 @@ "plugin": "graph", "path": "x-pack/plugins/graph/server/saved_objects/graph_workspace.ts" }, + { + "plugin": "visualizations", + "path": "src/plugins/visualizations/server/saved_objects/visualization.ts" + }, { "plugin": "maps", "path": "x-pack/plugins/maps/server/saved_objects/setup_saved_objects.ts" diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index be93347de8bf6..08cedc47281f5 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: 2023-09-13 +date: 2023-09-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 21b3f41f0fee1..3d09c1a16bc3a 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: 2023-09-13 +date: 2023-09-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 46ead18c42752..c1969ff7fcf64 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: 2023-09-13 +date: 2023-09-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 1f28dab63ff5b..2f2d8700a177b 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: 2023-09-13 +date: 2023-09-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 647c4e01d8b17..f6bfeb127f620 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: 2023-09-13 +date: 2023-09-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 20d65f134cf1c..d7e033962fc9e 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: 2023-09-13 +date: 2023-09-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 0707e03010fb3..a95c85aef9c37 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: 2023-09-13 +date: 2023-09-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 33a38b2a54919..0dabf2f727906 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: 2023-09-13 +date: 2023-09-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 481cd2b4bfd41..a76db2618c59f 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: 2023-09-13 +date: 2023-09-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 b23a31f9048d2..f587c7486d7ac 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: 2023-09-13 +date: 2023-09-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 e8e77e92f6c28..1240773f8f285 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: 2023-09-13 +date: 2023-09-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 abfa1570e05ed..bacd8c4074058 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: 2023-09-13 +date: 2023-09-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_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 371e3c6f42444..76f2c659c0539 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: 2023-09-13 +date: 2023-09-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 db1e0f76d4d62..2dcb3799bbf4e 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: 2023-09-13 +date: 2023-09-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 f276b62a73423..3158b396d302c 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: 2023-09-13 +date: 2023-09-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 7c24094965b1e..c39e3a95b7cab 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: 2023-09-13 +date: 2023-09-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 770daf63751bf..1b6b496ff01ce 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: 2023-09-13 +date: 2023-09-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 9b21cae907972..f3ae61bddca70 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: 2023-09-13 +date: 2023-09-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 65327a6f206fd..5f7e5253e8de6 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: 2023-09-13 +date: 2023-09-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 1aa4a737229d7..162f712a79987 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: 2023-09-13 +date: 2023-09-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 9cb79338d1682..323971c10f5c8 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: 2023-09-13 +date: 2023-09-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 ff32cbf0d8e3c..3ad2e6c3f5384 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: 2023-09-13 +date: 2023-09-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 404134d87f917..f2db0b00fb013 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: 2023-09-13 +date: 2023-09-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 da875bbf0e182..eedd3364ff4e7 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: 2023-09-13 +date: 2023-09-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 1e64c972845b0..e94ae89864a72 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: 2023-09-13 +date: 2023-09-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 771d2a438138c..3d43868ad5bb8 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: 2023-09-13 +date: 2023-09-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 06fbdc6d3125b..f5066fad2f930 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: 2023-09-13 +date: 2023-09-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 06b5995f2a0a1..425a2531f5965 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: 2023-09-13 +date: 2023-09-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 dd2186a3171b8..3b4434e7d04ed 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: 2023-09-13 +date: 2023-09-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 a853e8d288304..03a8fe5503a63 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: 2023-09-13 +date: 2023-09-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 905bcbc3d5f6f..528e97e474e28 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index a601161cb0b97..ee13a8d30520a 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: 2023-09-13 +date: 2023-09-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 8ac9dd661d0df..a5a8d1ece6c35 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: 2023-09-13 +date: 2023-09-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 20099207784ab..561f30321c9ce 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: 2023-09-13 +date: 2023-09-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 64ee037296eed..b884da72ef8ec 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: 2023-09-13 +date: 2023-09-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 c4a834b032daa..283c43a32e967 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: 2023-09-13 +date: 2023-09-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 ba3d070bf504c..72855aea447dd 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: 2023-09-13 +date: 2023-09-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 625bce98cf1d1..ed671de8bf406 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: 2023-09-13 +date: 2023-09-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 c775e2c4cf663..dc69c5b1e51be 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: 2023-09-13 +date: 2023-09-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 e50ede7967e03..2ce0acc9109c2 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: 2023-09-13 +date: 2023-09-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 785c22d4ff37f..19b4f26db20a2 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: 2023-09-13 +date: 2023-09-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 638eab6243550..f90fd9b4c1c35 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: 2023-09-13 +date: 2023-09-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 caed466a20784..077dc04b14c4b 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: 2023-09-13 +date: 2023-09-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 99894427aa689..8b1a8a6d2442e 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: 2023-09-13 +date: 2023-09-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.devdocs.json b/api_docs/kbn_default_nav_ml.devdocs.json index 2b213eea008dc..1c99e5a71cbbd 100644 --- a/api_docs/kbn_default_nav_ml.devdocs.json +++ b/api_docs/kbn_default_nav_ml.devdocs.json @@ -172,7 +172,7 @@ "label": "children", "description": [], "signature": [ - "[{ title: string; id: \"root\"; children: [{ link: \"ml:overview\"; }, { link: \"ml:notifications\"; }]; }, { title: string; id: \"anomaly_detection\"; children: [{ title: string; link: \"ml:anomalyDetection\"; }, { link: \"ml:anomalyExplorer\"; }, { link: \"ml:singleMetricViewer\"; }, { link: \"ml:settings\"; }]; }, { id: \"data_frame_analytics\"; title: string; children: [{ title: string; link: \"ml:dataFrameAnalytics\"; }, { link: \"ml:resultExplorer\"; }, { link: \"ml:analyticsMap\"; }]; }, { id: \"model_management\"; title: string; children: [{ link: \"ml:nodesOverview\"; }, { link: \"ml:nodes\"; }]; }, { id: \"data_visualizer\"; title: string; children: [{ title: string; link: \"ml:fileUpload\"; }, { title: string; link: \"ml:indexDataVisualizer\"; }]; }, { id: \"aiops_labs\"; title: string; children: [{ link: \"ml:logRateAnalysis\"; }, { link: \"ml:logPatternAnalysis\"; }, { link: \"ml:changePointDetections\"; }]; }]" + "[{ title: string; id: \"root\"; children: [{ link: \"ml:overview\"; }, { link: \"ml:notifications\"; }]; }, { title: string; id: \"anomaly_detection\"; children: [{ title: string; link: \"ml:anomalyDetection\"; }, { link: \"ml:anomalyExplorer\"; }, { link: \"ml:singleMetricViewer\"; }, { link: \"ml:settings\"; }]; }, { id: \"data_frame_analytics\"; title: string; children: [{ title: string; link: \"ml:dataFrameAnalytics\"; }, { link: \"ml:resultExplorer\"; }, { link: \"ml:analyticsMap\"; }]; }, { id: \"model_management\"; title: string; children: [{ link: \"ml:nodesOverview\"; }, { link: \"ml:nodes\"; }]; }, { id: \"data_visualizer\"; title: string; children: [{ title: string; link: \"ml:fileUpload\"; }, { title: string; link: \"ml:indexDataVisualizer\"; }, { title: string; link: \"ml:dataComparison\"; }]; }, { id: \"aiops_labs\"; title: string; children: [{ link: \"ml:logRateAnalysis\"; }, { link: \"ml:logPatternAnalysis\"; }, { link: \"ml:changePointDetections\"; }]; }]" ], "path": "packages/default-nav/ml/default_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index ee9ee501515d8..c638cd5b02c66 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: 2023-09-13 +date: 2023-09-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 925f6e916d4b8..dc762c12268a5 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: 2023-09-13 +date: 2023-09-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 93ed8330f7bf1..874e379971558 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: 2023-09-13 +date: 2023-09-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 2d9fbd7349e62..632b6851d1c44 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: 2023-09-13 +date: 2023-09-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 3720039d4bfe4..0cbe305d95267 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: 2023-09-13 +date: 2023-09-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 01964ac5527d7..2dc3fe764321a 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: 2023-09-13 +date: 2023-09-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 c9b0fa9ec9aac..d74d52371df6f 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: 2023-09-13 +date: 2023-09-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 f0d79b25235ba..a3dd4e7d95c0c 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: 2023-09-13 +date: 2023-09-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 2bc1fc8dc1528..4015b041af24d 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: 2023-09-13 +date: 2023-09-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 7c97e78475f7e..0fe733a604fed 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: 2023-09-13 +date: 2023-09-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 0173d4a028259..6366e66b1508b 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: 2023-09-13 +date: 2023-09-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 96f106702aae0..d922109843f3c 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: 2023-09-13 +date: 2023-09-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_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index ab3c82e8fcdc8..12f38999e1656 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index 22c9ba4d80ae4..8db7f3bb462b7 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: 2023-09-13 +date: 2023-09-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 be71956d98fe5..5c70b0446e6eb 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: 2023-09-13 +date: 2023-09-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 40439d20ca089..8a9468dbb4ca5 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: 2023-09-13 +date: 2023-09-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 0712fca6d837e..88675e82eb0e8 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: 2023-09-13 +date: 2023-09-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.devdocs.json b/api_docs/kbn_es_types.devdocs.json index 7b364b08e03a3..37cab03f85e11 100644 --- a/api_docs/kbn_es_types.devdocs.json +++ b/api_docs/kbn_es_types.devdocs.json @@ -20,6 +20,100 @@ "classes": [], "functions": [], "interfaces": [ + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ClusterDetails", + "type": "Interface", + "tags": [], + "label": "ClusterDetails", + "description": [], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ClusterDetails.status", + "type": "CompoundType", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "\"running\" | \"failed\" | \"partial\" | \"skipped\" | \"successful\"" + ], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ClusterDetails.indices", + "type": "string", + "tags": [], + "label": "indices", + "description": [], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ClusterDetails.took", + "type": "number", + "tags": [], + "label": "took", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ClusterDetails.timed_out", + "type": "boolean", + "tags": [], + "label": "timed_out", + "description": [], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ClusterDetails._shards", + "type": "Object", + "tags": [], + "label": "_shards", + "description": [], + "signature": [ + "ShardStatistics", + " | undefined" + ], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/es-types", + "id": "def-common.ClusterDetails.failures", + "type": "Array", + "tags": [], + "label": "failures", + "description": [], + "signature": [ + "ShardFailure", + "[] | undefined" + ], + "path": "packages/kbn-es-types/src/search.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-types", "id": "def-common.ESSearchOptions", diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 5e31bfaa121ad..2352686181283 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 12 | 0 | 12 | 0 | +| 19 | 0 | 19 | 0 | ## Common diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index dc6d7d4741330..32d71052df8fc 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: 2023-09-13 +date: 2023-09-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 0580b7ba9cfd2..cae3201e128bd 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: 2023-09-13 +date: 2023-09-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 fd16db558722a..0752b0811d323 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: 2023-09-13 +date: 2023-09-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 ec132a7ca87dd..80c9aeffdbd9a 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: 2023-09-13 +date: 2023-09-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 8e0ef67baf5a6..4e09c58ced8f5 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 5d7f29a0e55eb..4ce16dd124611 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: 2023-09-13 +date: 2023-09-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 ff41b34f565ab..65e8a87535235 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: 2023-09-13 +date: 2023-09-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_generate.mdx b/api_docs/kbn_generate.mdx index 482c6066fece2..f359f8e4a771e 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: 2023-09-13 +date: 2023-09-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 d577c348169ca..04673f56d19be 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: 2023-09-13 +date: 2023-09-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 6f0d7a49bb273..a1b4224659b11 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_generate_csv_types.mdx b/api_docs/kbn_generate_csv_types.mdx index d3b65b32e9eb8..a99265e2edd86 100644 --- a/api_docs/kbn_generate_csv_types.mdx +++ b/api_docs/kbn_generate_csv_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv-types title: "@kbn/generate-csv-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv-types plugin -date: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv-types'] --- import kbnGenerateCsvTypesObj from './kbn_generate_csv_types.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 6f045381a2937..fddefcb51af7f 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: 2023-09-13 +date: 2023-09-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 83c2936d49330..356929fd3e0ac 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: 2023-09-13 +date: 2023-09-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 df3d2a40d9d89..12e6c7829fb27 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: 2023-09-13 +date: 2023-09-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 5b6264973a3f8..7e01b718da2e1 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: 2023-09-13 +date: 2023-09-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 9c2be72f59c22..72269a6ec56ed 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: 2023-09-13 +date: 2023-09-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 f6741ecb0ed6a..429e532650cf3 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: 2023-09-13 +date: 2023-09-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 980f13dd03aac..c9339778f3702 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: 2023-09-13 +date: 2023-09-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 ec3f632afabc2..b530c8fa4d262 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: 2023-09-13 +date: 2023-09-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 6bc9021130a7c..d797007d0de4e 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: 2023-09-13 +date: 2023-09-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 101c3b4da4f6f..20706aa1c89a0 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: 2023-09-13 +date: 2023-09-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 0f4a144df6b34..c2473953e38b5 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: 2023-09-13 +date: 2023-09-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 530eb8d508e45..427bd7473cbb4 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: 2023-09-13 +date: 2023-09-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 6b234c62eb11c..b2fab75c5b6fe 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: 2023-09-13 +date: 2023-09-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 f2a811ec6aa63..3b387eafdd460 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: 2023-09-13 +date: 2023-09-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 485643ab2d9b2..fd351078add26 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: 2023-09-13 +date: 2023-09-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 6c6c91aaea30d..bcc0262ed6cdd 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: 2023-09-13 +date: 2023-09-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 777ae2876d2ba..212e79be42d60 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: 2023-09-13 +date: 2023-09-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 d5b016137948e..558dce5fbfe54 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: 2023-09-13 +date: 2023-09-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_logging.mdx b/api_docs/kbn_logging.mdx index 9406e406bd882..053c26a4307bf 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: 2023-09-13 +date: 2023-09-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 1b70ff4c25a95..76d40f947ec91 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: 2023-09-13 +date: 2023-09-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 147084d2cb7df..bb63414ff725f 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: 2023-09-13 +date: 2023-09-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 972b00f385842..82acf333a7c02 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: 2023-09-13 +date: 2023-09-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_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 559629a02eae2..e964d760e469c 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: 2023-09-13 +date: 2023-09-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 9a012764d458d..0b393875cb7f9 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: 2023-09-13 +date: 2023-09-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_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index 63f3d5df631bf..b40b1317a3e9e 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: 2023-09-13 +date: 2023-09-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.mdx b/api_docs/kbn_management_settings_ids.mdx index c294a94fe7007..0f11e31876047 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index 17370654b494a..995efd2ebfdd8 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: 2023-09-13 +date: 2023-09-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 c8592100f1456..f52054f767fad 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: 2023-09-13 +date: 2023-09-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 31e0ff94a2a40..86cf181e304b8 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: 2023-09-13 +date: 2023-09-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 8364e5c6de53c..4a31b9ecd99c8 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: 2023-09-13 +date: 2023-09-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 f309595582bc4..771d4e179bc63 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: 2023-09-13 +date: 2023-09-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 233ec13546216..6651c5ca93da6 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: 2023-09-13 +date: 2023-09-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 657ff4b8264ad..fa0481f442771 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: 2023-09-13 +date: 2023-09-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 be9336d573cd2..8c93d58113b6c 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: 2023-09-13 +date: 2023-09-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 1a3afc43e56d7..08e34ac4cb6bf 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: 2023-09-13 +date: 2023-09-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_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index c13c54d34121b..5a1f35fac2034 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: 2023-09-13 +date: 2023-09-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 647cb07b3eb64..3db213a28e09d 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: 2023-09-13 +date: 2023-09-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.devdocs.json b/api_docs/kbn_ml_date_picker.devdocs.json index 69aa0e7997284..77ed2b13c1320 100644 --- a/api_docs/kbn_ml_date_picker.devdocs.json +++ b/api_docs/kbn_ml_date_picker.devdocs.json @@ -543,6 +543,22 @@ "path": "x-pack/packages/ml/date_picker/src/hooks/use_date_picker_context.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-date-picker", + "id": "def-common.DatePickerDependencies.isServerless", + "type": "CompoundType", + "tags": [], + "label": "isServerless", + "description": [ + "\nOptional flag to indicate whether kibana is running in serverless" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/ml/date_picker/src/hooks/use_date_picker_context.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -935,6 +951,22 @@ "path": "x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/ml-date-picker", + "id": "def-common.FullTimeRangeSelectorProps.hideFrozenDataTierChoice", + "type": "CompoundType", + "tags": [], + "label": "hideFrozenDataTierChoice", + "description": [ + "\nOptional flag to disable the frozen data tier choice." + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index c6f8376c47a28..e1fe35619a900 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.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 | |-------------------|-----------|------------------------|-----------------| -| 47 | 0 | 0 | 0 | +| 49 | 0 | 0 | 0 | ## Common diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index be18567cbb014..80ed387868e23 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: 2023-09-13 +date: 2023-09-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 726d94891ed72..27375d6774b8a 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: 2023-09-13 +date: 2023-09-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.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 06ab4563359c0..ca2e66bad415a 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index b74d2f40fb222..527658739e1bc 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: 2023-09-13 +date: 2023-09-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 e04b238a09c40..1eabd362da545 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: 2023-09-13 +date: 2023-09-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 3c6e582f76844..58845cc4214d6 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: 2023-09-13 +date: 2023-09-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 863d2d28a4e24..7ef6b5a737e79 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: 2023-09-13 +date: 2023-09-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 03269cb0d0ed3..6d09ae6175d44 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: 2023-09-13 +date: 2023-09-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 0dae3a21c7702..6ec27bd2225a6 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: 2023-09-13 +date: 2023-09-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 381ef607c2a62..a4d839635e783 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: 2023-09-13 +date: 2023-09-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 05c5b586cab36..fa5dc58257f7b 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: 2023-09-13 +date: 2023-09-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 16c8571c874e4..fb4091192c189 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: 2023-09-13 +date: 2023-09-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 57a5df70840ad..e0cacb39f74e5 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: 2023-09-13 +date: 2023-09-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 9dec182d24c48..d73f78e4ebeca 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: 2023-09-13 +date: 2023-09-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 c6a77c39a1a26..37e7aa67e4663 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: 2023-09-13 +date: 2023-09-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_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 0d9473a6f86f5..b7b48fd7d7a67 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: 2023-09-13 +date: 2023-09-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_monaco.mdx b/api_docs/kbn_monaco.mdx index 9e5313ea98c4a..96a986fab3db4 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: 2023-09-13 +date: 2023-09-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 dc9d79bfa9777..696960e379718 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: 2023-09-13 +date: 2023-09-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 56b02aebfb5ea..5dc1eb53b7bb5 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: 2023-09-13 +date: 2023-09-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_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 5380d1d3b8d3a..8e06982e1288b 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: 2023-09-13 +date: 2023-09-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 d010e5fe75378..376572e4cd5c0 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: 2023-09-13 +date: 2023-09-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 7c70442dd6f6b..2a0a1984612e0 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: 2023-09-13 +date: 2023-09-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_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index e581c401d18e4..7115a7f11b212 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: 2023-09-13 +date: 2023-09-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 d6a167647782b..0ec08404ef5d8 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: 2023-09-13 +date: 2023-09-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 1f1a6f95d8d1c..8ff8e347903a2 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: 2023-09-13 +date: 2023-09-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 a864a8f52e917..ea79070706e78 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: 2023-09-13 +date: 2023-09-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 62f75661a564a..6b78c36ec3956 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: 2023-09-13 +date: 2023-09-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 934776daccf4c..8909e7997729e 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: 2023-09-13 +date: 2023-09-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 be5b4d7317203..0faa67ced74f6 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: 2023-09-13 +date: 2023-09-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 47a7840f07b8d..fcc2f7325518e 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: 2023-09-13 +date: 2023-09-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 2284a1ab60842..4512f6811753a 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: 2023-09-13 +date: 2023-09-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 a2b1c5c67e218..dd100457c412a 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: 2023-09-13 +date: 2023-09-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 1a9f28711e615..57ba261d0c59b 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: 2023-09-13 +date: 2023-09-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 32ecfc853ef48..8a9c35b027bb5 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: 2023-09-13 +date: 2023-09-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 da1599e7fc66f..967218a149a68 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: 2023-09-13 +date: 2023-09-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 76950102c2693..b168d1114e099 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: 2023-09-13 +date: 2023-09-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 3decad6e6e1c3..0fc9b66d3c178 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: 2023-09-13 +date: 2023-09-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 3e2c73632a132..3818d2e44fab7 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: 2023-09-13 +date: 2023-09-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 6a2412a96fc1f..31ee38d3e1e0b 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index bd1de89298aa7..f7ddb40758236 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index 679ea275d904d..8bd1b60ad7fc1 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: 2023-09-13 +date: 2023-09-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 6089cf1b5a99a..462f9a9d4940a 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: 2023-09-13 +date: 2023-09-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 f6c4935a70707..0cc0b244f550c 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: 2023-09-13 +date: 2023-09-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 4234000350c4d..69e830a1c7c53 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: 2023-09-13 +date: 2023-09-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 091ec4908a5e1..54d17b6e120b9 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.devdocs.json b/api_docs/kbn_search_response_warnings.devdocs.json index aa22ec9dc5bdb..1ffcdaf144fb1 100644 --- a/api_docs/kbn_search_response_warnings.devdocs.json +++ b/api_docs/kbn_search_response_warnings.devdocs.json @@ -29,7 +29,7 @@ "\nIntercepts warnings for a search source request" ], "signature": [ - "({ services, adapter, options, }: { services: { data: ", + "({ services, adapter, }: { services: { data: ", { "pluginId": "data", "scope": "public", @@ -53,7 +53,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - "; options?: { disableShardFailureWarning?: boolean | undefined; } | undefined; }) => ", + "; }) => ", { "pluginId": "@kbn/search-response-warnings", "scope": "common", @@ -61,7 +61,7 @@ "section": "def-common.SearchResponseInterceptedWarning", "text": "SearchResponseInterceptedWarning" }, - "[] | undefined" + "[]" ], "path": "packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx", "deprecated": false, @@ -72,7 +72,7 @@ "id": "def-common.getSearchResponseInterceptedWarnings.$1", "type": "Object", "tags": [], - "label": "{\n services,\n adapter,\n options,\n}", + "label": "{\n services,\n adapter,\n}", "description": [], "path": "packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx", "deprecated": false, @@ -127,20 +127,6 @@ "path": "packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.getSearchResponseInterceptedWarnings.$1.options", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - "{ disableShardFailureWarning?: boolean | undefined; } | undefined" - ], - "path": "packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx", - "deprecated": false, - "trackAdoption": false } ] } @@ -150,57 +136,46 @@ }, { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.removeInterceptedWarningDuplicates", + "id": "def-common.hasUnsupportedDownsampledAggregationFailure", "type": "Function", "tags": [], - "label": "removeInterceptedWarningDuplicates", - "description": [ - "\nRemoves duplicated warnings" - ], + "label": "hasUnsupportedDownsampledAggregationFailure", + "description": [], "signature": [ - "(interceptedWarnings: ", + "(warning: ", { - "pluginId": "@kbn/search-response-warnings", - "scope": "common", - "docId": "kibKbnSearchResponseWarningsPluginApi", - "section": "def-common.SearchResponseInterceptedWarning", - "text": "SearchResponseInterceptedWarning" - }, - "[] | undefined) => ", - { - "pluginId": "@kbn/search-response-warnings", - "scope": "common", - "docId": "kibKbnSearchResponseWarningsPluginApi", - "section": "def-common.SearchResponseInterceptedWarning", - "text": "SearchResponseInterceptedWarning" + "pluginId": "data", + "scope": "public", + "docId": "kibDataSearchPluginApi", + "section": "def-public.SearchResponseIncompleteWarning", + "text": "SearchResponseIncompleteWarning" }, - "[] | undefined" + ") => boolean" ], - "path": "packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx", + "path": "packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.removeInterceptedWarningDuplicates.$1", - "type": "Array", + "id": "def-common.hasUnsupportedDownsampledAggregationFailure.$1", + "type": "Object", "tags": [], - "label": "interceptedWarnings", + "label": "warning", "description": [], "signature": [ { - "pluginId": "@kbn/search-response-warnings", - "scope": "common", - "docId": "kibKbnSearchResponseWarningsPluginApi", - "section": "def-common.SearchResponseInterceptedWarning", - "text": "SearchResponseInterceptedWarning" - }, - "[] | undefined" + "pluginId": "data", + "scope": "public", + "docId": "kibDataSearchPluginApi", + "section": "def-public.SearchResponseIncompleteWarning", + "text": "SearchResponseIncompleteWarning" + } ], - "path": "packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx", + "path": "packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.ts", "deprecated": false, "trackAdoption": false, - "isRequired": false + "isRequired": true } ], "returnComment": [], @@ -275,14 +250,18 @@ { "parentPluginId": "@kbn/search-response-warnings", "id": "def-common.SearchResponseInterceptedWarning.originalWarning", - "type": "CompoundType", + "type": "Object", "tags": [], "label": "originalWarning", "description": [], "signature": [ - "SearchResponseTimeoutWarning", - " | ", - "SearchResponseShardFailureWarning" + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataSearchPluginApi", + "section": "def-public.SearchResponseIncompleteWarning", + "text": "SearchResponseIncompleteWarning" + } ], "path": "packages/kbn-search-response-warnings/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 6acb8bc0ab314..ed1c2f815ab45 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.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 | |-------------------|-----------|------------------------|-----------------| -| 16 | 0 | 8 | 0 | +| 15 | 0 | 8 | 0 | ## Common diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index a50f73e7ca604..b0c93a114d9d2 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: 2023-09-13 +date: 2023-09-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 265af90e0d81a..823aa28ad5d0e 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: 2023-09-13 +date: 2023-09-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 90a55a8147350..b6e4b1aff688d 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: 2023-09-13 +date: 2023-09-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 349822c41dd04..f960e16fdfd4f 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: 2023-09-13 +date: 2023-09-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 676bd50193170..2dcd449f30d2f 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: 2023-09-13 +date: 2023-09-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 45cea3ee8386b..172891831be08 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: 2023-09-13 +date: 2023-09-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 425802eee52dc..63fe52faaf53b 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: 2023-09-13 +date: 2023-09-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 f401066e69335..1ce01f667fe3f 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: 2023-09-13 +date: 2023-09-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 7666acc49edef..9e50cf6ec8c46 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: 2023-09-13 +date: 2023-09-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 c0d0505a3c8ad..ee81577030937 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: 2023-09-13 +date: 2023-09-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 47686702540aa..7989a3a2e2ea5 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: 2023-09-13 +date: 2023-09-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 6c3fa9690485a..2093a355cf1cb 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: 2023-09-13 +date: 2023-09-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 c88f5a634e9d7..94ec599ca69a4 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: 2023-09-13 +date: 2023-09-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 fbd9cea5e3ccd..6fdbd00d7f952 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: 2023-09-13 +date: 2023-09-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 2e40e7c12c181..2fd55f6520a60 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: 2023-09-13 +date: 2023-09-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 e542cc8df8dac..be1f04af331fb 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: 2023-09-13 +date: 2023-09-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 05eb8cc077765..b46e96a15f130 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: 2023-09-13 +date: 2023-09-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 c38ace33dbbc1..2a2ab033357a1 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: 2023-09-13 +date: 2023-09-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 d1acab8a34fd8..f52f4d5908dd8 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: 2023-09-13 +date: 2023-09-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 d8e7c5a7d078f..b6e894e12919a 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: 2023-09-13 +date: 2023-09-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 1bc4ef4d225e4..e95471efb1e05 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: 2023-09-13 +date: 2023-09-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 69ec92ff8e812..6c025bc87f228 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: 2023-09-13 +date: 2023-09-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 d172148a6b99c..85daecd0ae440 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: 2023-09-13 +date: 2023-09-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 04c06dd1c5630..0c4d9204518f0 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: 2023-09-13 +date: 2023-09-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 ee878f57220cc..46d3c19300dc7 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: 2023-09-13 +date: 2023-09-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 02c5606b0aa82..86594926c8f2e 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: 2023-09-13 +date: 2023-09-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 0844f0e999d77..0d44ac9134cc4 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: 2023-09-13 +date: 2023-09-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 575c3a99a7c68..96052a104eacf 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: 2023-09-13 +date: 2023-09-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 9961dbdbed79f..a8e59c62ab10d 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: 2023-09-13 +date: 2023-09-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 29344ddbe1e98..a5e341b9e1686 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: 2023-09-13 +date: 2023-09-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 2d8ba2d0494b8..797bcb8644378 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: 2023-09-13 +date: 2023-09-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 96c052166a38b..cef03d317406a 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: 2023-09-13 +date: 2023-09-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_avatar_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index a7c0873016a7e..0985e7b0153d4 100644 --- a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx +++ b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-user-profile-components title: "@kbn/shared-ux-avatar-user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-user-profile-components plugin -date: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-user-profile-components'] --- import kbnSharedUxAvatarUserProfileComponentsObj from './kbn_shared_ux_avatar_user_profile_components.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 5e4e0be470993..9a3252304d6a8 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: 2023-09-13 +date: 2023-09-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_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index a9da1a6e22917..97c0157e6340e 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index f5826bcf9adda..ae17e880a7383 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 2c583dc3e77ac..a32edc47c6eeb 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: 2023-09-13 +date: 2023-09-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 860e878a2a25c..1b74e5c12a283 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: 2023-09-13 +date: 2023-09-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 65ec1953880ad..f8a14ffdb24b4 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: 2023-09-13 +date: 2023-09-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_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 3d5ebbcc325ef..60067d38b3248 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: 2023-09-13 +date: 2023-09-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 05df1e3c48d61..29bfe4d7ff763 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: 2023-09-13 +date: 2023-09-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 170065a54c9f7..700acd34dd5ac 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: 2023-09-13 +date: 2023-09-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 2c46fdac34a17..baf5da5ae4e13 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: 2023-09-13 +date: 2023-09-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 2a6fd8a8efa67..8d6ac84ba4ee8 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: 2023-09-13 +date: 2023-09-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 2a06b6994f5d1..388dfc4029301 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: 2023-09-13 +date: 2023-09-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 270775d965ea4..907141e7d18a7 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: 2023-09-13 +date: 2023-09-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 aa952107aa3c7..c82cab2a0baf6 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: 2023-09-13 +date: 2023-09-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 0ceccc88c158b..79576558e9024 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: 2023-09-13 +date: 2023-09-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 85f28f39af24e..08399dfcbbf2e 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: 2023-09-13 +date: 2023-09-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 460ee093f305b..60750596e3eeb 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: 2023-09-13 +date: 2023-09-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 7cab462394e11..f47dcd50dd7e0 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: 2023-09-13 +date: 2023-09-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 e95b52c7c244f..88f4771dbac9c 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: 2023-09-13 +date: 2023-09-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 8c3fb6850cb95..ef47723385917 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: 2023-09-13 +date: 2023-09-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 eb426bcaba79e..0a91ba0779efc 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: 2023-09-13 +date: 2023-09-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 49c8f063f8e85..e7b74af2464e5 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: 2023-09-13 +date: 2023-09-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 48326fcb14531..bd5372d8631e4 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: 2023-09-13 +date: 2023-09-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 20246a63b2fda..dcc81bdf26e9e 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: 2023-09-13 +date: 2023-09-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 f7e47aceaa5d8..79b2397ae0745 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: 2023-09-13 +date: 2023-09-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 b4f83099a82e3..cf272cd25934a 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: 2023-09-13 +date: 2023-09-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 c97a83e2a4f7c..69b01749996ef 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: 2023-09-13 +date: 2023-09-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 e1defde765930..aee27375fc406 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: 2023-09-13 +date: 2023-09-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 e283143b1c9e6..cfd8a3949ba8e 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: 2023-09-13 +date: 2023-09-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 cd1ed4e1ae3c6..c3e948cbcfa39 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: 2023-09-13 +date: 2023-09-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 6ce1356fa6531..2bfba679e0eaa 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: 2023-09-13 +date: 2023-09-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 58f84c6c6b8a5..74d5e079ab07f 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: 2023-09-13 +date: 2023-09-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 426ee9804e6bd..63c322c12a253 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: 2023-09-13 +date: 2023-09-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 a40d398aa75e2..d5fed6437cbc2 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: 2023-09-13 +date: 2023-09-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 74e0173895b61..1966b91893a5a 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: 2023-09-13 +date: 2023-09-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 e2098bf0cff02..dbf9c41428ad3 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: 2023-09-13 +date: 2023-09-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 e9ff3a531ff1b..342c9f00ba9e8 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: 2023-09-13 +date: 2023-09-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 8bd2a0a66f841..cab0323602063 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: 2023-09-13 +date: 2023-09-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 79e5777d0b021..40b380b764b2f 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: 2023-09-13 +date: 2023-09-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 7ae5e6ab1827e..2c267b7b8fb79 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: 2023-09-13 +date: 2023-09-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 4cf9de783e1cb..a6e1b7b62c80c 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: 2023-09-13 +date: 2023-09-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 29e0fe389034a..e4fa4d265c566 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: 2023-09-13 +date: 2023-09-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 953065aae5fe0..becb2e0b2eff4 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: 2023-09-13 +date: 2023-09-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 bc1f0cceeae58..dc20c46ab6381 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 7afa74db5d8da..c9e08501e18fe 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: 2023-09-13 +date: 2023-09-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 46134be6ad400..db084142473ff 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: 2023-09-13 +date: 2023-09-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 e7e110038a130..bcf1bc196f5aa 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: 2023-09-13 +date: 2023-09-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 2a80fe3482872..00ea8cf4185c8 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 14dc50ec51bf4..cfe496da550cf 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: 2023-09-13 +date: 2023-09-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 a62c7030a00d2..d858f1e3b52af 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: 2023-09-13 +date: 2023-09-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 7e28e9a4d322b..104cbe4ef7b69 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: 2023-09-13 +date: 2023-09-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 9f5852794430a..1e9c6c17f5344 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: 2023-09-13 +date: 2023-09-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 a43a72a165881..e11259d50a623 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: 2023-09-13 +date: 2023-09-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 2f7a28bcca9ac..7cba5280d6cff 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: 2023-09-13 +date: 2023-09-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 fb88b69a01b1c..82ab23dfaaa66 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: 2023-09-13 +date: 2023-09-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.mdx b/api_docs/kbn_unified_field_list.mdx index 257f9d38d9e90..842a6cc725906 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index f96bf45a0263b..f3bd5b991941a 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: 2023-09-13 +date: 2023-09-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 3f6ef80b04d09..6031a92c8643b 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: 2023-09-13 +date: 2023-09-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 e2494c484925a..9b12d7af3bd74 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: 2023-09-13 +date: 2023-09-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 62eb2672f9c27..bec96b10007d8 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: 2023-09-13 +date: 2023-09-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 0378171610dcb..b56f7235cdcbc 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: 2023-09-13 +date: 2023-09-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 141f78735f1b5..93151c9662d9a 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: 2023-09-13 +date: 2023-09-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 275fee7af2303..3b9a7d06e1ae9 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: 2023-09-13 +date: 2023-09-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_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 7ff4e23d1da27..90c4135b919e7 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: 2023-09-13 +date: 2023-09-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 bffee930c8051..e8cdfe66d5af5 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index a68c974f1d405..d49597e09e76f 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.devdocs.json b/api_docs/kibana_react.devdocs.json index 242e917a38c35..de4ee43837b29 100644 --- a/api_docs/kibana_react.devdocs.json +++ b/api_docs/kibana_react.devdocs.json @@ -3080,11 +3080,11 @@ }, { "plugin": "data", - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.tsx" + "path": "src/plugins/data/public/incomplete_results_modal/open_incomplete_results_modal_button.tsx" }, { "plugin": "data", - "path": "src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.tsx" + "path": "src/plugins/data/public/incomplete_results_modal/open_incomplete_results_modal_button.tsx" }, { "plugin": "data", @@ -3844,11 +3844,11 @@ }, { "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx" + "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx" }, { "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx" + "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx" }, { "plugin": "synthetics", @@ -3856,11 +3856,11 @@ }, { "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx" + "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx" }, { "plugin": "synthetics", - "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/browser_test_results.tsx" + "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/delete_monitor.tsx" }, { "plugin": "synthetics", diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 5e89af9eabac7..57ec6558ef9de 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: 2023-09-13 +date: 2023-09-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 b7f26f3ec2903..65e31b8bb1845 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: 2023-09-13 +date: 2023-09-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 5b0c16a73152b..6de2dd85e2693 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: 2023-09-13 +date: 2023-09-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 8688b219874c8..94b49228010cf 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: 2023-09-13 +date: 2023-09-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 e2877b9552ceb..bf1137695d04a 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: 2023-09-13 +date: 2023-09-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 b6e081cc6a736..d8ab2586b8f33 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: 2023-09-13 +date: 2023-09-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 451cd31cd5996..817c22a4cd368 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 32f3640893098..ffc40f1e32099 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: 2023-09-13 +date: 2023-09-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 a3c52e411f77a..c1cbaa7345fe3 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: 2023-09-13 +date: 2023-09-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 25409f679ad5f..d60da68b5eafe 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: 2023-09-13 +date: 2023-09-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 8ccfceeddf4e6..dfecf89a79bfe 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.devdocs.json b/api_docs/maps.devdocs.json index e732667d42150..2912fb874ff47 100644 --- a/api_docs/maps.devdocs.json +++ b/api_docs/maps.devdocs.json @@ -3095,54 +3095,6 @@ ], "returnComment": [] }, - { - "parentPluginId": "maps", - "id": "def-public.IVectorSource.createField", - "type": "Function", - "tags": [], - "label": "createField", - "description": [], - "signature": [ - "({ fieldName }: { fieldName: string; }) => ", - { - "pluginId": "maps", - "scope": "public", - "docId": "kibMapsPluginApi", - "section": "def-public.IField", - "text": "IField" - } - ], - "path": "x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "maps", - "id": "def-public.IVectorSource.createField.$1", - "type": "Object", - "tags": [], - "label": "{ fieldName }", - "description": [], - "path": "x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "maps", - "id": "def-public.IVectorSource.createField.$1.fieldName", - "type": "string", - "tags": [], - "label": "fieldName", - "description": [], - "path": "x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] - }, { "parentPluginId": "maps", "id": "def-public.IVectorSource.hasTooltipProperties", diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index faa9c48aa838a..f198e8f06fb79 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 262 | 0 | 261 | 28 | +| 259 | 0 | 258 | 28 | ## Client diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 2289ee7785b59..bc5124531256e 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.devdocs.json b/api_docs/metrics_data_access.devdocs.json new file mode 100644 index 0000000000000..ed498fd981e05 --- /dev/null +++ b/api_docs/metrics_data_access.devdocs.json @@ -0,0 +1,319 @@ +{ + "id": "metricsDataAccess", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataClient", + "type": "Class", + "tags": [], + "label": "MetricsDataClient", + "description": [], + "path": "x-pack/plugins/metrics_data_access/server/client/client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataClient.getMetricIndices", + "type": "Function", + "tags": [], + "label": "getMetricIndices", + "description": [], + "signature": [ + "(options: ", + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.GetMetricIndicesOptions", + "text": "GetMetricIndicesOptions" + }, + ") => Promise" + ], + "path": "x-pack/plugins/metrics_data_access/server/client/client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataClient.getMetricIndices.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.GetMetricIndicesOptions", + "text": "GetMetricIndicesOptions" + } + ], + "path": "x-pack/plugins/metrics_data_access/server/client/client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataClient.updateMetricIndices", + "type": "Function", + "tags": [], + "label": "updateMetricIndices", + "description": [], + "signature": [ + "(options: ", + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.UpdateMetricIndicesOptions", + "text": "UpdateMetricIndicesOptions" + }, + ") => Promise<", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObject", + "text": "SavedObject" + }, + "<{ metricIndices: string; }>>" + ], + "path": "x-pack/plugins/metrics_data_access/server/client/client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataClient.updateMetricIndices.$1", + "type": "CompoundType", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.UpdateMetricIndicesOptions", + "text": "UpdateMetricIndicesOptions" + } + ], + "path": "x-pack/plugins/metrics_data_access/server/client/client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataClient.setDefaultMetricIndicesHandler", + "type": "Function", + "tags": [], + "label": "setDefaultMetricIndicesHandler", + "description": [], + "signature": [ + "(handler: ", + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.DefaultMetricIndicesHandler", + "text": "DefaultMetricIndicesHandler" + }, + ") => void" + ], + "path": "x-pack/plugins/metrics_data_access/server/client/client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataClient.setDefaultMetricIndicesHandler.$1", + "type": "CompoundType", + "tags": [], + "label": "handler", + "description": [], + "signature": [ + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.DefaultMetricIndicesHandler", + "text": "DefaultMetricIndicesHandler" + } + ], + "path": "x-pack/plugins/metrics_data_access/server/client/client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [], + "interfaces": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.GetMetricIndicesOptions", + "type": "Interface", + "tags": [], + "label": "GetMetricIndicesOptions", + "description": [], + "path": "x-pack/plugins/metrics_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.GetMetricIndicesOptions.savedObjectsClient", + "type": "Object", + "tags": [], + "label": "savedObjectsClient", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-common.SavedObjectsClientContract", + "text": "SavedObjectsClientContract" + } + ], + "path": "x-pack/plugins/metrics_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.DefaultMetricIndicesHandler", + "type": "Type", + "tags": [], + "label": "DefaultMetricIndicesHandler", + "description": [], + "signature": [ + "((options: ", + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.GetMetricIndicesOptions", + "text": "GetMetricIndicesOptions" + }, + ") => Promise) | null" + ], + "path": "x-pack/plugins/metrics_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.metricsDataSourceSavedObjectName", + "type": "string", + "tags": [], + "label": "metricsDataSourceSavedObjectName", + "description": [], + "signature": [ + "\"metrics-data-source\"" + ], + "path": "x-pack/plugins/metrics_data_access/server/saved_objects/metrics_data_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.UpdateMetricIndicesOptions", + "type": "Type", + "tags": [], + "label": "UpdateMetricIndicesOptions", + "description": [], + "signature": [ + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.GetMetricIndicesOptions", + "text": "GetMetricIndicesOptions" + }, + " & { metricIndices: string; }" + ], + "path": "x-pack/plugins/metrics_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [], + "setup": { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataPluginSetup", + "type": "Interface", + "tags": [], + "label": "MetricsDataPluginSetup", + "description": [], + "path": "x-pack/plugins/metrics_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "metricsDataAccess", + "id": "def-server.MetricsDataPluginSetup.client", + "type": "Object", + "tags": [], + "label": "client", + "description": [], + "signature": [ + { + "pluginId": "metricsDataAccess", + "scope": "server", + "docId": "kibMetricsDataAccessPluginApi", + "section": "def-server.MetricsDataClient", + "text": "MetricsDataClient" + } + ], + "path": "x-pack/plugins/metrics_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "lifecycle": "setup", + "initialIsOpen": true + } + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx new file mode 100644 index 0000000000000..cb2b523a3a856 --- /dev/null +++ b/api_docs/metrics_data_access.mdx @@ -0,0 +1,39 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibMetricsDataAccessPluginApi +slug: /kibana-dev-docs/api/metricsDataAccess +title: "metricsDataAccess" +image: https://source.unsplash.com/400x175/?github +description: API docs for the metricsDataAccess plugin +date: 2023-09-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] +--- +import metricsDataAccessObj from './metrics_data_access.devdocs.json'; + +Exposes utilities for accessing metrics data + +Contact [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 14 | 0 | 14 | 0 | + +## Server + +### Setup + + +### Classes + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 5e1771d3df8bd..35f9ab7fcc61b 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index c825cb956660b..de2e8f924b102 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: 2023-09-13 +date: 2023-09-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 37d9d39cbf00e..560c13b59b125 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: 2023-09-13 +date: 2023-09-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 4480c9f083529..1f5a9474a2797 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: 2023-09-13 +date: 2023-09-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 2d7b01467c5db..bd52005bad914 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: 2023-09-13 +date: 2023-09-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 d2c175ae44c3d..883d864519811 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: 2023-09-13 +date: 2023-09-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 b48fefcb206e6..de13ef2fa03fb 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 2489775b841ae..bb1d1f6f01202 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index f27a9bd1cfe11..c21954570cb51 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_onboarding.devdocs.json b/api_docs/observability_onboarding.devdocs.json index 8cc4b9736bf0f..8a5eae27e9a29 100644 --- a/api_docs/observability_onboarding.devdocs.json +++ b/api_docs/observability_onboarding.devdocs.json @@ -119,6 +119,53 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "observabilityOnboarding", + "id": "def-public.ObservabilityOnboardingLocatorParams", + "type": "Interface", + "tags": [], + "label": "ObservabilityOnboardingLocatorParams", + "description": [], + "signature": [ + { + "pluginId": "observabilityOnboarding", + "scope": "public", + "docId": "kibObservabilityOnboardingPluginApi", + "section": "def-public.ObservabilityOnboardingLocatorParams", + "text": "ObservabilityOnboardingLocatorParams" + }, + " extends ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.SerializableRecord", + "text": "SerializableRecord" + } + ], + "path": "x-pack/plugins/observability_onboarding/public/locators/onboarding_locator/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observabilityOnboarding", + "id": "def-public.ObservabilityOnboardingLocatorParams.source", + "type": "CompoundType", + "tags": [], + "label": "source", + "description": [ + "If given, it will load the given map else will load the create a new map page." + ], + "signature": [ + "\"customLogs\" | \"systemLogs\" | undefined" + ], + "path": "x-pack/plugins/observability_onboarding/public/locators/onboarding_locator/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false } ], "enums": [], diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 35fa1d82dc54b..6fc01593e875e 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) for ques | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 15 | 0 | 15 | 0 | +| 17 | 0 | 16 | 0 | ## Client diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 1fa1a145ce13f..829614bf91064 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: 2023-09-13 +date: 2023-09-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 88c1929639562..27ebf2c6f647b 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: 2023-09-13 +date: 2023-09-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 ec3b948caf653..8ff5523cb5a58 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: 2023-09-13 +date: 2023-09-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 6b709b1457498..7f126f7856295 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: 2023-09-13 +date: 2023-09-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 | |--------------|----------|------------------------| -| 688 | 579 | 43 | +| 689 | 580 | 43 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 74788 | 223 | 63851 | 1530 | +| 74825 | 223 | 63875 | 1528 | ## Plugin Directory @@ -29,7 +29,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] |--------------|----------------|-----------|--------------|----------|---------------|--------| | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 269 | 0 | 263 | 31 | | | [@elastic/appex-sharedux @elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 17 | 1 | 15 | 2 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 61 | 1 | 3 | 1 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 66 | 1 | 4 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 793 | 1 | 762 | 49 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 29 | 0 | 29 | 119 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 9 | 0 | 9 | 0 | @@ -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 | 101 | 0 | 98 | 9 | | | [@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. | 3311 | 33 | 2584 | 26 | +| | [@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. | 3308 | 33 | 2577 | 24 | | | [@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 | 16 | 0 | 7 | 0 | | | [@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 | @@ -107,7 +107,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 3 | 0 | 3 | 1 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 194 | 0 | 189 | 4 | -| | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 45 | 0 | 42 | 11 | +| | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 42 | 0 | 39 | 11 | | ingestPipelines | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | inputControlVis | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 123 | 2 | 96 | 4 | @@ -126,8 +126,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | Exposes the shared components and APIs to access and visualize logs. | 269 | 10 | 256 | 27 | | logstash | [@elastic/logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 47 | 0 | 47 | 7 | -| | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 262 | 0 | 261 | 28 | +| | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 259 | 0 | 258 | 28 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 67 | 0 | 67 | 0 | +| | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | Exposes utilities for accessing metrics data | 14 | 0 | 14 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 150 | 3 | 64 | 32 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | - | 15 | 3 | 13 | 1 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | - | 9 | 0 | 9 | 0 | @@ -138,7 +139,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 543 | 2 | 534 | 14 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 42 | 0 | 39 | 7 | | observabilityLogExplorer | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin exposes and registers observability log consumption features. | 0 | 0 | 0 | 0 | -| | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 15 | 0 | 15 | 0 | +| | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 17 | 0 | 16 | 0 | | | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 281 | 1 | 279 | 11 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 24 | 0 | 24 | 7 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 2 | 0 | 2 | 0 | @@ -169,7 +170,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 134 | 0 | 134 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds URL Service and sharing capabilities to Kibana | 119 | 0 | 60 | 10 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 22 | 1 | 22 | 1 | -| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 253 | 0 | 65 | 0 | +| | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 256 | 0 | 65 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 24 | 0 | 24 | 3 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 4 | 0 | 4 | 1 | | synthetics | [@elastic/uptime](https://github.com/orgs/elastic/teams/uptime) | This plugin visualizes data from Synthetics and Heartbeat, and integrates with other Observability solutions. | 0 | 0 | 0 | 0 | @@ -208,7 +209,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Registers the vega visualization. Is the elastic version of vega and vega-lite libraries. | 2 | 0 | 2 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the vislib visualizations. These are the classical area/line/bar, gauge/goal and heatmap charts. We want to replace them with elastic-charts. | 1 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the new xy-axis chart using the elastic-charts library, which will eventually replace the vislib xy-axis charts including bar, area, and line. | 52 | 0 | 50 | 5 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 823 | 12 | 793 | 19 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 837 | 12 | 807 | 19 | | watcher | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | ## Package Directory @@ -441,7 +442,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 27 | 0 | 14 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 3 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 259 | 1 | 199 | 15 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 12 | 0 | 12 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 19 | 0 | 19 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 39 | 0 | 39 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 65 | 0 | 65 | 1 | @@ -490,7 +491,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 37 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 152 | 1 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 141 | 0 | 5 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 47 | 0 | 0 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 49 | 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 | @@ -536,7 +537,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 68 | 0 | 68 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 1678 | 0 | 1678 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 16 | 0 | 8 | 0 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 15 | 0 | 8 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 14 | 0 | 14 | 6 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 50 | 0 | 47 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 29 | 0 | 23 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index e4ff920b0c8d6..6cc7380f2ec08 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: 2023-09-13 +date: 2023-09-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 6a6a990f614b1..50f3f5623ff0c 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: 2023-09-13 +date: 2023-09-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 79326ba432d7a..0fca245710a1f 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: 2023-09-13 +date: 2023-09-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 ccc7a2726c35c..07861cdaab4af 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: 2023-09-13 +date: 2023-09-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 4b22ef69d9458..550604e1f92d4 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: 2023-09-13 +date: 2023-09-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 9dc448dc57502..05186b3837ec3 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: 2023-09-13 +date: 2023-09-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 41d6c0a704b8f..b78ee68addedc 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: 2023-09-13 +date: 2023-09-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 43cec5adfb93a..d546a0fcbfe5c 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: 2023-09-13 +date: 2023-09-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 f2276867e82bf..1289b8082f15c 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: 2023-09-13 +date: 2023-09-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 f0749afca0cb3..81be3ed82e94d 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: 2023-09-13 +date: 2023-09-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 3a6386cb22f4e..a9d1c9de75842 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: 2023-09-13 +date: 2023-09-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 245d1d7032fd6..6f90cd670eb91 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: 2023-09-13 +date: 2023-09-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 4bae1c0a95f03..0cf3153c21f52 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: 2023-09-13 +date: 2023-09-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 129b5871103ee..a1fafc0d9e600 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: 2023-09-13 +date: 2023-09-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 8ecfc548b34a4..e0be883a82619 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: 2023-09-13 +date: 2023-09-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 786531b718120..0b6812e03161c 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: 2023-09-13 +date: 2023-09-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 6e2e6e30e7ea1..a0e5f3958528d 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index fd1c2715fd1f6..aa482454e241f 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: 2023-09-13 +date: 2023-09-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 ed5161597c071..56d20bd218a1d 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: 2023-09-13 +date: 2023-09-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 64c8cd2aeaa93..449cec5c99f47 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: 2023-09-13 +date: 2023-09-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 98e11bb21c91c..b7690903dcb37 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: 2023-09-13 +date: 2023-09-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 bc210ab3c6ce9..58fee5b981a9a 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: 2023-09-13 +date: 2023-09-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 19608208fd71b..eb69dc2ee18dd 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: 2023-09-13 +date: 2023-09-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 295391e8a034b..53cffa4d8addc 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: 2023-09-13 +date: 2023-09-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 791df54b06f27..7f1e3c24847e7 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: 2023-09-13 +date: 2023-09-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 e74f26d598679..bd2066e176725 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.devdocs.json b/api_docs/spaces.devdocs.json index 8ce91315daa63..2b4ff0b4dd02d 100644 --- a/api_docs/spaces.devdocs.json +++ b/api_docs/spaces.devdocs.json @@ -2832,7 +2832,7 @@ "\nSetup contract for the Spaces plugin." ], "signature": [ - "{}" + "{ hasOnlyDefaultSpace: boolean; }" ], "path": "x-pack/plugins/spaces/public/plugin.tsx", "deprecated": false, @@ -2907,6 +2907,19 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "spaces", + "id": "def-public.SpacesApi.hasOnlyDefaultSpace", + "type": "boolean", + "tags": [], + "label": "hasOnlyDefaultSpace", + "description": [ + "\nDetermines whether Kibana supports multiple spaces or only the default space.\n\nWhen `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden." + ], + "path": "x-pack/plugins/spaces/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "spaces", "id": "def-public.SpacesApi.ui", @@ -4359,6 +4372,23 @@ "path": "x-pack/plugins/spaces/server/plugin.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "spaces", + "id": "def-server.SpacesPluginSetup.hasOnlyDefaultSpace$", + "type": "Object", + "tags": [], + "label": "hasOnlyDefaultSpace$", + "description": [ + "\nDetermines whether Kibana supports multiple spaces or only the default space.\n\nWhen `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden." + ], + "signature": [ + "Observable", + "" + ], + "path": "x-pack/plugins/spaces/server/plugin.ts", + "deprecated": false, + "trackAdoption": false } ], "lifecycle": "setup", @@ -4398,6 +4428,23 @@ "path": "x-pack/plugins/spaces/server/plugin.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "spaces", + "id": "def-server.SpacesPluginStart.hasOnlyDefaultSpace$", + "type": "Object", + "tags": [], + "label": "hasOnlyDefaultSpace$", + "description": [ + "\nDetermines whether Kibana supports multiple spaces or only the default space.\n\nWhen `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden." + ], + "signature": [ + "Observable", + "" + ], + "path": "x-pack/plugins/spaces/server/plugin.ts", + "deprecated": false, + "trackAdoption": false } ], "lifecycle": "start", diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 5f971d4f8c9e4..bfa5a722cbe4d 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 253 | 0 | 65 | 0 | +| 256 | 0 | 65 | 0 | ## Client diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 6cc3dec6ffe10..90e6d6601053f 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: 2023-09-13 +date: 2023-09-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 6fe4521717e3f..168bfd57d3ee0 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: 2023-09-13 +date: 2023-09-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 888da9894e207..445ca35f47bac 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: 2023-09-13 +date: 2023-09-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 1642f2fb8d7df..0c2df964763bf 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: 2023-09-13 +date: 2023-09-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 d86425638a738..990f3387c15e6 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: 2023-09-13 +date: 2023-09-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 acb98267b441b..dede2c68c8e54 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: 2023-09-13 +date: 2023-09-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 af8357713f14c..0536c71dec572 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: 2023-09-13 +date: 2023-09-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 167bf0fd570c2..db66b02453219 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: 2023-09-13 +date: 2023-09-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 26cd5c79d1dc5..10ab57a2aae1e 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.devdocs.json b/api_docs/timelines.devdocs.json index a6c77777588d2..631be6552c1cb 100644 --- a/api_docs/timelines.devdocs.json +++ b/api_docs/timelines.devdocs.json @@ -4725,6 +4725,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/components/drag_and_drop/drag_drop_context_wrapper.tsx" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/flyout/shared/hooks/use_event_details.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/flyout/shared/hooks/use_event_details.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/flyout/right/context.tsx" diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index c2fbff2affc30..daa142d2f5a98 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: 2023-09-13 +date: 2023-09-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 92cb909761fa4..aab4cc3ca3b84 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: 2023-09-13 +date: 2023-09-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 e8d467d363418..056cec5992083 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: 2023-09-13 +date: 2023-09-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 62661096c057c..827c0b3e6ad9c 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: 2023-09-13 +date: 2023-09-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 482d62bbf6f76..2bbf550db6304 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: 2023-09-13 +date: 2023-09-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 fd4de8afb7c49..1ef1858c6d3b6 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: 2023-09-13 +date: 2023-09-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 afa74e73e7990..4288127fabc2b 100644 --- a/api_docs/unified_histogram.devdocs.json +++ b/api_docs/unified_histogram.devdocs.json @@ -466,7 +466,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - " | undefined; } & Pick<", + " | undefined; isChartLoading?: boolean | undefined; } & Pick<", "UnifiedHistogramLayoutProps", ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"resizeRef\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\"> & React.RefAttributes<", { @@ -1176,7 +1176,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - " | undefined; } & Pick<", + " | undefined; isChartLoading?: boolean | undefined; } & Pick<", "UnifiedHistogramLayoutProps", ", \"children\" | \"className\" | \"query\" | \"filters\" | \"columns\" | \"onBrushEnd\" | \"disabledActions\" | \"timeRange\" | \"services\" | \"dataView\" | \"relativeTimeRange\" | \"resizeRef\" | \"appendHitsCounter\" | \"onFilter\" | \"withDefaultActions\">" ], diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 7357d15dcff9d..da803dcd3ebcd 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: 2023-09-13 +date: 2023-09-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 20509874fc91c..d59ecfad68141 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: 2023-09-13 +date: 2023-09-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 c17109be851c7..55e54f1cc260d 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: 2023-09-13 +date: 2023-09-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 7dfeea17d0844..17e4d25bdd873 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: 2023-09-13 +date: 2023-09-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 00b55be3b9d36..c28952cd54fea 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: 2023-09-13 +date: 2023-09-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 24f9bd750a5bf..9860d9ed2ff23 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: 2023-09-13 +date: 2023-09-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 6389bb834a1af..9d06563a6ec9e 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: 2023-09-13 +date: 2023-09-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 b277a26fa2f95..69c5eadc53b07 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: 2023-09-13 +date: 2023-09-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 5feee7e62166c..5d317162ac2fa 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: 2023-09-13 +date: 2023-09-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 a0a65e0ff8b6c..9bd200893416f 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: 2023-09-13 +date: 2023-09-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 f635d9b5fcab3..6554613743fa6 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: 2023-09-13 +date: 2023-09-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 c74d6003d6b76..54fd8cdc5d6b5 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: 2023-09-13 +date: 2023-09-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 bc0bbc7d21c85..ce5461037ebd1 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: 2023-09-13 +date: 2023-09-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 7dc780b576f66..18826619ca39c 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: 2023-09-13 +date: 2023-09-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 b5fe2abb212ff..2ee902d8111c8 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: 2023-09-13 +date: 2023-09-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 a2d355e89a5d3..9e1d6f7a4f8ad 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: 2023-09-13 +date: 2023-09-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 f924d3a80161e..2b00479a62f29 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index 5b78f2be3fd99..af70fceb72ac9 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -3352,6 +3352,34 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "visualizations", + "id": "def-public.SerializableAttributes", + "type": "Interface", + "tags": [], + "label": "SerializableAttributes", + "description": [], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.SerializableAttributes.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[key: string]: unknown", + "description": [], + "signature": [ + "[key: string]: unknown" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "visualizations", "id": "def-public.SerializedVis", @@ -5518,6 +5546,323 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient", + "type": "Interface", + "tags": [], + "label": "VisualizationClient", + "description": [], + "signature": [ + { + "pluginId": "visualizations", + "scope": "public", + "docId": "kibVisualizationsPluginApi", + "section": "def-public.VisualizationClient", + "text": "VisualizationClient" + }, + "" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [], + "signature": [ + "(id: string) => Promise<{ item: ", + { + "pluginId": "@kbn/content-management-utils", + "scope": "common", + "docId": "kibKbnContentManagementUtilsPluginApi", + "section": "def-common.SOWithMetadata", + "text": "SOWithMetadata" + }, + "; meta: { outcome: \"conflict\" | \"exactMatch\" | \"aliasMatch\"; aliasTargetId?: string | undefined; aliasPurpose?: \"savedObjectConversion\" | \"savedObjectImport\" | undefined; }; }>" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.get.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "(visualization: Omit<", + { + "pluginId": "contentManagement", + "scope": "common", + "docId": "kibContentManagementPluginApi", + "section": "def-common.CreateIn", + "text": "CreateIn" + }, + ">, \"contentTypeId\">) => Promise<{ item: ", + { + "pluginId": "@kbn/content-management-utils", + "scope": "common", + "docId": "kibKbnContentManagementUtilsPluginApi", + "section": "def-common.SOWithMetadata", + "text": "SOWithMetadata" + }, + "; }>" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.create.$1", + "type": "Object", + "tags": [], + "label": "visualization", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "contentManagement", + "scope": "common", + "docId": "kibContentManagementPluginApi", + "section": "def-common.CreateIn", + "text": "CreateIn" + }, + ">, \"contentTypeId\">" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.update", + "type": "Function", + "tags": [], + "label": "update", + "description": [], + "signature": [ + "(visualization: Omit<", + { + "pluginId": "contentManagement", + "scope": "common", + "docId": "kibContentManagementPluginApi", + "section": "def-common.UpdateIn", + "text": "UpdateIn" + }, + ", Pick<", + { + "pluginId": "@kbn/content-management-utils", + "scope": "common", + "docId": "kibKbnContentManagementUtilsPluginApi", + "section": "def-common.SavedObjectUpdateOptions", + "text": "SavedObjectUpdateOptions" + }, + ", \"references\">>, \"contentTypeId\">) => Promise<{ item: ", + { + "pluginId": "@kbn/content-management-utils", + "scope": "common", + "docId": "kibKbnContentManagementUtilsPluginApi", + "section": "def-common.SOWithMetadataPartial", + "text": "SOWithMetadataPartial" + }, + "; }>" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.update.$1", + "type": "Object", + "tags": [], + "label": "visualization", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "contentManagement", + "scope": "common", + "docId": "kibContentManagementPluginApi", + "section": "def-common.UpdateIn", + "text": "UpdateIn" + }, + ", Pick<", + { + "pluginId": "@kbn/content-management-utils", + "scope": "common", + "docId": "kibKbnContentManagementUtilsPluginApi", + "section": "def-common.SavedObjectUpdateOptions", + "text": "SavedObjectUpdateOptions" + }, + ", \"references\">>, \"contentTypeId\">" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.delete", + "type": "Function", + "tags": [], + "label": "delete", + "description": [], + "signature": [ + "(id: string) => Promise<", + { + "pluginId": "contentManagement", + "scope": "common", + "docId": "kibContentManagementPluginApi", + "section": "def-common.DeleteResult", + "text": "DeleteResult" + }, + ">" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.delete.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.search", + "type": "Function", + "tags": [], + "label": "search", + "description": [], + "signature": [ + "(query: ", + { + "pluginId": "contentManagement", + "scope": "common", + "docId": "kibContentManagementPluginApi", + "section": "def-common.SearchQuery", + "text": "SearchQuery" + }, + ", options?: object | undefined) => Promise<{ hits: ", + { + "pluginId": "@kbn/content-management-utils", + "scope": "common", + "docId": "kibKbnContentManagementUtilsPluginApi", + "section": "def-common.SOWithMetadata", + "text": "SOWithMetadata" + }, + "[]; pagination: { total: number; cursor?: string | undefined; }; }>" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.search.$1", + "type": "Object", + "tags": [], + "label": "query", + "description": [], + "signature": [ + { + "pluginId": "contentManagement", + "scope": "common", + "docId": "kibContentManagementPluginApi", + "section": "def-common.SearchQuery", + "text": "SearchQuery" + } + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "visualizations", + "id": "def-public.VisualizationClient.search.$2", + "type": "Uncategorized", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "object | undefined" + ], + "path": "src/plugins/visualizations/public/vis_types/vis_type_alias_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "visualizations", "id": "def-public.VisualizationListItem", diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 29d5001163434..af8226cbd8de6 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: 2023-09-13 +date: 2023-09-16 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.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 | |-------------------|-----------|------------------------|-----------------| -| 823 | 12 | 793 | 19 | +| 837 | 12 | 807 | 19 | ## Client diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index f3e74bb49ab0d..765f1949ff5f5 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -10,7 +10,7 @@ Review important information about the {kib} 8.x releases. - +* <> * <> * <> * <> @@ -48,6 +48,268 @@ Review important information about the {kib} 8.x releases. * <> -- +[[release-notes-8.10.0]] +== {kib} 8.10.0 + +For information about the {kib} 8.10.0 release, review the following information. + +[float] +[[breaking-changes-8.10.0]] +=== Breaking changes + +Breaking changes can prevent your application from optimal operation and performance. +Before you upgrade to 8.10.0, review the breaking changes, then mitigate the impact to your application. + +[discrete] +[[breaking-162665]] +.New summary search capabilities +[%collapsible] +==== +*Details* + +New summary search capabilities introduce breaking changes in various places, and we have decided to not handle backward compatibility: + +* SLO find API body parameters have changed +* The index mapping used by the rollup data has changed, and we have added a summary index that becomes the new source of truth for search +* The rollup transform have been updated, but existing SLO with their transform won't be updated. + +If some SLOs have been installed in a prior version at 8.10, the user will need to remove them manually from the UI, or by deleting the Saved Object and the associated Transform. +==== + +[discrete] +[[breaking-162506]] +.Get case metrics APIs now internal +[%collapsible] +==== +*Details* + +The get case metrics APIs are now internal. For more information, refer to ({kibana-pull}162506[#162506]). +==== + +[discrete] +[[breaking-162492]] +.Case limits +[%collapsible] +==== +*Details* + +Limits are now imposed on the number of objects cases can process or the amount of data those objects can store. +//// +For example: +* Updating a case comment is now included in the 10000 user actions restriction. ({kibana-pull}163150[#163150]) +* Updating a case now fails if the operation makes it reach more than 10000 user actions. ({kibana-pull}161848[#161848]) +* The total number of characters per comment is limited to 30000. ({kibana-pull}161357[#161357]) +* The getConnectors API now limits the number of supported connectors returned to 1000. ({kibana-pull}161282[#161282]) +* There are new limits and restrictions when retrieving cases. ({kibana-pull}162411[#162411]), ({kibana-pull}162245[#162245]), ({kibana-pull}161111[#161111]), ({kibana-pull}160705[#160705]) +* A case can now only have 100 external references and persistable state(excluding files) attachments combined. ({kibana-pull}162071[#162071]). +* New limits on titles, descriptions, tags and category. ({kibana-pull}160844[#160844]). +* The maximum number of cases that can be updated simultaneously is now 100. The minimum is 1. ({kibana-pull}161076[#161076]). +* The Delete cases API now limits the number of cases to be deleted to 100.({kibana-pull}160846[#160846]). +//// +For the full list, refer to {kib-issue}146945[#146945]. +==== + +[discrete] +[[breaking-159041]] +.`addProcessorDefinition` is removed +[%collapsible] +==== +*Details* + +The function `addProcessorDefinition` is removed from the Console plugin start contract (server side). For more information, refer to ({kibana-pull}159041[#159041]). +==== + +[float] +[[deprecations-8.10.0]] +=== Deprecations + +The following functionality is deprecated in 8.10.0, and will be removed in 9.0.0. +Deprecated functionality does not have an immediate impact on your application, but we strongly recommend +you make the necessary updates after you upgrade to 8.10.0. + +[discrete] +[[deprecation-161136]] +.Action variables in the UI and in tests that were no longer used have been replaced +[%collapsible] +==== +*Details* + +The following rule action variables have been deprecated; use the recommended variables (in parentheses) instead: + +* alertActionGroup (alert.actionGroup) +* alertActionGroupName (alert.actionGroupName) +* alertActionSubgroup (alert.actionSubgroup) +* alertId (rule.id) +* alertInstanceId (alert.id) +* alertName (rule.name) +* params (rule.params) +* spaceId (rule.spaceId) +* tags (rule.tags) + +For more information, refer to ({kibana-pull}161136[#161136]). +==== + +[float] +[[features-8.10.0]] +=== Features +{kib} 8.10.0 adds the following new and notable features. + +Alerting:: +* Adds support for self-signed SSL certificate authentication in webhook connector ({kibana-pull}161894[#161894]). +* Allow runtime fields to be selected for {es} query rule type 'group by' or 'aggregate over' options ({kibana-pull}160319[#160319]). +APM:: +* Adds KQL filtering in APM rules ({kibana-pull}163825[#163825]). +* Make service group saved objects exportable ({kibana-pull}163569[#163569]). +* Added ability to manage Cross-Cluster API keys ({kibana-pull}162363[#162363]). +* Enable Trace Explorer by default ({kibana-pull}162308[#162308]). +* Adds error.grouping_name to group alerts in Error Count rule ({kibana-pull}161810[#161810]). +* Adds query to check for overflow bucket in service groups ({kibana-pull}159990[#159990]). +Elastic Security:: +For the Elastic Security 8.10.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +Enterprise Search:: +For the Elastic Enterprise Search 8.10.0 release information, refer to {enterprise-search-ref}/changelog.html[_Elastic Enterprise Search Documentation Release notes_]. +Fleet:: +* Only enable secret storage once all fleet servers are above 8.10.0 ({kibana-pull}163627[#163627]). +* Kafka integration API ({kibana-pull}159110[#159110]). +Machine Learning:: +* AIOps: Adds/edits change point charts embeddable from the Dashboard app ({kibana-pull}163694[#163694]). +* AIOps: Adds change point detection charts embeddable ({kibana-pull}162796[#162796]). +* Adds ability to deploy trained models for data frame analytics jobs ({kibana-pull}162537[#162537]). +* Adds map view for models in Trained Models and expands support for models in Analytics map ({kibana-pull}162443[#162443]). +* Adds new Data comparison view ({kibana-pull}161365[#161365]). +Management:: +* Added ability to create a remote cluster with the API key based security model ({kibana-pull}161836[#161836]). +* REST endpoint for swapping saved object references ({kibana-pull}157665[#157665]). +Maps:: +* Maps tracks layer now uses group by time series logic ({kibana-pull}159267[#159267]). +Observability:: +* SLO definition and computed values are now summarized periodically into a summary search index, allowing users to search by name, tags, SLO budgeting type or time window, and even by and sort by error budget consumed, error budget remaining, SLI value or status ({kibana-pull}162665[#162665]). +* Adds indicator to support histogram fields ({kibana-pull}161582[#161582]). + +For more information about the features introduced in 8.10.0, refer to <>. + +[discrete] +[[enhancements-and-bug-fixes-v8.10.0-revised]] +=== Enhancements and bug fixes + +For detailed information about the 8.10.0 release, review the enhancements and bug fixes. + +[float] +[[enhancement-v8.10.0]] +=== Enhancements +Alerting:: +* Fixes the event log data stream to use Data stream lifecycle instead of Index Lifecycle Management. If you had previously customized the Kibana event log ILM policy, you should now update the lifecycle of the event log data stream itself. ({kibana-pull}163210[#163210]). +* KQL search bar for Rules page ({kibana-pull}158106[#158106]). +APM:: +* Lens function ({kibana-pull}163872[#163872]). +* Adds several function implementations to the AI Assistant ({kibana-pull}163764[#163764]). +* Feature controls ({kibana-pull}163232[#163232]). +* Added improved JVM runtime metrics dashboard ({kibana-pull}162460[#162460]). +* Move to new plugin, update design and use connectors ({kibana-pull}162243[#162243]). +* Adding endpoint to upload android map files ({kibana-pull}161252[#161252]). +* Navigate from the transaction details view into the Profiling ({kibana-pull}159686[#159686]). +Dashboard:: +* Change badge color in options list ({kibana-pull}161401[#161401]). +* Edit title, description, and tags from dashboard listing page ({kibana-pull}161399[#161399]). +* Editing toolbar update ({kibana-pull}154966[#154966]). +Discover:: +* Inline shard failures warnings ({kibana-pull}161271[#161271]). +* Improve shard error message formatting ({kibana-pull}161098[#161098]). +Elastic Security:: +For the Elastic Security 8.10.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +Enterprise Search:: +For the Elastic Enterprise Search 8.10.0 release information, refer to {enterprise-search-ref}/changelog.html[_Elastic Enterprise Search Documentation Release notes_]. +Fleet:: +* Adds support for runtime fields ({kibana-pull}161129[#161129]). +Lens & Visualizations:: +* Migrate range slider to `EuiDualRange` and make styling consistent across all controls ({kibana-pull}162651[#162651]). +* Introduce new duration formatter in *Lens* ({kibana-pull}162246[#162246]). +* Create a filter with field:value when last value metric is used on a data table in *Lens* ({kibana-pull}160509[#160509]). +* Adds tooltip for partition and heatmap filtering ({kibana-pull}162716[#162716]). +Machine Learning:: +* Hides paging controls in anomaly swim lane if only one page is available ({kibana-pull}163931[#163931]). +* Adds a throughput description in the Trained Models Deployment stats table ({kibana-pull}163481[#163481]). +* Provides hints for empty fields in dropdown options in Anomaly detection & Transform creation wizards, Change point detection view ({kibana-pull}163371[#163371]). +* AIOps: Adds dip support to log rate analysis in ML AIOps Labs ({kibana-pull}163100[#163100]). +* AIOps: Improves table hovering for log rate analysis ({kibana-pull}162941[#162941]). +* AIOps: Adds dip support for log rate analysis in observability alert details page ({kibana-pull}162476[#162476]). +* Adds validation of field selected for log pattern analysis ({kibana-pull}162319[#162319]). +* AIOps: Renames Explain Log Rate Spikes to Log Rate Analysis ({kibana-pull}161764[#161764]). +* Adds new Data comparison view ({kibana-pull}161365[#161365]). +* Adds test UI for text expansion models ({kibana-pull}159150[#159150]). +* Adds update index mappings step to ML pipeline config workflow ({kibana-pull}163723[#163723]). +Management:: +* Adds multiple formats for geo_point fields and make geo conversion tools part of field_format/common/utils ({kibana-pull}147272[#147272]). +Maps:: +* Support time series split for top hits per entity source ({kibana-pull}161799[#161799]). +Observability:: +* Adds support for group by to SLO burn rate rule ({kibana-pull}163434[#163434]). +* Applying consistent design to Histogram and Custom Metric forms ({kibana-pull}162083[#162083]). +* Adds preview chart to custom metric indicator ({kibana-pull}161597[#161597]). +* Support filters for good/total custom metrics ({kibana-pull}161308[#161308]). +Reporting:: +* Increase max size bytes default to 250mb ({kibana-pull}161318[#161318]). +Security:: +* Change the default value of `session.idleTimeout` from 8 hours to 3 days ({kibana-pull}162313[#162313]). +* User roles displayed on the user profile page ({kibana-pull}161375[#161375]). +Uptime:: +* Implement private location run once ({kibana-pull}162582[#162582]). + +[float] +[[fixes-v8.10.0]] +=== Bug Fixes +APM:: +* Fixes styling and port issue with new onboarding ({kibana-pull}163922[#163922]). +* Fixes missing alert index issue ({kibana-pull}163600[#163600]). +* Fixes trace waterfall loading logic to handle empty scenarios ({kibana-pull}163397[#163397]). +* Fixes the action menu overlapping the 'Create custom link' flyout ({kibana-pull}162664[#162664]). +* Improve service groups error messages and validations ({kibana-pull}162556[#162556]). +* Fixes throwing appropriate error when user is missing necessary permission ({kibana-pull}162466[#162466]). +* Hide components when there is no support from agents ({kibana-pull}161970[#161970]). +* Fixes link to onboarding page in the Observability Onboarding plugin ({kibana-pull}161847[#161847]). +Dashboard:: +* Disables top navigation actions when cloning or overlay is showing ({kibana-pull}162091[#162091]). +Discover:: +* Fixes document failing to load when the ID contains a slash ({kibana-pull}160239[#160239]). +* Fixes NoData screen in alignment with Dashboard and Lends behavior ({kibana-pull}160747[#160747]). +Elastic Security:: +For the Elastic Security 8.10.0 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +Enterprise Search:: +For the Elastic Enterprise Search 8.10.0 release information, refer to {enterprise-search-ref}/changelog.html[_Elastic Enterprise Search Documentation Release notes_]. +Fleet:: +* Only show agent dashboard links if there is more than one non-server agent and if the dashboards exist ({kibana-pull}164469[#164469]). +* Exclude Synthetics from per-policy-outputs ({kibana-pull}161949[#161949]). +* Fixing the path for hint templates for auto-discover ({kibana-pull}161075[#161075]). +Lens & Visualizations:: +* Fixes params._interval conversion to Lens formula ({kibana-pull}164150[#164150]). +* Fixes issues with field name that contains the `:` character in it in *Lens* ({kibana-pull}163626[#163626]). +* Fixes other request merge behavior when empty string key is retrieved ({kibana-pull}163187[#163187]). +* Fixes editing of multi values filters when adding a custom item ({kibana-pull}161940[#161940]). +* Allow setting custom colors to be collapsed by slices pie's multiple metrics in *Lens* ({kibana-pull}160592[#160592]). +* Fixes data table sorting for keyword values in *Lens* ({kibana-pull}160163[#160163]). +* Fixes override parameter when creating data views ({kibana-pull}160953[#160953]). +Logs:: +* Amend lazy imports in logs_shared plugin ({kibana-pull}164102[#164102]). +Machine Learning:: +* Fixes Trained models list crashes on browser refresh if not on page 1 ({kibana-pull}164163[#164163]). +* Fixes query bar not switching from KQL to Lucene and vice versa in Anomaly explorer ({kibana-pull}163625[#163625]). +* Data Frame Analytics creation wizard: ensures validation works correctly ({kibana-pull}163446[#163446]). +* Fixes capabilities polling in manage page ({kibana-pull}163399[#163399]). +* Fixes unhandled promise rejection from ML plugin ({kibana-pull}163129[#163129]). +* AIOps: Uses Kibana's http service instead of fetch and fixes throttling ({kibana-pull}162335[#162335]). +* Uses model supplied mask token for testing trained models ({kibana-pull}162168[#162168]). +Management:: +* Fixes how a bulk request body with variables are processed in Console ({kibana-pull}162745[#162745]). +* Improves a way of variable substitution and its documentation in Console ({kibana-pull}162382[#162382]). +* Transforms: Reduces rerenders and multiple fetches of source index on transform wizard load ({kibana-pull}160979[#160979]). +Maps:: +* Fixes Map layer preview blocks adding layer until all tiles are loaded ({kibana-pull}161994[#161994]). +Monitoring:: +* Rewrite CPU usage rule to improve accuracy ({kibana-pull}159351[#159351]). +Observability:: +* Fixes email connector rule URL ({kibana-pull}162954[#162954]). +* Disable the 'View rule details' option from the Alert Details' Actions list when the rule is deleted ({kibana-pull}163183[#163183]). +Reporting:: +* Fixes a bug where Kibana Reporting would not work in Elastic Docker without adding a special setting in kibana.yml to disable the Chromium sandbox. ({kibana-pull}149080[#149080]). +* Fixes an issue where certain international characters would not appear correctly in the contents of a print-optimized PDF report of a dashboard ({kibana-pull}161825[#161825]). +Uptime:: +* Fixes auto-expand feature for failed step detail ({kibana-pull}162747[#162747]). + [[release-notes-8.9.2]] == {kib} 8.9.2 @@ -85,7 +347,7 @@ Reporting:: [[release-notes-8.9.1]] == {kib} 8.9.1 -Review the following information about the {kib} 8.9.1 release. +Review the following information about the {kib} 8.9.1 release. [float] [[breaking-changes-8.9.1]] @@ -132,6 +394,28 @@ Discover:: For information about the {kib} 8.9.0 release, review the following information. +[float] +[[known-issues-8.9.0]] +=== Known issues + +// tag::known-issue-160116[] +[discrete] +.Changes to Lens visualizations do not appear in the saved object. +[%collapsible] +==== +*Details* + +Changes to Lens visualizations do not appear in the saved object. + +*Impact* + +When you remove fields from Lens visualizations, then save your changes, the removed fields continue to appear in the Lens visualization saved objects. +For example, when you remove runtime fields from a Lens visualization and {kib}, then inspect the Lens visualization saved object, the runtime fields continue to appear and an error message appears. + +*Workaround* + +In 8.10.0, we are addressing this issue by merging the existing and changed saved object instead of replacing the saved object. + +==== +// end::known-issue-161249[] + [float] [[breaking-changes-8.9.0]] === Breaking changes @@ -148,7 +432,7 @@ Before you upgrade to 8.9.0, review the breaking changes, then mitigate the impa The Uptime app now gets hidden from the interface when it doesn't have any data for more than a week. If you have a standalone Heartbeat pushing data to Elasticsearch, the Uptime app is considered active. You can disable this automatic behavior from the advanced settings in Kibana using the **Always show legacy Uptime app** option. For synthetic monitoring, we now recommend to use the new Synthetics app. For more information, refer to {kibana-pull}159118[#159118] ==== - + [discrete] [[breaking-159012]] .Remove synthetics pattern from Uptime settings @@ -165,7 +449,7 @@ Data from browser monitors and monitors of all types created within the Syntheti The following functionality is deprecated in 8.9.0, and will be removed in 9.0.0. Deprecated functionality does not have an immediate impact on your application, but we strongly recommend you make the necessary updates after you upgrade to 8.9.0. - + [discrete] [[deprecation-156455]] .Hide ability to create legacy input controls @@ -174,7 +458,7 @@ you make the necessary updates after you upgrade to 8.9.0. *Details* + The option to create legacy input controls when creating a new visualization is hidden. For more information, refer to {kibana-pull}156455[#156455] ==== - + [discrete] [[deprecation-155503]] .Remove legacy field stats @@ -183,7 +467,7 @@ The option to create legacy input controls when creating a new visualization is *Details* + Legacy felid stats that were previously shown within a popover have been removed. For more information, refer to {kibana-pull}155503[#155503] ==== - + [float] [[features-8.9.0]] === Features @@ -393,14 +677,14 @@ Review the following information about the {kib} 8.8.2 release. [%collapsible] ==== *Details* + -Due to a schema version update, during {fleet} setup in 8.8.x, all agent policies are being queried and deployed. +Due to a schema version update, during {fleet} setup in 8.8.x, all agent policies are being queried and deployed. This action triggers a lot of queries to the Elastic Package Registry (EPR) to fetch integration packages. As a result, -there is an increase in Kibana's resident memory usage (RSS). +there is an increase in Kibana's resident memory usage (RSS). *Impact* + -Because the default batch size of `100` for schema version upgrade of {fleet} agent policies is too high, this can +Because the default batch size of `100` for schema version upgrade of {fleet} agent policies is too high, this can cause Kibana to run out of memory during an upgrade. For example, we have observed 1GB Kibana instances run -out of memory during an upgrade when there were 20 agent policies with 5 integrations in each. +out of memory during an upgrade when there were 20 agent policies with 5 integrations in each. *Workaround* + Two workaround options are available: @@ -476,14 +760,14 @@ Review the following information about the {kib} 8.8.1 release. [%collapsible] ==== *Details* + -Due to a schema version update, during {fleet} setup in 8.8.x, all agent policies are being queried and deployed. +Due to a schema version update, during {fleet} setup in 8.8.x, all agent policies are being queried and deployed. This action triggers a lot of queries to the Elastic Package Registry (EPR) to fetch integration packages. As a result, -there is an increase in Kibana's resident memory usage (RSS). +there is an increase in Kibana's resident memory usage (RSS). *Impact* + -Because the default batch size of `100` for schema version upgrade of {fleet} agent policies is too high, this can +Because the default batch size of `100` for schema version upgrade of {fleet} agent policies is too high, this can cause Kibana to run out of memory during an upgrade. For example, we have observed 1GB Kibana instances run -out of memory during an upgrade when there were 20 agent policies with 5 integrations in each. +out of memory during an upgrade when there were 20 agent policies with 5 integrations in each. *Workaround* + Two workaround options are available: @@ -594,14 +878,14 @@ Review the following information about the {kib} 8.8.0 release. [%collapsible] ==== *Details* + -Due to a schema version update, during {fleet} setup in 8.8.x, all agent policies are being queried and deployed. +Due to a schema version update, during {fleet} setup in 8.8.x, all agent policies are being queried and deployed. This action triggers a lot of queries to the Elastic Package Registry (EPR) to fetch integration packages. As a result, -there is an increase in Kibana's resident memory usage (RSS). +there is an increase in Kibana's resident memory usage (RSS). *Impact* + -Because the default batch size of `100` for schema version upgrade of {fleet} agent policies is too high, this can +Because the default batch size of `100` for schema version upgrade of {fleet} agent policies is too high, this can cause Kibana to run out of memory during an upgrade. For example, we have observed 1GB Kibana instances run -out of memory during an upgrade when there were 20 agent policies with 5 integrations in each. +out of memory during an upgrade when there were 20 agent policies with 5 integrations in each. *Workaround* + Two workaround options are available: diff --git a/docs/api-generated/connectors/connector-apis-passthru.asciidoc b/docs/api-generated/connectors/connector-apis-passthru.asciidoc index 73a0bf8df1da0..a3d8de47a0ab2 100644 --- a/docs/api-generated/connectors/connector-apis-passthru.asciidoc +++ b/docs/api-generated/connectors/connector-apis-passthru.asciidoc @@ -1003,6 +1003,7 @@ Any modifications made to this file will be overwritten.
  • action_response_properties - Action response properties
  • config_properties_cases_webhook - Connector request properties for Webhook - Case Management connector
  • config_properties_d3security - Connector request properties for a D3 Security connector
  • +
  • config_properties_email - Connector request properties for an email connector
  • config_properties_genai - Connector request properties for a generative AI connector
  • config_properties_index - Connector request properties for an index connector
  • config_properties_jira - Connector request properties for a Jira connector
  • @@ -1092,6 +1093,7 @@ Any modifications made to this file will be overwritten.
  • run_connector_subaction_pushtoservice_subActionParams_incident_source_ip -
  • secrets_properties_cases_webhook - Connector secrets properties for Webhook - Case Management connector
  • secrets_properties_d3security - Connector secrets properties for a D3 Security connector
  • +
  • secrets_properties_email - Connector secrets properties for an email connector
  • secrets_properties_genai - Connector secrets properties for a generative AI connector
  • secrets_properties_jira - Connector secrets properties for a Jira connector
  • secrets_properties_opsgenie - Connector secrets properties for an Opsgenie connector
  • @@ -1107,6 +1109,7 @@ Any modifications made to this file will be overwritten.
  • updateConnector_400_response -
  • update_connector_request_cases_webhook - Update Webhook - Case Managment connector request
  • update_connector_request_d3security - Update D3 Security connector request
  • +
  • update_connector_request_email - Update email connector request
  • update_connector_request_index - Update index connector request
  • update_connector_request_jira - Update Jira connector request
  • update_connector_request_opsgenie - Update Opsgenie connector request
  • @@ -1119,6 +1122,7 @@ Any modifications made to this file will be overwritten.
  • update_connector_request_slack_webhook - Update Slack connector request
  • update_connector_request_swimlane - Update Swimlane connector request
  • update_connector_request_teams - Update Microsoft Teams connector request
  • +
  • update_connector_request_webhook - Update Webhook connector request
  • update_connector_request_xmatters - Update xMatters connector request
  • @@ -1397,6 +1401,23 @@ Any modifications made to this file will be overwritten.
    url
    String The D3 Security API request URL. If you are using the xpack.actions.allowedHosts setting, add the hostname to the allowed hosts.
    +
    +

    config_properties_email - Connector request properties for an email connector Up

    +
    Defines properties for connectors when type is .email.
    +
    +
    clientId (optional)
    String The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If service is exchange_server, this property is required.
    +
    from
    String The from address for all emails sent by the connector. It must be specified in user@host-name format.
    +
    hasAuth (optional)
    Boolean Specifies whether a user and password are required inside the secrets configuration.
    +
    host (optional)
    String The host name of the service provider. If the service is elastic_cloud (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If service is other, this property must be defined.
    +
    oauthTokenUrl (optional)
    +
    port (optional)
    Integer The port to connect to on the service provider. If the service is elastic_cloud (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If service is other, this property must be defined.
    +
    secure (optional)
    Boolean Specifies whether the connection to the service provider will use TLS. If the service is elastic_cloud (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored.
    +
    service (optional)
    String The name of the email service.
    +
    Enum:
    +
    elastic_cloud
    exchange_server
    gmail
    other
    outlook365
    ses
    +
    tenantId (optional)
    String The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If service is exchange_server, this property is required.
    +
    +

    config_properties_genai - Connector request properties for a generative AI connector Up

    Defines properties for connectors when type is .gen-ai.
    @@ -1561,7 +1582,7 @@ Any modifications made to this file will be overwritten.

    connector_response_properties_email - Connector response properties for an email connector Up

    -
    config
    map[String, oas_any_type_not_mapped] Defines properties for connectors when type is .email.
    +
    config
    connector_type_id
    String The type of connector.
    Enum:
    .email
    @@ -1861,12 +1882,12 @@ Any modifications made to this file will be overwritten.

    create_connector_request_email - Create email connector request Up

    The email connector uses the SMTP protocol to send mail messages, using an integration of Nodemailer. An exception is Microsoft Exchange, which uses HTTP protocol for sending emails, Send mail. Email message text is sent as both plain text and html text.
    -
    config
    map[String, oas_any_type_not_mapped] Defines properties for connectors when type is .email.
    +
    config
    connector_type_id
    String The type of connector.
    Enum:
    .email
    name
    String The display name for the connector.
    -
    secrets
    map[String, oas_any_type_not_mapped] Defines secrets for connectors when type is .email.
    +
    secrets
    @@ -2425,6 +2446,15 @@ Any modifications made to this file will be overwritten.
    token
    String The D3 Security token.
    +
    +

    secrets_properties_email - Connector secrets properties for an email connector Up

    +
    Defines secrets for connectors when type is .email.
    +
    +
    clientSecret (optional)
    String The Microsoft Exchange Client secret for OAuth 2.0 client credentials authentication. It must be URL-encoded. If service is exchange_server, this property is required.
    +
    password (optional)
    String The password for HTTP basic authentication. If hasAuth is set to true, this property is required.
    +
    user (optional)
    String The username for HTTP basic authentication. If hasAuth is set to true, this property is required.
    +
    +

    secrets_properties_genai - Connector secrets properties for a generative AI connector Up

    Defines secrets for connectors when type is .gen-ai.
    @@ -2548,6 +2578,15 @@ Any modifications made to this file will be overwritten.
    secrets
    +
    +

    update_connector_request_email - Update email connector request Up

    +
    +
    +
    config
    +
    name
    String The display name for the connector.
    +
    secrets (optional)
    +
    +

    update_connector_request_index - Update index connector request Up

    @@ -2650,6 +2689,15 @@ Any modifications made to this file will be overwritten.
    secrets
    +

    update_connector_request_xmatters - Update xMatters connector request Up

    diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 9321e7499f9b4..48190bc8929be 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -648,6 +648,10 @@ using the CURL scripts in the scripts folder. |Visualize geo data from Elasticsearch or 3rd party geo-services. +|{kib-repo}blob/{branch}/x-pack/plugins/metrics_data_access/README.md[metricsDataAccess] +|Exposes utilities to access metrics data. + + |{kib-repo}blob/{branch}/x-pack/plugins/ml/readme.md[ml] |This plugin provides access to the machine learning features provided by Elastic. diff --git a/docs/landing-page.asciidoc b/docs/landing-page.asciidoc index 79b7fdf2a7ec4..8d806d574129a 100644 --- a/docs/landing-page.asciidoc +++ b/docs/landing-page.asciidoc @@ -259,7 +259,7 @@
    - +

    diff --git a/docs/management/cases/manage-cases.asciidoc b/docs/management/cases/manage-cases.asciidoc index a3f0a40fd6009..e3896423b3f13 100644 --- a/docs/management/cases/manage-cases.asciidoc +++ b/docs/management/cases/manage-cases.asciidoc @@ -105,14 +105,13 @@ For self-managed {kib}: + -- NOTE: At this time, email notifications support only preconfigured connectors, -which are defined in the `kibana.yml` file. For examples, refer to -{kibana-ref}/email-action-type.html#preconfigured-email-configuration[Preconfigured email connector] -and {kibana-ref}/email-action-type.html#configuring-email[Configuring email connectors for well-known services]. +which are defined in the `kibana.yml` file. +For examples, refer to <> and <>. -- . Set the `notifications.connectors.default.email` {kib} setting to the name of your email connector. . If you want the email notifications to contain links back to the case, you -must configure the {kibana-ref}/settings.html#server-publicBaseUrl[server.publicBaseUrl] setting. +must configure the <> setting. When you subsequently add assignees to cases, they receive an email. // end::case-notifications[] diff --git a/docs/management/connectors/action-types/email.asciidoc b/docs/management/connectors/action-types/email.asciidoc index 0f652821a3661..c7cea7e1dceff 100644 --- a/docs/management/connectors/action-types/email.asciidoc +++ b/docs/management/connectors/action-types/email.asciidoc @@ -97,88 +97,12 @@ Username for login type authentication. Password:: Password for login type authentication. -[float] -[[preconfigured-email-configuration]] -=== Create preconfigured connectors - -If you are running {kib} on-prem, you can define connectors by -adding `xpack.actions.preconfigured` settings to your `kibana.yml` file. -For example: - -[source,text] --- -xpack.actions.preconfigured: - my-email: - name: preconfigured-email-connector-type - actionTypeId: .email - config: - service: other - from: testsender@test.com - host: validhostname - port: 8080 - secure: false - secrets: - user: testuser - password: passwordkeystorevalue --- - -Config defines information for the connector type. - -`service`:: -The name of the email service. If `service` is `elastic_cloud` (for Elastic -Cloud notifications) or one of Nodemailer's well-known email service providers, -the `host`, `port`, and `secure` properties are ignored. If `service` is `other`, -the `host` and `port` properties must be defined. For more information on the -`gmail` service value, refer to -https://nodemailer.com/usage/using-gmail/[Nodemailer Gmail documentation]. If -`service` is `exchange_server`, the `tenantId`, `clientId`, `clientSecret` -properties are required instead of `host` and `port`. - -`from`:: -An email address that corresponds to *Sender*. - -`host`:: -A string that corresponds to *Host*. - -`port`:: -A number that corresponds to *Port*. - -`secure`:: -A boolean that corresponds to *Secure*. - -`hasAuth`:: -A boolean that corresponds to *Requires authentication*. If `true`, this -connector will require values for `user` and `password` inside the secrets -configuration. Defaults to `true`. - -`tenantId`:: -A GUID format value that corresponds to *Tenant ID*, which is a part of OAuth -2.0 Client Credentials Authentication. - -`clientId`:: -A GUID format value that corresponds to *Client ID*, which is a part of OAuth -2.0 Client Credentials Authentication. - -Secrets defines sensitive information for the connector type. - -`user`:: -A string that corresponds to *Username*. Required if `hasAuth` is set to `true`. - -`password`:: -A string that corresponds to *Password*. Should be stored in the -<>. Required if `hasAuth` is set to `true`. - -`clientSecret`:: -A string that corresponds to *Client Secret*. Should be stored in the -<>. Required if `service` is set to -`exchange_server`, which uses OAuth 2.0 Client Credentials Authentication. - [float] [[email-action-configuration]] === Test connectors -You can test connectors with the <> or -as you're creating or editing the connector in {kib}. For example: +You can test connectors as you're creating or editing the connector in {kib}. +For example: [role="screenshot"] image::management/connectors/images/email-params-test.png[Email params test] @@ -214,14 +138,6 @@ settings. You can set configurations that apply to all your connectors or use The email connector uses an integration of https://nodemailer.com/[Nodemailer] to send email from many popular SMTP email services. For Microsoft Exchange email, it uses the Microsoft Graph API. -To configure the email connector to work with common email systems, refer to: - -* <> -* <> -* <> -* <> -* <> - For other email servers, you can check the list of well-known services that Nodemailer supports in the JSON file https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json[well-known/services.json]. @@ -233,32 +149,17 @@ is considered `false`. Typically, `port: 465` uses `secure: true`, and [float] [[elasticcloud]] -==== Sending email from Elastic Cloud +==== {ecloud} -Use the preconfigured email connector (`Elastic-Cloud-SMTP`) to send emails from -Elastic Cloud. +Use the preconfigured email connector (`Elastic-Cloud-SMTP`) to send emails from {ecloud}. -NOTE: For more information on the preconfigured email connector, see link:{cloud}/ec-watcher.html#ec-cloud-email-service-limits[Elastic Cloud email service limits]. +NOTE: For more information on the preconfigured email connector, see link:{cloud}/ec-watcher.html#ec-cloud-email-service-limits[{ecloud} email service limits]. [float] [[gmail]] -==== Sending email from Gmail - -Use the following email connector configuration to send email from the -https://mail.google.com[Gmail] SMTP service: - -[source,text] --------------------------------------------------- - config: - service: gmail - // `host`, `port` and `secure` have the following default values and do not need to set: - // host: smtp.gmail.com - // port: 465 - // secure: true - secrets: - user: - password: --------------------------------------------------- +==== Gmail + +To create a connector that sends email from the https://mail.google.com[Gmail] SMTP service, set the **Service** to `Gmail`. If you get an authentication error that indicates that you need to continue the sign-in process from a web browser when the action attempts to send email, you @@ -272,23 +173,10 @@ for more information. [float] [[outlook]] -==== Sending email from Outlook.com - -Use the following email connector configuration to send email from the -https://www.outlook.com/[Outlook.com] SMTP service: - -[source,text] --------------------------------------------------- -config: - service: outlook365 - // `host`, `port` and `secure` have the following default values and do not need to set: - // host: smtp.office365.com - // port: 587 - // secure: false -secrets: - user: - password: --------------------------------------------------- +==== Outlook.com + +To create a connector that sends email from the +https://www.outlook.com/[Outlook.com] SMTP service, set the **Service** to `Outlook`. When sending emails, you must provide a `from` address, either as the default in your connector configuration or as part of the email action in the rule. @@ -300,24 +188,10 @@ for more information. [float] [[amazon-ses]] -==== Sending email from Amazon SES (Simple Email Service) - -Use the following email connector configuration to send email from the -http://aws.amazon.com/ses[Amazon Simple Email Service] (SES) SMTP service: - -[source,text] --------------------------------------------------- -config: - service: ses - // `host`, `port` and `secure` have the following default values and do not need to set: - // host: email-smtp.us-east-1.amazonaws.com <1> - // port: 465 - // secure: true -secrets: - user: - password: --------------------------------------------------- -<1> `config.host` varies depending on the region +==== Amazon SES + +To create a connector that sends email from the +http://aws.amazon.com/ses[Amazon Simple Email Service] (SES) SMTP service, set the **Service** to `Amazon SES`. NOTE: You must use your Amazon SES SMTP credentials to send email through Amazon SES. For more information, see @@ -328,38 +202,19 @@ or https://docs.aws.amazon.com/ses/latest/DeveloperGuide/verify-domains.html[your whole domain] at AWS. - [float] [[exchange-basic-auth]] -==== Sending email from Microsoft Exchange with Basic Authentication +==== Microsoft Exchange with basic authentication deprecated:[7.16.0,"This Microsoft Exchange configuration is deprecated and will be removed later because Microsoft is deprecating basic authentication."] -[source,text] --------------------------------------------------- -config: - service: other - host: - port: 465 - secure: true - from: <1> -secrets: - user: <2> - password: --------------------------------------------------- -<1> Some organizations configure Exchange to validate that the `from` field is a - valid local email account. -<2> Many organizations support use of your email address as your username. - Check with your system administrator if you receive - authentication-related failures. - To prepare for the removal of Basic Auth, you must update all existing Microsoft Exchange connectors with the new configuration based on the https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow[OAuth 2.0 Client Credentials Authentication]. [float] [[exchange]] -==== Sending email from Microsoft Exchange with OAuth 2.0 +==== Microsoft Exchange with OAuth 2.0 NOTE: The email connector uses Microsoft Graph REST API v1.0, in particular the https://docs.microsoft.com/en-us/graph/api/user-sendmail[sendMail] endpoint. It supports only the https://learn.microsoft.com/en-us/graph/deployments#microsoft-graph-and-graph-explorer-service-root-endpoints[Microsoft Graph global service] root endpoint (`https://graph.microsoft.com`). @@ -396,9 +251,9 @@ image::management/connectors/images/exchange-granted.png[MS Exchange grant confi [float] [[exchange-client-secret]] -===== Configure Microsoft Exchange Client secret +===== Configure the Microsoft Exchange Client secret -To configure the Client secret , open *Manage > Certificates & secrets*. +To configure the Microsoft Exchange Client secret, open *Manage > Certificates & secrets*: [role="screenshot"] image::management/connectors/images/exchange-secrets.png[MS Exchange secrets configuration] @@ -408,29 +263,12 @@ the Microsoft Exchange email connector. [float] [[exchange-client-tenant-id]] -===== Configure Microsoft Exchange Client ID and Tenant ID +===== Configure the Microsoft Exchange client and tenant identifiers -To find the application Client ID, open the *Overview* page. +To find the Microsoft Exchange client and tenant IDs, open the *Overview* page: [role="screenshot"] image::management/connectors/images/exchange-client-tenant.png[MS Exchange Client ID and Tenant ID configuration] -Copy and paste this values to the proper fields in the Microsoft Exchange email -connector. - -Use the following email connector configuration to send email from Microsoft -Exchange: - -[source,text] --------------------------------------------------- -config: - service: exchange_server - clientId: <1> - tenantId: - from: <2> -secrets: - clientSecret: --------------------------------------------------- -<1> This application information is on the https://go.microsoft.com/fwlink/?linkid=2083908[Azure portal – App registrations]. -<2> Some organizations configure Exchange to validate that the `from` field is a - valid local email account. +Create a connector and set the **Service** to `MS Exchange Server`. +Copy and paste the values into the proper fields. \ No newline at end of file diff --git a/docs/management/connectors/pre-configured-connectors.asciidoc b/docs/management/connectors/pre-configured-connectors.asciidoc index 60e35eb510597..0cf5734f1ab77 100644 --- a/docs/management/connectors/pre-configured-connectors.asciidoc +++ b/docs/management/connectors/pre-configured-connectors.asciidoc @@ -108,6 +108,7 @@ Index names must start with `kibana-alert-history-` to take advantage of the pre * <> * <> +* <> * <> * <> * <> @@ -138,6 +139,141 @@ xpack.actions.preconfigured: <1> The D3 Security API request URL. <2> The D3 Security token. +[float] +[[preconfigured-email-configuration]] +==== Email connectors + +The following example creates an <>: + +[source,text] +-- +xpack.actions.preconfigured: + my-email: + name: preconfigured-email-connector-type + actionTypeId: .email + config: + service: other <1> + from: testsender@test.com <2> + host: validhostname <3> + port: 8080 <4> + secure: false <5> + hasAuth: true <6> + secrets: + user: testuser <7> + password: passwordkeystorevalue <8> +-- + +<1> The name of the email service. If `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, the `host`, `port`, and `secure` properties are ignored. If `service` is `other`, the `host` and `port` properties must be defined. For more information on the `gmail` service value, refer to https://nodemailer.com/usage/using-gmail/[Nodemailer Gmail documentation]. If `service` is `exchange_server`, the `tenantId`, `clientId`, `clientSecret` +properties are required instead of `host` and `port`. +<2> The email address for all emails sent with this connector. It must be specified in `user@host-name` format. +<3> The host name of the service provider. +<4> The port to connect to on the service provider. +<5> If true, the connection will use TLS when connecting to the service provider. +<6> If `true`, this connector will require values for `user` and `password` inside the secrets configuration. Defaults to `true`. +<7> A user name for authentication. Required if `hasAuth` is set to `true`. +<8> A password for authentication. Should be stored in the <>. Required if `hasAuth` is set to `true`. + + +[float] +[[preconfigured-email-configuration-amazon-ses]] +===== Amazon SES (Simple Email Service) + +Use the following email connector configuration to send email from the +http://aws.amazon.com/ses[Amazon Simple Email Service] (SES) SMTP service: + +[source,text] +-------------------------------------------------- +config: + service: ses + // `host`, `port` and `secure` have the following default values and do not need to set: + // host: email-smtp.us-east-1.amazonaws.com <1> + // port: 465 + // secure: true +secrets: + user: + password: +-------------------------------------------------- +<1> `config.host` varies depending on the region + +[float] +[[preconfigured-email-configuration-gmail]] +===== Gmail + +Use the following email connector configuration to send email from the https://mail.google.com[Gmail] SMTP service: + +[source,text] +-------------------------------------------------- + config: + service: gmail + // `host`, `port` and `secure` have the following default values and do not need to set: + // host: smtp.gmail.com + // port: 465 + // secure: true + secrets: + user: + password: +-------------------------------------------------- + +[float] +[[preconfigured-email-configuration-exchange-basic-auth]] +===== Microsoft Exchange with basic authentication + +deprecated:[7.16.0,"This Microsoft Exchange configuration is deprecated and will be removed later because Microsoft is deprecating basic authentication."] + +[source,text] +-------------------------------------------------- +config: + service: other + host: + port: 465 + secure: true + from: <1> +secrets: + user: <2> + password: +-------------------------------------------------- +<1> Some organizations configure Exchange to validate that the `from` field is a valid local email account. +<2> Many organizations support use of your email address as your username. Check with your system administrator if you receive authentication-related failures. + +[float] +[[preconfigured-email-configuration-exchange]] +===== Microsoft Exchange with OAuth 2.0 + +Use the following email connector configuration to send email from Microsoft Exchange: + +[source,text] +-------------------------------------------------- +config: + service: exchange_server + clientId: <1> + tenantId: + from: <2> +secrets: + clientSecret: +-------------------------------------------------- +<1> This application information is on the https://go.microsoft.com/fwlink/?linkid=2083908[Azure portal – App registrations]. +<2> Some organizations configure Exchange to validate that the `from` field is a valid local email account. + +[float] +[[preconfigured-email-configuration-outlook]] +===== Outlook.com + +Use the following email connector configuration to send email from the +https://www.outlook.com/[Outlook.com] SMTP service: + +[source,text] +-------------------------------------------------- +config: + service: outlook365 + // `host`, `port` and `secure` have the following default values and do not need to set: + // host: smtp.office365.com + // port: 587 + // secure: false +secrets: + user: + password: +-------------------------------------------------- + [float] [[preconfigured-resilient-configuration]] ==== {ibm-r} connectors diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index 1928cfb97bdfe..f4ac0f11739b0 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -291,7 +291,7 @@ This page has been moved. Refer to <>. [[development-plugin-localization]] === Localization for plugins -This page has been moved. PRefer to <>. +This page has been moved. Refer to <>. [role="exclude",id="visualize"] == Visualize @@ -417,3 +417,8 @@ This page has been deleted. Refer to <>. == Alerts and Actions This page has been deleted. Refer to <>. + +[role="exclude",id="enhancements-and-bug-fixes-v8.10.0"] +== Enhancements and bug fixes for 8.10.0 + +This content has moved. Refer to <> for 8.10.0. diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index c86678ee3a775..88da0859858a0 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -270,6 +270,9 @@ A configuration URL that varies by connector: NOTE: If you are using the `xpack.actions.allowedHosts` setting, make sure the hostname in the URL is added to the allowed hosts. -- +`xpack.actions.preconfigured..config.clientId`:: +For an <>, specifies a GUID format value that corresponds to the client ID, which is a part of OAuth 2.0 client credentials authentication. + `xpack.actions.preconfigured..config.configUrl`:: For an <> with basic authentication, specifies the request URL for the Elastic Alerts trigger in xMatters. @@ -306,6 +309,10 @@ For a <>, specifies a string f `xpack.actions.preconfigured..config.executionTimeField`:: For an <>, a field that indicates when the document was indexed. +`xpack.actions.preconfigured..config.from`:: +For an <>, specifies the from address for all emails sent by the connector. +It must be specified in `user@host-name` format. + `xpack.actions.preconfigured..config.getIncidentResponseExternalTitleKey`:: For a <>, specifies a string from the response body of the get case method that corresponds to the external service title. @@ -315,20 +322,38 @@ For a <>, specifies a REST API NOTE: If you are using the `xpack.actions.allowedHosts` setting, make sure the hostname in the URL is added to the allowed hosts. `xpack.actions.preconfigured..config.hasAuth`:: -For a <>, specifies whether a user and password are required inside the secrets configuration. Defaults to `true`. +For an <>, <>, or <>, specifies whether a user and password are required inside the secrets configuration. Defaults to `true`. `xpack.actions.preconfigured..config.headers`:: -For a <>, specifies a set of key-value pairs sent as headers with the request. +For a <> or <>, specifies a set of key-value pairs sent as headers with the request. + +`xpack.actions.preconfigured..config.host`:: +For an <>, specifies the host name of the service provider. `xpack.actions.preconfigured..config.index`:: For an <>, specifies the {es} index. +`xpack.actions.preconfigured..config.method`:: +For a <>, specifies the HTTP request method, either `post` or `put`. Defaults to `post`. + `xpack.actions.preconfigured..config.orgId`:: For an <>, specifies the {ibm-r} organization identifier. +`xpack.actions.preconfigured..config.port`:: +For an <>, specifies the port to connect to on the service provider. + `xpack.actions.preconfigured..config.projectKey`:: For a <>, specifies the Jira project key. +`xpack.actions.preconfigured..config.secure`:: +For an <>, specifies whether the connection will use TLS when connecting to the service provider. If not true, the connection will initially connect over TCP then attempt to switch to TLS via the SMTP STARTTLS command. + +`xpack.actions.preconfigured..config.service`:: +For an <>, specifies the name of the email service. For example, `elastic_cloud`, `exchange_server`, `gmail`, `other`, `outlook365`, or `ses`. + +`xpack.actions.preconfigured..config.tenantId`:: +For an <>, specifies a GUID format value that corresponds to a tenant ID, which is a part of OAuth 2.0 client credentials authentication. + `xpack.actions.preconfigured..config.updateIncidentJson`:: For a <>, specifies a stringified JSON payload with Mustache variables that is sent to the update case URL to update a case. Required variables are `case.title` and `case.description`. + @@ -348,6 +373,7 @@ A configuration URL that varies by connector: + -- * For a <>, specifies the D3 Security API request URL. +* For a <>, specifies the web service request URL. NOTE: If you are using the `xpack.actions.allowedHosts` setting, make sure this hostname is added to the allowed hosts. -- @@ -382,6 +408,15 @@ For an <>, specifies the authentication `xpack.actions.preconfigured..secrets.apiToken`:: For a <>, specifies the API authentication token for HTTP basic authentication. +`xpack.actions.preconfigured..secrets.clientSecret`:: +A client secret that varies by connector: ++ +-- +* For an <>, specifies the client secret that you generated for your app in the app registration portal. It is required when the email service is `exchange_server`, which uses OAuth 2.0 client credentials authentication. + +NOTE: The client secret must be URL-encoded. +-- + `xpack.actions.preconfigured..secrets.email`:: For a <>, specifies the account email for HTTP basic authentication. @@ -389,7 +424,7 @@ For a <>, specifies the account email for HTTP A password secret that varies by connector: + -- -* For a <>, specifies a password that is required when `xpack.actions.preconfigured..config.hasAuth` is `true`. +* For an <>, <>, or <>, specifies a password that is required when `xpack.actions.preconfigured..config.hasAuth` is `true`. * For an <>, specifies a password that is required when `xpack.actions.preconfigured..config.usesBasic` is `true`. -- @@ -414,7 +449,7 @@ A token secret that varies by connector: A user name secret that varies by connector: + -- -* For a <>, specifies a user name that is required when `xpack.actions.preconfigured..config.hasAuth` is `true`. +* For an <>, <>, or <>, specifies a user name that is required when `xpack.actions.preconfigured..config.hasAuth` is `true`. * For an <>, specifies a user name that is required when `xpack.actions.preconfigured..config.usesBasic` is `true`. -- diff --git a/examples/search_examples/public/search/app.tsx b/examples/search_examples/public/search/app.tsx index 0fa13df35a4e9..84bc3e1cd79be 100644 --- a/examples/search_examples/public/search/app.tsx +++ b/examples/search_examples/public/search/app.tsx @@ -311,17 +311,15 @@ export const SearchExamplesApp = ({ const result = await lastValueFrom( searchSource.fetch$({ abortSignal: abortController.signal, - disableShardFailureWarning: !showWarningToastNotifications, + disableWarningToasts: !showWarningToastNotifications, inspector, }) ); setRawResponse(result.rawResponse); - /* Here is an example of using showWarnings on the search service, using an optional callback to - * intercept the warnings before notification warnings are shown. - * - * Suppressing the shard failure warning notification from appearing by default requires setting - * { disableShardFailureWarning: true } in the SearchSourceSearchOptions passed to $fetch + /* + * Set disableWarningToasts to true to disable warning toasts and customize warning display. + * Then use showWarnings to customize warning notification. */ if (showWarningToastNotifications) { setWarningContents([]); @@ -498,7 +496,7 @@ export const SearchExamplesApp = ({ {' '} {' '} {' '} {' '} diff --git a/package.json b/package.json index 08d889905d37d..220d685d29cab 100644 --- a/package.json +++ b/package.json @@ -514,6 +514,7 @@ "@kbn/maps-ems-plugin": "link:src/plugins/maps_ems", "@kbn/maps-plugin": "link:x-pack/plugins/maps", "@kbn/maps-vector-tile-utils": "link:x-pack/packages/maps/vector_tile_utils", + "@kbn/metrics-data-access-plugin": "link:x-pack/plugins/metrics_data_access", "@kbn/ml-agg-utils": "link:x-pack/packages/ml/agg_utils", "@kbn/ml-anomaly-utils": "link:x-pack/packages/ml/anomaly_utils", "@kbn/ml-category-validator": "link:x-pack/packages/ml/category_validator", @@ -1433,7 +1434,7 @@ "blob-polyfill": "^7.0.20220408", "callsites": "^3.1.0", "chance": "1.0.18", - "chromedriver": "^115.0.1", + "chromedriver": "^116.0.0", "clean-webpack-plugin": "^3.0.0", "cli-table3": "^0.6.1", "compression-webpack-plugin": "^4.0.0", diff --git a/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts b/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts index f2ba7c25de768..d140a6c99e7b0 100644 --- a/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts +++ b/packages/core/analytics/core-analytics-browser-internal/src/track_clicks.ts @@ -9,8 +9,17 @@ import { fromEvent } from 'rxjs'; import type { AnalyticsClient } from '@kbn/analytics-client'; -/** HTML attributes that should be skipped from reporting because they might contain user data */ -const POTENTIAL_PII_HTML_ATTRIBUTES = ['value']; +/** HTML attributes that should be skipped from reporting because they might contain data we do not wish to collect */ +const HTML_ATTRIBUTES_TO_REMOVE = [ + 'data-href', + 'data-ech-series-name', + 'data-provider-id', + 'data-rfd-drag-handle-draggable-id', + 'data-rfd-droppable-id', + 'data-rfd-draggable-id', + 'href', + 'value', +]; /** * Registers the event type "click" in the analytics client. @@ -71,7 +80,7 @@ function getTargetDefinition(target: HTMLElement): string[] { ...(target.parentElement ? getTargetDefinition(target.parentElement) : []), target.tagName, ...[...target.attributes] - .filter((attr) => !POTENTIAL_PII_HTML_ATTRIBUTES.includes(attr.name)) + .filter((attr) => !HTML_ATTRIBUTES_TO_REMOVE.includes(attr.name)) .map((attr) => `${attr.name}=${attr.value}`), ]; } diff --git a/packages/core/http/core-http-router-server-internal/src/router.ts b/packages/core/http/core-http-router-server-internal/src/router.ts index 5177464796291..5f7d970bc6bb6 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.ts @@ -200,7 +200,7 @@ export class Router field.name === fieldName); }; + dataViewFields.getByType = (type: string) => { + return dataViewFields.filter((field) => field.type === type); + }; + dataViewFields.getAll = () => { return dataViewFields; }; diff --git a/packages/kbn-es-types/index.ts b/packages/kbn-es-types/index.ts index e97df4d4eaa11..cd2d0a5f2618e 100644 --- a/packages/kbn-es-types/index.ts +++ b/packages/kbn-es-types/index.ts @@ -18,4 +18,5 @@ export type { AggregationResultOfMap, ESFilter, MaybeReadonlyArray, + ClusterDetails, } from './src'; diff --git a/packages/kbn-es-types/src/index.ts b/packages/kbn-es-types/src/index.ts index a18d6b39410f8..f22e43fc7e705 100644 --- a/packages/kbn-es-types/src/index.ts +++ b/packages/kbn-es-types/src/index.ts @@ -11,6 +11,7 @@ import { AggregateOf as AggregationResultOf, AggregateOfMap as AggregationResultOfMap, SearchHit, + ClusterDetails, } from './search'; export type ESFilter = estypes.QueryDslQueryContainer; @@ -34,4 +35,10 @@ export type ESSearchResponse< TOptions extends { restTotalHitsAsInt: boolean } = { restTotalHitsAsInt: false } > = InferSearchResponseOf; -export type { InferSearchResponseOf, AggregationResultOf, AggregationResultOfMap, SearchHit }; +export type { + InferSearchResponseOf, + AggregationResultOf, + AggregationResultOfMap, + SearchHit, + ClusterDetails, +}; diff --git a/packages/kbn-es-types/src/search.ts b/packages/kbn-es-types/src/search.ts index 13ebc02b65aa6..502a7464e5351 100644 --- a/packages/kbn-es-types/src/search.ts +++ b/packages/kbn-es-types/src/search.ts @@ -644,3 +644,12 @@ export type InferSearchResponseOf< >; }; }; + +export interface ClusterDetails { + status: 'running' | 'successful' | 'partial' | 'skipped' | 'failed'; + indices: string; + took?: number; + timed_out: boolean; + _shards?: estypes.ShardStatistics; + failures?: estypes.ShardFailure[]; +} diff --git a/packages/kbn-es/src/cli_commands/serverless.ts b/packages/kbn-es/src/cli_commands/serverless.ts index 53f1e1b35ae74..f20d957851fed 100644 --- a/packages/kbn-es/src/cli_commands/serverless.ts +++ b/packages/kbn-es/src/cli_commands/serverless.ts @@ -30,11 +30,16 @@ export const serverless: Command = { --tag Image tag of ESS to run from ${SERVERLESS_REPO} [default: ${SERVERLESS_TAG}] --image Full path of ESS image to run, has precedence over tag. [default: ${SERVERLESS_IMG}] + + --background Start ESS without attaching to the first node's logs + --basePath Path to the directory where the ES cluster will store data --clean Remove existing file system object store before running + --kill Kill running ESS nodes if detected on startup --port The port to bind to on 127.0.0.1 [default: ${DEFAULT_PORT}] --ssl Enable HTTP SSL on Elasticsearch - --kill Kill running ESS nodes if detected - --background Start ESS without attaching to the first node's logs + --teardown If this process exits, teardown the ES cluster as well + --waitForReady Wait for the ES cluster to be ready to serve requests + -E Additional key=value settings to pass to Elasticsearch -F Absolute paths for files to mount into containers @@ -60,8 +65,8 @@ export const serverless: Command = { files: 'F', }, - string: ['tag', 'image'], - boolean: ['clean', 'ssl', 'kill', 'background'], + string: ['tag', 'image', 'basePath'], + boolean: ['clean', 'ssl', 'kill', 'background', 'teardown', 'waitForReady'], default: defaults, }) as unknown as ServerlessOptions; diff --git a/packages/kbn-es/src/cluster.ts b/packages/kbn-es/src/cluster.ts index 00cd40875208b..76c1119ab3584 100644 --- a/packages/kbn-es/src/cluster.ts +++ b/packages/kbn-es/src/cluster.ts @@ -12,7 +12,7 @@ import chalk from 'chalk'; import * as path from 'path'; import execa from 'execa'; import { Readable } from 'stream'; -import Rx from 'rxjs'; +import { combineLatest, fromEvent, first } from 'rxjs'; import { Client } from '@elastic/elasticsearch'; import { promisify } from 'util'; import { CA_CERT_PATH, ES_NOPASSWORD_P12_PATH, extract } from '@kbn/dev-utils'; @@ -46,7 +46,7 @@ import { const DEFAULT_READY_TIMEOUT = 60 * 1000; // listen to data on stream until map returns anything but undefined -const first = (stream: Readable, map: (data: Buffer) => string | true | undefined) => +const firstResult = (stream: Readable, map: (data: Buffer) => string | true | undefined) => new Promise((resolve) => { const onData = (data: any) => { const result = map(data); @@ -205,7 +205,7 @@ export class Cluster { await Promise.race([ // wait for native realm to be setup and es to be started Promise.all([ - first(this.process?.stdout!, (data: Buffer) => { + firstResult(this.process?.stdout!, (data: Buffer) => { if (/started/.test(data.toString('utf-8'))) { return true; } @@ -400,7 +400,7 @@ export class Cluster { this.setupPromise = Promise.all([ // parse log output to find http port - first(this.process.stdout!, (data: Buffer) => { + firstResult(this.process.stdout!, (data: Buffer) => { const match = data.toString('utf8').match(/HttpServer.+publish_address {[0-9.]+:([0-9]+)/); if (match) { @@ -476,11 +476,11 @@ export class Cluster { // close the stdio target if we have one defined if (this.stdioTarget) { - Rx.combineLatest([ - Rx.fromEvent(this.process.stderr!, 'end'), - Rx.fromEvent(this.process.stdout!, 'end'), + combineLatest([ + fromEvent(this.process.stderr!, 'end'), + fromEvent(this.process.stdout!, 'end'), ]) - .pipe(Rx.first()) + .pipe(first()) .subscribe(() => { this.stdioTarget?.end(); }); diff --git a/packages/kbn-es/src/integration_tests/cluster.test.ts b/packages/kbn-es/src/integration_tests/cluster.test.ts index 3d33e2f299a0a..dfe3d25f5ec65 100644 --- a/packages/kbn-es/src/integration_tests/cluster.test.ts +++ b/packages/kbn-es/src/integration_tests/cluster.test.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import fs from 'fs'; import { ToolingLog, ToolingLogCollectingWriter } from '@kbn/tooling-log'; import * as extractConfig from '../utils/extract_config_files'; import * as dockerUtils from '../utils/docker'; @@ -355,6 +356,16 @@ describe('#start(installPath)', () => { await new Cluster({ log }).start(installPath, esClusterExecOptions); }); + test(`writes logs to file when 'writeLogsToPath' is passed`, async () => { + mockEsBin({ start: true }); + const writeLogsToPath = `${KIBANA_ROOT}/es-cluster.log`; + + await new Cluster({ log }).start(installPath, { writeLogsToPath }); + + expect(logWriter.messages[0]).toContain(`and writing logs to ${writeLogsToPath}`); + expect(fs.existsSync(writeLogsToPath)).toBe(true); + }); + test('rejects if #start() was called previously', async () => { mockEsBin({ start: true }); diff --git a/packages/kbn-es/src/utils/docker.ts b/packages/kbn-es/src/utils/docker.ts index 563fd33c7a01e..00adea7e07cd6 100644 --- a/packages/kbn-es/src/utils/docker.ts +++ b/packages/kbn-es/src/utils/docker.ts @@ -626,11 +626,24 @@ export async function runServerlessCluster(log: ToolingLog, options: ServerlessO log.success('ES is ready'); } + if (options.teardown) { + // SIGINT will not trigger in FTR (see cluster.runServerless for FTR signal) + process.on('SIGINT', () => teardownServerlessClusterSync(log, options)); + } + if (!options.background) { // The ESS cluster has to be started detached, so we attach a logger afterwards for output await execa('docker', ['logs', '-f', SERVERLESS_NODES[0].name], { // inherit is required to show Docker output and Java console output for pw, enrollment token, etc stdio: ['ignore', 'inherit', 'inherit'], + }).catch((error) => { + /** + * 255 is a generic exit code which is triggered from docker logs command + * if we teardown the cluster since the entrypoint doesn't exit normally + */ + if (error.exitCode !== 255) { + log.error(error.message); + } }); } diff --git a/packages/kbn-search-response-warnings/index.ts b/packages/kbn-search-response-warnings/index.ts index 8ef18d86b9a92..d81b3510553e6 100644 --- a/packages/kbn-search-response-warnings/index.ts +++ b/packages/kbn-search-response-warnings/index.ts @@ -13,7 +13,5 @@ export { type SearchResponseWarningsProps, } from './src/components/search_response_warnings'; -export { - getSearchResponseInterceptedWarnings, - removeInterceptedWarningDuplicates, -} from './src/utils/get_search_response_intercepted_warnings'; +export { getSearchResponseInterceptedWarnings } from './src/utils/get_search_response_intercepted_warnings'; +export { hasUnsupportedDownsampledAggregationFailure } from './src/utils/has_unsupported_downsampled_aggregation_failure'; diff --git a/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts b/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts index 9fe2cf02a1671..d4110f1bb62b7 100644 --- a/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts +++ b/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts @@ -8,43 +8,33 @@ import type { SearchResponseWarning } from '@kbn/data-plugin/public'; -export const searchResponseTimeoutWarningMock: SearchResponseWarning = { - type: 'timed_out', - message: 'Data might be incomplete because your request timed out', - reason: undefined, -}; - -export const searchResponseShardFailureWarningMock: SearchResponseWarning = { - type: 'shard_failure', - message: '3 of 4 shards failed', - text: 'The data might be incomplete or wrong.', - reason: { - type: 'illegal_argument_exception', - reason: 'Field [__anonymous_] of type [boolean] does not support custom formats', - }, -}; - -export const searchResponseWarningsMock: SearchResponseWarning[] = [ - searchResponseTimeoutWarningMock, - searchResponseShardFailureWarningMock, - { - type: 'shard_failure', - message: '3 of 4 shards failed', - text: 'The data might be incomplete or wrong.', - reason: { - type: 'query_shard_exception', - reason: - 'failed to create query: [.ds-kibana_sample_data_logs-2023.07.11-000001][0] Testing shard failures!', - }, - }, - { - type: 'shard_failure', - message: '1 of 4 shards failed', - text: 'The data might be incomplete or wrong.', - reason: { - type: 'query_shard_exception', - reason: - 'failed to create query: [.ds-kibana_sample_data_logs-2023.07.11-000001][0] Testing shard failures!', +export const searchResponseIncompleteWarningLocalCluster: SearchResponseWarning = { + type: 'incomplete', + message: 'The data might be incomplete or wrong.', + clusters: { + '(local)': { + status: 'partial', + indices: '', + took: 25, + timed_out: false, + _shards: { + total: 4, + successful: 3, + skipped: 0, + failed: 1, + }, + failures: [ + { + shard: 0, + index: 'sample-01-rollup', + node: 'VFTFJxpHSdaoiGxJFLSExQ', + reason: { + type: 'illegal_argument_exception', + reason: + 'Field [kubernetes.container.memory.available.bytes] of type [aggregate_metric_double] is not supported for aggregation [percentiles]', + }, + }, + ], }, }, -]; +}; diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/__snapshots__/search_response_warnings.test.tsx.snap b/packages/kbn-search-response-warnings/src/components/search_response_warnings/__snapshots__/search_response_warnings.test.tsx.snap index 01f917a0e6dbc..079d3d9b90b06 100644 --- a/packages/kbn-search-response-warnings/src/components/search_response_warnings/__snapshots__/search_response_warnings.test.tsx.snap +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/__snapshots__/search_response_warnings.test.tsx.snap @@ -13,7 +13,7 @@ exports[`SearchResponseWarnings renders "badge" correctly 1`] = ` @@ -68,84 +68,14 @@ exports[`SearchResponseWarnings renders "callout" correctly 1`] = ` class="euiText emotion-euiText-s" data-test-subj="test1_warningTitle" > - Data might be incomplete because your request timed out -

    -
    - - -
    - -
    - -

    - - -

  • -
    -

    -

    -
    -
    -
    -
    -
    - - 3 of 4 shards failed - -
    -
    -
    -
    -

    - The data might be incomplete or wrong. -

    + The data might be incomplete or wrong.
    @@ -155,161 +85,7 @@ exports[`SearchResponseWarnings renders "callout" correctly 1`] = ` > -
    -
    -

    -

    -
  • -
  • -
    -

    -

    -
    -
    -
    -
    -
    - - 3 of 4 shards failed - -
    -
    -
    -
    -

    - The data might be incomplete or wrong. -

    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -

    -

    -
  • -
  • -
    -

    -

    -
    -
    -
    -
    -
    - - 1 of 4 shards failed - -
    -
    -
    -
    -

    - The data might be incomplete or wrong. -

    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
  • -
  • -
    -
    -
    - - 3 of 4 shards failed - -
    -
    -
    -
    -

    - The data might be incomplete or wrong. -

    -
    -
    -
    - -
    -
    -
  • -
  • -
    -
    -
    - - 3 of 4 shards failed - -
    -
    -
    -
    -

    - The data might be incomplete or wrong. -

    -
    -
    -
    - -
    -
    -
  • -
  • -
    -
    -
    - - 1 of 4 shards failed - -
    -
    -
    -
    -

    - The data might be incomplete or wrong. -

    + The data might be incomplete or wrong.
    diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.test.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.test.tsx index 6e3c1b1a0d08d..ca51bd8babee8 100644 --- a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.test.tsx +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.test.tsx @@ -9,12 +9,14 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { SearchResponseWarnings } from './search_response_warnings'; -import { searchResponseWarningsMock } from '../../__mocks__/search_response_warnings'; +import { searchResponseIncompleteWarningLocalCluster } from '../../__mocks__/search_response_warnings'; -const interceptedWarnings = searchResponseWarningsMock.map((originalWarning, index) => ({ - originalWarning, - action: originalWarning.type === 'shard_failure' ? : undefined, -})); +const interceptedWarnings = [ + { + originalWarning: searchResponseIncompleteWarningLocalCluster, + action: , + }, +]; describe('SearchResponseWarnings', () => { it('renders "callout" correctly', () => { diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx index 3c92096aa982b..8588e7275505e 100644 --- a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx @@ -270,22 +270,13 @@ function WarningContent({ groupStyles?: Partial; 'data-test-subj': string; }) { - const hasDescription = 'text' in originalWarning; - return ( - {hasDescription ? {originalWarning.message} : originalWarning.message} + {originalWarning.message} - {hasDescription ? ( - - -

    {originalWarning.text}

    -
    -
    - ) : null} {action ? {action} : null}
    ); @@ -306,6 +297,7 @@ function CalloutTitleWrapper({ onClick={onCloseCallout} type="button" iconType="cross" + color="warning" /> diff --git a/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.test.tsx b/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.test.tsx index 34ae546f42ba6..b6bf93169ae63 100644 --- a/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.test.tsx +++ b/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.test.tsx @@ -9,11 +9,8 @@ import { RequestAdapter } from '@kbn/inspector-plugin/common'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { coreMock } from '@kbn/core/public/mocks'; -import { - getSearchResponseInterceptedWarnings, - removeInterceptedWarningDuplicates, -} from './get_search_response_intercepted_warnings'; -import { searchResponseWarningsMock } from '../__mocks__/search_response_warnings'; +import { getSearchResponseInterceptedWarnings } from './get_search_response_intercepted_warnings'; +import { searchResponseIncompleteWarningLocalCluster } from '../__mocks__/search_response_warnings'; const servicesMock = { data: dataPluginMock.createStartContract(), @@ -23,162 +20,66 @@ const servicesMock = { describe('getSearchResponseInterceptedWarnings', () => { const adapter = new RequestAdapter(); - it('should catch warnings correctly', () => { + it('should return intercepted incomplete data warnings', () => { const services = { ...servicesMock, }; services.data.search.showWarnings = jest.fn((_, callback) => { // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[0], {}); - // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[1], {}); - // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[2], {}); - // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[3], {}); - - // plus duplicates - // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[0], {}); - // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[1], {}); - // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[2], {}); + callback?.(searchResponseIncompleteWarningLocalCluster, {}); }); - expect( - getSearchResponseInterceptedWarnings({ - services, - adapter, - options: { - disableShardFailureWarning: true, - }, - }) - ).toMatchInlineSnapshot(` - Array [ - Object { - "action": undefined, - "originalWarning": Object { - "message": "Data might be incomplete because your request timed out", - "reason": undefined, - "type": "timed_out", - }, - }, - Object { - "action": , - "originalWarning": Object { - "message": "3 of 4 shards failed", - "reason": Object { - "reason": "Field [__anonymous_] of type [boolean] does not support custom formats", - "type": "illegal_argument_exception", - }, - "text": "The data might be incomplete or wrong.", - "type": "shard_failure", - }, - }, - Object { - "action": , - "originalWarning": Object { - "message": "3 of 4 shards failed", - "reason": Object { - "reason": "failed to create query: [.ds-kibana_sample_data_logs-2023.07.11-000001][0] Testing shard failures!", - "type": "query_shard_exception", + const warnings = getSearchResponseInterceptedWarnings({ + services, + adapter, + }); + + expect(warnings.length).toBe(1); + expect(warnings[0].originalWarning).toEqual(searchResponseIncompleteWarningLocalCluster); + expect(warnings[0].action).toMatchInlineSnapshot(` + , - "originalWarning": Object { - "message": "1 of 4 shards failed", - "reason": Object { - "reason": "failed to create query: [.ds-kibana_sample_data_logs-2023.07.11-000001][0] Testing shard failures!", - "type": "query_shard_exception", + "failures": Array [ + Object { + "index": "sample-01-rollup", + "node": "VFTFJxpHSdaoiGxJFLSExQ", + "reason": Object { + "reason": "Field [kubernetes.container.memory.available.bytes] of type [aggregate_metric_double] is not supported for aggregation [percentiles]", + "type": "illegal_argument_exception", + }, + "shard": 0, + }, + ], + "indices": "", + "status": "partial", + "timed_out": false, + "took": 25, + }, }, - "text": "The data might be incomplete or wrong.", - "type": "shard_failure", - }, - }, - ] + "message": "The data might be incomplete or wrong.", + "type": "incomplete", + } + } + /> `); }); - - it('should not catch any warnings if disableShardFailureWarning is false', () => { - const services = { - ...servicesMock, - }; - services.data.search.showWarnings = jest.fn((_, callback) => { - // @ts-expect-error for empty meta - callback?.(searchResponseWarningsMock[0], {}); - }); - expect( - getSearchResponseInterceptedWarnings({ - services, - adapter, - options: { - disableShardFailureWarning: false, - }, - }) - ).toBeUndefined(); - }); -}); - -describe('removeInterceptedWarningDuplicates', () => { - it('should remove duplicates successfully', () => { - const interceptedWarnings = searchResponseWarningsMock.map((originalWarning) => ({ - originalWarning, - })); - - expect(removeInterceptedWarningDuplicates([interceptedWarnings[0]])).toEqual([ - interceptedWarnings[0], - ]); - expect(removeInterceptedWarningDuplicates(interceptedWarnings)).toEqual(interceptedWarnings); - expect( - removeInterceptedWarningDuplicates([...interceptedWarnings, ...interceptedWarnings]) - ).toEqual(interceptedWarnings); - }); - - it('should return undefined if the list is empty', () => { - expect(removeInterceptedWarningDuplicates([])).toBeUndefined(); - expect(removeInterceptedWarningDuplicates(undefined)).toBeUndefined(); - }); }); diff --git a/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx b/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx index 38ad0da2639f7..6518d12109a1d 100644 --- a/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx +++ b/packages/kbn-search-response-warnings/src/utils/get_search_response_intercepted_warnings.tsx @@ -7,11 +7,9 @@ */ import React from 'react'; -import { uniqBy } from 'lodash'; import { type DataPublicPluginStart, - type ShardFailureRequest, - ShardFailureOpenModalButton, + OpenIncompleteResultsModalButton, } from '@kbn/data-plugin/public'; import type { RequestAdapter } from '@kbn/inspector-plugin/common'; import type { CoreStart } from '@kbn/core-lifecycle-browser'; @@ -26,21 +24,13 @@ import type { SearchResponseInterceptedWarning } from '../types'; export const getSearchResponseInterceptedWarnings = ({ services, adapter, - options, }: { services: { data: DataPublicPluginStart; theme: CoreStart['theme']; }; adapter: RequestAdapter; - options?: { - disableShardFailureWarning?: boolean; - }; -}): SearchResponseInterceptedWarning[] | undefined => { - if (!options?.disableShardFailureWarning) { - return undefined; - } - +}): SearchResponseInterceptedWarning[] => { const interceptedWarnings: SearchResponseInterceptedWarning[] = []; services.data.search.showWarnings(adapter, (warning, meta) => { @@ -49,13 +39,13 @@ export const getSearchResponseInterceptedWarnings = ({ interceptedWarnings.push({ originalWarning: warning, action: - warning.type === 'shard_failure' && warning.text && warning.message ? ( - ({ - request: request as ShardFailureRequest, + request, response, })} color="primary" @@ -66,23 +56,5 @@ export const getSearchResponseInterceptedWarnings = ({ return true; // suppress the default behaviour }); - return removeInterceptedWarningDuplicates(interceptedWarnings); -}; - -/** - * Removes duplicated warnings - * @param interceptedWarnings - */ -export const removeInterceptedWarningDuplicates = ( - interceptedWarnings: SearchResponseInterceptedWarning[] | undefined -): SearchResponseInterceptedWarning[] | undefined => { - if (!interceptedWarnings?.length) { - return undefined; - } - - const uniqInterceptedWarnings = uniqBy(interceptedWarnings, (interceptedWarning) => - JSON.stringify(interceptedWarning.originalWarning) - ); - - return uniqInterceptedWarnings?.length ? uniqInterceptedWarnings : undefined; + return interceptedWarnings; }; diff --git a/packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.test.ts b/packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.test.ts new file mode 100644 index 0000000000000..e8d722feb131a --- /dev/null +++ b/packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.test.ts @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { hasUnsupportedDownsampledAggregationFailure } from './has_unsupported_downsampled_aggregation_failure'; + +describe('hasUnsupportedDownsampledAggregationFailure', () => { + test('should return false when unsupported_aggregation_on_downsampled_index shard failure does not exist', () => { + expect( + hasUnsupportedDownsampledAggregationFailure({ + type: 'incomplete', + message: 'The data might be incomplete or wrong.', + clusters: { + '(local)': { + status: 'partial', + indices: '', + took: 25, + timed_out: false, + _shards: { + total: 4, + successful: 3, + skipped: 0, + failed: 1, + }, + failures: [ + { + shard: 0, + index: 'sample-01-rollup', + node: 'VFTFJxpHSdaoiGxJFLSExQ', + reason: { + type: 'illegal_argument_exception', + reason: + 'Field [kubernetes.container.memory.available.bytes] of type [aggregate_metric_double] is not supported for aggregation [percentiles]', + }, + }, + ], + }, + }, + }) + ).toBe(false); + }); + + test('should return true when unsupported_aggregation_on_downsampled_index shard failure exists', () => { + expect( + hasUnsupportedDownsampledAggregationFailure({ + type: 'incomplete', + message: 'The data might be incomplete or wrong.', + clusters: { + '(local)': { + status: 'partial', + indices: '', + took: 25, + timed_out: false, + _shards: { + total: 4, + successful: 3, + skipped: 0, + failed: 1, + }, + failures: [ + { + shard: 0, + index: 'sample-01-rollup', + node: 'VFTFJxpHSdaoiGxJFLSExQ', + reason: { + type: 'unsupported_aggregation_on_downsampled_index', + reason: 'blah blah blah timeseries data', + }, + }, + ], + }, + }, + }) + ).toBe(true); + }); +}); diff --git a/packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.ts b/packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.ts new file mode 100644 index 0000000000000..d6dcd4e176498 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/utils/has_unsupported_downsampled_aggregation_failure.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { + SearchResponseWarning, + SearchResponseIncompleteWarning, +} from '@kbn/data-plugin/public'; + +export function hasUnsupportedDownsampledAggregationFailure(warning: SearchResponseWarning) { + return warning.type === 'incomplete' + ? Object.values((warning as SearchResponseIncompleteWarning).clusters).some( + (clusterDetails) => { + return clusterDetails.failures + ? clusterDetails.failures.some((shardFailure) => { + return shardFailure.reason?.type === 'unsupported_aggregation_on_downsampled_index'; + }) + : false; + } + ) + : false; +} diff --git a/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts b/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts index 75e093b047158..c64c9d7a543aa 100644 --- a/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts +++ b/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts @@ -105,6 +105,7 @@ const STANDARD_LIST_TYPES = [ 'osquery-saved-query', 'osquery-pack', 'infrastructure-ui-source', + 'metrics-data-source', 'metrics-explorer-view', 'inventory-view', 'infrastructure-monitoring-log-view', diff --git a/packages/shared-ux/chrome/navigation/mocks/src/navlinks.ts b/packages/shared-ux/chrome/navigation/mocks/src/navlinks.ts index b9b1c287dce73..c3d3b756eaae4 100644 --- a/packages/shared-ux/chrome/navigation/mocks/src/navlinks.ts +++ b/packages/shared-ux/chrome/navigation/mocks/src/navlinks.ts @@ -62,6 +62,7 @@ const allNavLinks: AppDeepLinkId[] = [ 'ml:fileUpload', 'ml:filterListsSettings', 'ml:indexDataVisualizer', + 'ml:dataComparison', 'ml:logPatternAnalysis', 'ml:logRateAnalysis', 'ml:memoryUsage', diff --git a/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap b/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap index 97d241f6c957f..f7f08fe075f56 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap +++ b/packages/shared-ux/chrome/navigation/src/ui/__snapshots__/default_navigation.test.tsx.snap @@ -469,6 +469,26 @@ Array [ "renderItem": undefined, "title": "Data view", }, + Object { + "children": undefined, + "deepLink": Object { + "baseUrl": "/mocked", + "href": "http://mocked/ml:dataComparison", + "id": "ml:dataComparison", + "title": "Deeplink ml:dataComparison", + "url": "/mocked/ml:dataComparison", + }, + "href": undefined, + "id": "ml:dataComparison", + "isActive": false, + "path": Array [ + "rootNav:ml", + "data_visualizer", + "ml:dataComparison", + ], + "renderItem": undefined, + "title": "Data comparison", + }, ], "deepLink": undefined, "href": undefined, diff --git a/src/core/server/integration_tests/http/router.test.ts b/src/core/server/integration_tests/http/router.test.ts index fdfbb76effbcf..5408aea01d373 100644 --- a/src/core/server/integration_tests/http/router.test.ts +++ b/src/core/server/integration_tests/http/router.test.ts @@ -578,7 +578,7 @@ describe('Handler', () => { ); const [message] = loggingSystemMock.collect(logger).error[0]; - expect(message).toEqual('500 Server Error - /'); + expect(message).toEqual('500 Server Error'); }); it('captures the error if handler throws', async () => { @@ -614,7 +614,7 @@ describe('Handler', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -643,7 +643,7 @@ describe('Handler', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -687,7 +687,7 @@ describe('Handler', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "400 Bad Request - /", + "400 Bad Request", Object { "http": Object { "response": Object { @@ -1171,7 +1171,7 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -1584,7 +1584,7 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -1660,7 +1660,7 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -1807,7 +1807,7 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -1840,7 +1840,7 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -1872,7 +1872,7 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { @@ -1904,7 +1904,7 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - "500 Server Error - /", + "500 Server Error", Object { "http": Object { "response": Object { diff --git a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts index 43890b88dbdb5..594c4faa9337f 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group2/check_registered_types.test.ts @@ -115,6 +115,7 @@ describe('checking migration metadata changes on all registered SO types', () => "lens-ui-telemetry": "8c47a9e393861f76e268345ecbadfc8a5fb1e0bd", "maintenance-window": "d893544460abad56ff7a0e25b78f78776dfe10d1", "map": "76c71023bd198fb6b1163b31bafd926fe2ceb9da", + "metrics-data-source": "81b69dc9830699d9ead5ac8dcb9264612e2a3c89", "metrics-explorer-view": "98cf395d0e87b89ab63f173eae16735584a8ff42", "ml-job": "150e1ab260e87f9963cc99e013304b9c54703dab", "ml-module": "2225cbb4bd508ea5f69db4b848be9d8a74b60198", diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts index 61294c22a160e..1809437f3cdcd 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts @@ -84,6 +84,7 @@ const previouslyRegisteredTypes = [ 'maintenance-window', 'map', 'maps-telemetry', + 'metrics-data-source', 'metrics-explorer-view', 'ml-job', 'ml-trained-model', diff --git a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts index 6581541e70244..636e70cd9dd9e 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts @@ -235,6 +235,7 @@ describe('split .kibana index into multiple system indices', () => { "lens-ui-telemetry", "maintenance-window", "map", + "metrics-data-source", "metrics-explorer-view", "ml-job", "ml-module", diff --git a/src/plugins/dashboard/public/dashboard_app/_dashboard_app.scss b/src/plugins/dashboard/public/dashboard_app/_dashboard_app.scss index b1333d1c90623..c89337d29e720 100644 --- a/src/plugins/dashboard/public/dashboard_app/_dashboard_app.scss +++ b/src/plugins/dashboard/public/dashboard_app/_dashboard_app.scss @@ -1,11 +1,5 @@ @import 'src/core/public/mixins'; -.dshAppWrapper { - display: flex; - flex: 1; - flex-direction: column; -} - .dshUnsavedListingItem { margin-top: $euiSizeM; } diff --git a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx index daa6c94f7f60d..f9f3efdd299f3 100644 --- a/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx +++ b/src/plugins/dashboard/public/dashboard_app/dashboard_app.tsx @@ -185,7 +185,7 @@ export function DashboardApp({ }, [dashboardAPI, kbnUrlStateStorage, savedDashboardId]); return ( -
    + <> {showNoDataPage && ( setShowNoDataPage(false)} /> )} @@ -208,6 +208,6 @@ export function DashboardApp({ /> )} -
    + ); } diff --git a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx index c85909f8881fc..5ba29031d5cb7 100644 --- a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx +++ b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.test.tsx @@ -28,6 +28,7 @@ describe('dashboard renderer', () => { mockDashboardContainer = { destroy: jest.fn(), render: jest.fn(), + select: jest.fn(), navigateToDashboard: jest.fn().mockResolvedValue({}), } as unknown as DashboardContainer; mockDashboardFactory = { @@ -143,6 +144,7 @@ describe('dashboard renderer', () => { destroy: jest.fn(), render: jest.fn(), navigateToDashboard: jest.fn(), + select: jest.fn(), } as unknown as DashboardContainer; const mockSuccessFactory = { create: jest.fn().mockReturnValue(mockSuccessEmbeddable), @@ -211,4 +213,48 @@ describe('dashboard renderer', () => { // The shared UX not found prompt should be rendered. expect(wrapper!.find(NotFoundPrompt).exists()).toBeTruthy(); }); + + test('does not add a class to the parent element when expandedPanelId is undefined', async () => { + let wrapper: ReactWrapper; + await act(async () => { + wrapper = await mountWithIntl( +
    + +
    + ); + }); + await wrapper!.update(); + + expect( + wrapper!.find('#superParent').getDOMNode().classList.contains('dshDashboardViewportWrapper') + ).toBe(false); + }); + + test('adds a class to the parent element when expandedPanelId is truthy', async () => { + const mockSuccessEmbeddable = { + destroy: jest.fn(), + render: jest.fn(), + navigateToDashboard: jest.fn(), + select: jest.fn().mockReturnValue('WhatAnExpandedPanel'), + } as unknown as DashboardContainer; + const mockSuccessFactory = { + create: jest.fn().mockReturnValue(mockSuccessEmbeddable), + } as unknown as DashboardContainerFactory; + pluginServices.getServices().embeddable.getEmbeddableFactory = jest + .fn() + .mockReturnValue(mockSuccessFactory); + + let wrapper: ReactWrapper; + await act(async () => { + wrapper = await mountWithIntl( +
    + +
    + ); + }); + + expect( + wrapper!.find('#superParent').getDOMNode().classList.contains('dshDashboardViewportWrapper') + ).toBe(true); + }); }); diff --git a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx index 0f3e1d5a08a7c..8bd064d268015 100644 --- a/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx +++ b/src/plugins/dashboard/public/dashboard_container/external_api/dashboard_renderer.tsx @@ -15,6 +15,7 @@ import React, { useEffect, forwardRef, useImperativeHandle, + useLayoutEffect, } from 'react'; import { v4 as uuidv4 } from 'uuid'; import classNames from 'classnames'; @@ -50,6 +51,7 @@ export interface DashboardRendererProps { export const DashboardRenderer = forwardRef( ({ savedObjectId, getCreationOptions, dashboardRedirect, showPlainSpinner }, ref) => { const dashboardRoot = useRef(null); + const dashboardViewport = useRef(null); const [loading, setLoading] = useState(true); const [screenshotMode, setScreenshotMode] = useState(false); const [dashboardContainer, setDashboardContainer] = useState(); @@ -170,6 +172,45 @@ export const DashboardRenderer = forwardRef; }; - return
    {renderDashboardContents()}
    ; + return ( +
    + {dashboardViewport?.current && + dashboardContainer && + !isErrorEmbeddable(dashboardContainer) && ( + + )} + {renderDashboardContents()} +
    + ); } ); + +/** + * Maximizing a panel in Dashboard only works if the parent div has a certain class. This + * small component listens to the Dashboard's expandedPanelId state and adds and removes + * the class to whichever element renders the Dashboard. + */ +const ParentClassController = ({ + dashboard, + viewportRef, +}: { + dashboard: DashboardContainer; + viewportRef: HTMLDivElement; +}) => { + const maximizedPanelId = dashboard.select((state) => state.componentState.expandedPanelId); + + useLayoutEffect(() => { + const parentDiv = viewportRef.parentElement; + if (!parentDiv) return; + + if (maximizedPanelId) { + parentDiv.classList.add('dshDashboardViewportWrapper'); + } else { + parentDiv.classList.remove('dshDashboardViewportWrapper'); + } + }, [maximizedPanelId, viewportRef.parentElement]); + return null; +}; diff --git a/src/plugins/data/common/search/aggs/agg_type.ts b/src/plugins/data/common/search/aggs/agg_type.ts index 4812ac6f07c5f..f0b2b2702dbf9 100644 --- a/src/plugins/data/common/search/aggs/agg_type.ts +++ b/src/plugins/data/common/search/aggs/agg_type.ts @@ -30,7 +30,7 @@ type PostFlightRequestFn = ( inspectorRequestAdapter?: RequestAdapter, abortSignal?: AbortSignal, searchSessionId?: string, - disableShardFailureWarning?: boolean + disableWarningToasts?: boolean ) => Promise>; export interface AggTypeConfig< diff --git a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts index 924564744962f..fb88fdbeaa4aa 100644 --- a/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts +++ b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts @@ -396,7 +396,7 @@ export const createOtherBucketPostFlightRequest = ( inspectorRequestAdapter, abortSignal, searchSessionId, - disableShardFailureWarning + disableWarningToasts ) => { if (!resp.aggregations) return resp; const nestedSearchSource = searchSource.createChild(); @@ -410,7 +410,7 @@ export const createOtherBucketPostFlightRequest = ( nestedSearchSource.fetch$({ abortSignal, sessionId: searchSessionId, - disableShardFailureWarning, + disableWarningToasts, inspector: { adapter: inspectorRequestAdapter, title: i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', { diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts index e0555fbd24076..4c42fdc985ff4 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.test.ts @@ -53,7 +53,7 @@ describe('esaggs expression function - public', () => { query: undefined, searchSessionId: 'abc123', searchSourceService: searchSourceCommonMock, - disableShardWarnings: false, + disableWarningToasts: false, timeFields: ['@timestamp', 'utc_time'], timeRange: undefined, }; @@ -139,7 +139,7 @@ describe('esaggs expression function - public', () => { description: 'This request queries Elasticsearch to fetch the data for the visualization.', adapter: undefined, }, - disableShardFailureWarning: false, + disableWarningToasts: false, }); }); @@ -159,7 +159,7 @@ describe('esaggs expression function - public', () => { description: 'MyDescription', adapter: undefined, }, - disableShardFailureWarning: false, + disableWarningToasts: false, }); }); diff --git a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts index 196ebfa55810f..7f0155d74082f 100644 --- a/src/plugins/data/common/search/expressions/esaggs/request_handler.ts +++ b/src/plugins/data/common/search/expressions/esaggs/request_handler.ts @@ -30,7 +30,7 @@ export interface RequestHandlerParams { searchSourceService: ISearchStartSearchSource; timeFields?: string[]; timeRange?: TimeRange; - disableShardWarnings?: boolean; + disableWarningToasts?: boolean; getNow?: () => Date; executionContext?: KibanaExecutionContext; title?: string; @@ -48,7 +48,7 @@ export const handleRequest = ({ searchSourceService, timeFields, timeRange, - disableShardWarnings, + disableWarningToasts, getNow, executionContext, title, @@ -110,7 +110,7 @@ export const handleRequest = ({ requestSearchSource .fetch$({ abortSignal, - disableShardFailureWarning: disableShardWarnings, + disableWarningToasts, sessionId: searchSessionId, inspector: { adapter: inspectorAdapters.requests, diff --git a/src/plugins/data/common/search/expressions/kibana_context_type.ts b/src/plugins/data/common/search/expressions/kibana_context_type.ts index cec788d27d856..d6947d2d46ce3 100644 --- a/src/plugins/data/common/search/expressions/kibana_context_type.ts +++ b/src/plugins/data/common/search/expressions/kibana_context_type.ts @@ -15,7 +15,7 @@ export type ExecutionContextSearch = { filters?: Filter[]; query?: Query | Query[]; timeRange?: TimeRange; - disableShardWarnings?: boolean; + disableWarningToasts?: boolean; }; export type ExpressionValueSearchContext = ExpressionValueBoxed< diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index b74b7e111b5ce..f05f198451e0a 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -520,7 +520,7 @@ export class SearchSource { options.inspector?.adapter, options.abortSignal, options.sessionId, - options.disableShardFailureWarning + options.disableWarningToasts ); } } diff --git a/src/plugins/data/common/search/search_source/types.ts b/src/plugins/data/common/search/search_source/types.ts index 140c2dd59a59d..60c0d3713ec64 100644 --- a/src/plugins/data/common/search/search_source/types.ts +++ b/src/plugins/data/common/search/search_source/types.ts @@ -249,7 +249,7 @@ export interface SearchSourceSearchOptions extends ISearchOptions { inspector?: IInspectorInfo; /** - * Disable default warnings of shard failures + * Set to true to disable warning toasts and customize warning display */ - disableShardFailureWarning?: boolean; + disableWarningToasts?: boolean; } diff --git a/src/plugins/data/public/incomplete_results_modal/__snapshots__/incomplete_results_modal.test.tsx.snap b/src/plugins/data/public/incomplete_results_modal/__snapshots__/incomplete_results_modal.test.tsx.snap new file mode 100644 index 0000000000000..666b87f998c3e --- /dev/null +++ b/src/plugins/data/public/incomplete_results_modal/__snapshots__/incomplete_results_modal.test.tsx.snap @@ -0,0 +1,271 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`IncompleteResultsModal should render shard failures 1`] = ` + + + + + + + + + + , + "data-test-subj": "showClusterDetailsButton", + "id": "table", + "name": "Cluster details", + } + } + tabs={ + Array [ + Object { + "content": + + , + "data-test-subj": "showClusterDetailsButton", + "id": "table", + "name": "Cluster details", + }, + Object { + "content": + {} + , + "data-test-subj": "showRequestButton", + "id": "json-request", + "name": "Request", + }, + Object { + "content": + { + "_shards": { + "total": 4, + "successful": 3, + "skipped": 0, + "failed": 1, + "failures": [ + { + "shard": 0, + "index": "sample-01-rollup", + "node": "VFTFJxpHSdaoiGxJFLSExQ", + "reason": { + "type": "illegal_argument_exception", + "reason": "Field [kubernetes.container.memory.available.bytes] of type [aggregate_metric_double] is not supported for aggregation [percentiles]" + } + } + ] + } +} + , + "data-test-subj": "showResponseButton", + "id": "json-response", + "name": "Response", + }, + ] + } + /> + + + + + + + + + + +`; + +exports[`IncompleteResultsModal should render time out 1`] = ` + + + + + + + + + +

    + Request timed out +

    +
    + , + "data-test-subj": "showClusterDetailsButton", + "id": "table", + "name": "Cluster details", + } + } + tabs={ + Array [ + Object { + "content": + +

    + Request timed out +

    +
    +
    , + "data-test-subj": "showClusterDetailsButton", + "id": "table", + "name": "Cluster details", + }, + Object { + "content": + {} + , + "data-test-subj": "showRequestButton", + "id": "json-request", + "name": "Request", + }, + Object { + "content": + { + "timed_out": true, + "_shards": { + "total": 4, + "successful": 4, + "skipped": 0, + "failed": 0 + } +} + , + "data-test-subj": "showResponseButton", + "id": "json-response", + "name": "Response", + }, + ] + } + /> +
    + + + + + + + + +
    +`; diff --git a/src/plugins/data/public/shard_failure_modal/_shard_failure_modal.scss b/src/plugins/data/public/incomplete_results_modal/_incomplete_results_modal.scss similarity index 59% rename from src/plugins/data/public/shard_failure_modal/_shard_failure_modal.scss rename to src/plugins/data/public/incomplete_results_modal/_incomplete_results_modal.scss index 33c6844719ed1..e2ca0f8f9b3b6 100644 --- a/src/plugins/data/public/shard_failure_modal/_shard_failure_modal.scss +++ b/src/plugins/data/public/incomplete_results_modal/_incomplete_results_modal.scss @@ -1,5 +1,5 @@ // set width and height to fixed values to prevent resizing when you switch tabs -.shardFailureModal { +.incompleteResultsModal { min-height: 75vh; width: 768px; @@ -12,10 +12,4 @@ .euiModalHeader { padding-bottom: 0; } -} - -.shardFailureModal__desc { - // set for IE11, since without it depending on the content the width of the list - // could be much higher than the available screenspace - max-width: 686px; -} +} \ No newline at end of file diff --git a/src/plugins/data/public/incomplete_results_modal/incomplete_results_modal.test.tsx b/src/plugins/data/public/incomplete_results_modal/incomplete_results_modal.test.tsx new file mode 100644 index 0000000000000..6e90740cf9888 --- /dev/null +++ b/src/plugins/data/public/incomplete_results_modal/incomplete_results_modal.test.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { SearchResponseIncompleteWarning } from '../search'; +import { IncompleteResultsModal } from './incomplete_results_modal'; + +describe('IncompleteResultsModal', () => { + test('should render shard failures', () => { + const component = shallow( + + } + onClose={jest.fn()} + /> + ); + + expect(component).toMatchSnapshot(); + }); + + test('should render time out', () => { + const component = shallow( + + } + onClose={jest.fn()} + /> + ); + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/data/public/incomplete_results_modal/incomplete_results_modal.tsx b/src/plugins/data/public/incomplete_results_modal/incomplete_results_modal.tsx new file mode 100644 index 0000000000000..eb07d8d60e517 --- /dev/null +++ b/src/plugins/data/public/incomplete_results_modal/incomplete_results_modal.tsx @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { + EuiCallOut, + EuiCodeBlock, + EuiTabbedContent, + EuiCopy, + EuiButton, + EuiModalBody, + EuiModalHeader, + EuiModalHeaderTitle, + EuiModalFooter, + EuiButtonEmpty, +} from '@elastic/eui'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { SearchRequest } from '..'; +import type { SearchResponseIncompleteWarning } from '../search'; +import { ShardFailureTable } from '../shard_failure_modal/shard_failure_table'; + +export interface Props { + onClose: () => void; + request: SearchRequest; + response: estypes.SearchResponse; + warning: SearchResponseIncompleteWarning; +} + +export function IncompleteResultsModal({ request, response, warning, onClose }: Props) { + const requestJSON = JSON.stringify(request, null, 2); + const responseJSON = JSON.stringify(response, null, 2); + + const tabs = [ + { + id: 'table', + name: i18n.translate( + 'data.search.searchSource.fetch.incompleteResultsModal.tabHeaderClusterDetails', + { + defaultMessage: 'Cluster details', + description: 'Name of the tab displaying cluster details', + } + ), + content: ( + <> + {response.timed_out ? ( + +

    + {i18n.translate( + 'data.search.searchSource.fetch.incompleteResultsModal.requestTimedOutMessage', + { + defaultMessage: 'Request timed out', + } + )} +

    +
    + ) : null} + + {response._shards.failures?.length ? ( + + ) : null} + + ), + ['data-test-subj']: 'showClusterDetailsButton', + }, + { + id: 'json-request', + name: i18n.translate( + 'data.search.searchSource.fetch.incompleteResultsModal.tabHeaderRequest', + { + defaultMessage: 'Request', + description: 'Name of the tab displaying the JSON request', + } + ), + content: ( + + {requestJSON} + + ), + ['data-test-subj']: 'showRequestButton', + }, + { + id: 'json-response', + name: i18n.translate( + 'data.search.searchSource.fetch.incompleteResultsModal.tabHeaderResponse', + { + defaultMessage: 'Response', + description: 'Name of the tab displaying the JSON response', + } + ), + content: ( + + {responseJSON} + + ), + ['data-test-subj']: 'showResponseButton', + }, + ]; + + return ( + + + + + + + + + + + + {(copy) => ( + + + + )} + + onClose()} fill data-test-subj="closeIncompleteResultsModal"> + + + + + ); +} diff --git a/src/plugins/data/public/shard_failure_modal/index.tsx b/src/plugins/data/public/incomplete_results_modal/index.tsx similarity index 54% rename from src/plugins/data/public/shard_failure_modal/index.tsx rename to src/plugins/data/public/incomplete_results_modal/index.tsx index f600ca4368e48..9cb02367e67a5 100644 --- a/src/plugins/data/public/shard_failure_modal/index.tsx +++ b/src/plugins/data/public/incomplete_results_modal/index.tsx @@ -7,17 +7,13 @@ */ import React from 'react'; -import type { ShardFailureOpenModalButtonProps } from './shard_failure_open_modal_button'; +import type { OpenIncompleteResultsModalButtonProps } from './open_incomplete_results_modal_button'; const Fallback = () =>
    ; -const LazyShardFailureOpenModalButton = React.lazy( - () => import('./shard_failure_open_modal_button') -); -export const ShardFailureOpenModalButton = (props: ShardFailureOpenModalButtonProps) => ( +const LazyOpenModalButton = React.lazy(() => import('./open_incomplete_results_modal_button')); +export const OpenIncompleteResultsModalButton = (props: OpenIncompleteResultsModalButtonProps) => ( }> - + ); - -export type { ShardFailureRequest } from './shard_failure_types'; diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.tsx b/src/plugins/data/public/incomplete_results_modal/open_incomplete_results_modal_button.tsx similarity index 68% rename from src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.tsx rename to src/plugins/data/public/incomplete_results_modal/open_incomplete_results_modal_button.tsx index 922aee3f49483..648eca08d525b 100644 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.tsx +++ b/src/plugins/data/public/incomplete_results_modal/open_incomplete_results_modal_button.tsx @@ -13,18 +13,19 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ThemeServiceStart } from '@kbn/core/public'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import { getOverlays } from '../services'; -import { ShardFailureModal } from './shard_failure_modal'; -import type { ShardFailureRequest } from './shard_failure_types'; -import './_shard_failure_modal.scss'; +import type { SearchRequest } from '..'; +import { IncompleteResultsModal } from './incomplete_results_modal'; +import type { SearchResponseIncompleteWarning } from '../search'; +import './_incomplete_results_modal.scss'; // @internal -export interface ShardFailureOpenModalButtonProps { +export interface OpenIncompleteResultsModalButtonProps { theme: ThemeServiceStart; - title: string; + warning: SearchResponseIncompleteWarning; size?: EuiButtonProps['size']; color?: EuiButtonProps['color']; getRequestMeta: () => { - request: ShardFailureRequest; + request: SearchRequest; response: estypes.SearchResponse; }; isButtonEmpty?: boolean; @@ -32,31 +33,31 @@ export interface ShardFailureOpenModalButtonProps { // Needed for React.lazy // eslint-disable-next-line import/no-default-export -export default function ShardFailureOpenModalButton({ +export default function OpenIncompleteResultsModalButton({ getRequestMeta, theme, - title, + warning, size = 's', color = 'warning', isButtonEmpty = false, -}: ShardFailureOpenModalButtonProps) { +}: OpenIncompleteResultsModalButtonProps) { const onClick = useCallback(() => { const { request, response } = getRequestMeta(); const modal = getOverlays().openModal( toMountPoint( - modal.close()} />, { theme$: theme.theme$ } ), { - className: 'shardFailureModal', + className: 'incompleteResultsModal', } ); - }, [getRequestMeta, theme.theme$, title]); + }, [getRequestMeta, theme.theme$, warning]); const Component = isButtonEmpty ? EuiLink : EuiButton; @@ -65,11 +66,11 @@ export default function ShardFailureOpenModalButton({ color={color} size={size} onClick={onClick} - data-test-subj="openShardFailureModalBtn" + data-test-subj="openIncompleteResultsModalBtn" > diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index d8aa9a35a29a7..48a2d9c10b71c 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -170,6 +170,7 @@ export type { Reason, WaitUntilNextSessionCompletesOptions, SearchResponseWarning, + SearchResponseIncompleteWarning, } from './search'; export { @@ -273,8 +274,7 @@ export type { } from './query'; // TODO: move to @kbn/search-response-warnings -export type { ShardFailureRequest } from './shard_failure_modal'; -export { ShardFailureOpenModalButton } from './shard_failure_modal'; +export { OpenIncompleteResultsModalButton } from './incomplete_results_modal'; export type { AggsStart } from './search/aggs'; diff --git a/src/plugins/data/public/search/expressions/esaggs.test.ts b/src/plugins/data/public/search/expressions/esaggs.test.ts index de35e0b238da9..cf3b04029a2c8 100644 --- a/src/plugins/data/public/search/expressions/esaggs.test.ts +++ b/src/plugins/data/public/search/expressions/esaggs.test.ts @@ -126,7 +126,7 @@ describe('esaggs expression function - public', () => { searchSessionId: 'abc123', searchSourceService: startDependencies.searchSource, timeFields: args.timeFields, - disableShardWarnings: false, + disableWarningToasts: false, timeRange: undefined, getNow: undefined, }); diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts index eecaa5890ba35..5ae0b72e1fe58 100644 --- a/src/plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -61,7 +61,7 @@ export function getFunctionDefinition({ return { aggConfigs, indexPattern, searchSource, getNow, handleEsaggsRequest }; }).pipe( switchMap(({ aggConfigs, indexPattern, searchSource, getNow, handleEsaggsRequest }) => { - const { disableShardWarnings } = getSearchContext(); + const { disableWarningToasts } = getSearchContext(); return handleEsaggsRequest({ abortSignal, @@ -74,7 +74,7 @@ export function getFunctionDefinition({ searchSourceService: searchSource, timeFields: args.timeFields, timeRange: get(input, 'timeRange', undefined), - disableShardWarnings: (disableShardWarnings || false) as boolean, + disableWarningToasts: (disableWarningToasts || false) as boolean, getNow, executionContext: getExecutionContext(), }); diff --git a/src/plugins/data/public/search/fetch/extract_warnings.test.ts b/src/plugins/data/public/search/fetch/extract_warnings.test.ts index 28a45ca9e6d65..fed0969c2004f 100644 --- a/src/plugins/data/public/search/fetch/extract_warnings.test.ts +++ b/src/plugins/data/public/search/fetch/extract_warnings.test.ts @@ -10,121 +10,280 @@ import { estypes } from '@elastic/elasticsearch'; import { extractWarnings } from './extract_warnings'; describe('extract search response warnings', () => { - it('should extract warnings from response with shard failures', () => { - const response = { - took: 25, - timed_out: false, - _shards: { - total: 4, - successful: 2, - skipped: 0, - failed: 2, - failures: [ - { - shard: 0, - index: 'sample-01-rollup', - node: 'VFTFJxpHSdaoiGxJFLSExQ', - reason: { - type: 'illegal_argument_exception', - reason: - 'Field [kubernetes.container.memory.available.bytes] of type [aggregate_metric_double] is not supported for aggregation [percentiles]', + describe('single cluster', () => { + it('should extract incomplete warning from response with shard failures', () => { + const response = { + took: 25, + timed_out: false, + _shards: { + total: 4, + successful: 3, + skipped: 0, + failed: 1, + failures: [ + { + shard: 0, + index: 'sample-01-rollup', + node: 'VFTFJxpHSdaoiGxJFLSExQ', + reason: { + type: 'illegal_argument_exception', + reason: + 'Field [kubernetes.container.memory.available.bytes] of type [aggregate_metric_double] is not supported for aggregation [percentiles]', + }, + }, + ], + }, + hits: { total: 18239, max_score: null, hits: [] }, + aggregations: {}, + }; + + expect(extractWarnings(response)).toEqual([ + { + type: 'incomplete', + message: 'The data might be incomplete or wrong.', + clusters: { + '(local)': { + status: 'partial', + indices: '', + took: 25, + timed_out: false, + _shards: response._shards, + failures: response._shards.failures, }, }, - ], - }, - hits: { total: 18239, max_score: null, hits: [] }, - aggregations: {}, - }; + }, + ]); + }); - expect(extractWarnings(response)).toEqual([ - { - type: 'shard_failure', - message: '2 of 4 shards failed', - reason: { - type: 'illegal_argument_exception', - reason: - 'Field [kubernetes.container.memory.available.bytes] of type' + - ' [aggregate_metric_double] is not supported for aggregation [percentiles]', + it('should extract incomplete warning from response with time out', () => { + const response = { + took: 999, + timed_out: true, + _shards: {} as estypes.ShardStatistics, + hits: { hits: [] }, + }; + expect(extractWarnings(response)).toEqual([ + { + type: 'incomplete', + message: 'The data might be incomplete or wrong.', + clusters: { + '(local)': { + status: 'partial', + indices: '', + took: 999, + timed_out: true, + _shards: response._shards, + failures: response._shards.failures, + }, + }, }, - text: 'The data might be incomplete or wrong.', - }, - ]); - }); + ]); + }); - it('should extract timeout warning', () => { - const warnings = { - took: 999, - timed_out: true, - _shards: {} as estypes.ShardStatistics, - hits: { hits: [] }, - }; - expect(extractWarnings(warnings)).toEqual([ - { - type: 'timed_out', - message: 'Data might be incomplete because your request timed out', - }, - ]); - }); + it('should not include warnings when there are none', () => { + const warnings = extractWarnings({ + timed_out: false, + _shards: { + failed: 0, + total: 9000, + }, + } as estypes.SearchResponse); - it('should extract shards failed warnings', () => { - const warnings = { - _shards: { - failed: 77, - total: 79, - }, - } as estypes.SearchResponse; - expect(extractWarnings(warnings)).toEqual([ - { - type: 'shard_failure', - message: '77 of 79 shards failed', - reason: { type: 'generic_shard_warning' }, - text: 'The data might be incomplete or wrong.', - }, - ]); + expect(warnings).toEqual([]); + }); }); - it('should extract shards failed warning failure reason type', () => { - const warnings = extractWarnings({ - _shards: { - failed: 77, - total: 79, - }, - } as estypes.SearchResponse); - expect(warnings).toEqual([ - { - type: 'shard_failure', - message: '77 of 79 shards failed', - reason: { type: 'generic_shard_warning' }, - text: 'The data might be incomplete or wrong.', - }, - ]); - }); + describe('remote clusters', () => { + it('should extract incomplete warning from response with shard failures', () => { + const response = { + took: 25, + timed_out: false, + _shards: { + total: 4, + successful: 3, + skipped: 0, + failed: 1, + failures: [ + { + shard: 0, + index: 'remote1:.ds-kibana_sample_data_logs-2023.08.21-000001', + node: 'NVzFRd6SS4qT9o0k2vIzlg', + reason: { + type: 'query_shard_exception', + reason: + 'failed to create query: [.ds-kibana_sample_data_logs-2023.08.21-000001][0] local shard failure message 123', + index_uuid: 'z1sPO8E4TdWcijNgsL_BxQ', + index: 'remote1:.ds-kibana_sample_data_logs-2023.08.21-000001', + caused_by: { + type: 'runtime_exception', + reason: + 'runtime_exception: [.ds-kibana_sample_data_logs-2023.08.21-000001][0] local shard failure message 123', + }, + }, + }, + ], + }, + _clusters: { + total: 2, + successful: 2, + skipped: 0, + details: { + '(local)': { + status: 'successful', + indices: 'kibana_sample_data_logs,kibana_sample_data_flights', + took: 1, + timed_out: false, + _shards: { + total: 2, + successful: 2, + skipped: 0, + failed: 0, + }, + }, + remote1: { + status: 'partial', + indices: 'kibana_sample_data_logs,kibana_sample_data_flights', + took: 5, + timed_out: false, + _shards: { + total: 2, + successful: 1, + skipped: 0, + failed: 1, + }, + failures: [ + { + shard: 0, + index: 'remote1:.ds-kibana_sample_data_logs-2023.08.21-000001', + node: 'NVzFRd6SS4qT9o0k2vIzlg', + reason: { + type: 'query_shard_exception', + reason: + 'failed to create query: [.ds-kibana_sample_data_logs-2023.08.21-000001][0] local shard failure message 123', + index_uuid: 'z1sPO8E4TdWcijNgsL_BxQ', + index: 'remote1:.ds-kibana_sample_data_logs-2023.08.21-000001', + caused_by: { + type: 'runtime_exception', + reason: + 'runtime_exception: [.ds-kibana_sample_data_logs-2023.08.21-000001][0] local shard failure message 123', + }, + }, + }, + ], + }, + }, + }, + hits: { total: 18239, max_score: null, hits: [] }, + aggregations: {}, + }; - it('extracts multiple warnings', () => { - const warnings = extractWarnings({ - timed_out: true, - _shards: { - failed: 77, - total: 79, - }, - } as estypes.SearchResponse); - const [shardFailures, timedOut] = [ - warnings.filter(({ type }) => type !== 'timed_out'), - warnings.filter(({ type }) => type === 'timed_out'), - ]; - expect(shardFailures[0]!.message).toBeDefined(); - expect(timedOut[0]!.message).toBeDefined(); - }); + expect(extractWarnings(response)).toEqual([ + { + type: 'incomplete', + message: 'The data might be incomplete or wrong.', + clusters: response._clusters.details, + }, + ]); + }); - it('should not include shardStats or types fields if there are no warnings', () => { - const warnings = extractWarnings({ - timed_out: false, - _shards: { - failed: 0, - total: 9000, - }, - } as estypes.SearchResponse); + it('should extract incomplete warning from response with time out', () => { + const response = { + took: 999, + timed_out: true, + _shards: { + total: 6, + successful: 6, + skipped: 0, + failed: 0, + }, + _clusters: { + total: 2, + successful: 2, + skipped: 0, + details: { + '(local)': { + status: 'successful', + indices: + 'kibana_sample_data_ecommerce,kibana_sample_data_logs,kibana_sample_data_flights', + took: 0, + timed_out: false, + _shards: { + total: 3, + successful: 3, + skipped: 0, + failed: 0, + }, + }, + remote1: { + status: 'partial', + indices: 'kibana_sample_data*', + took: 10005, + timed_out: true, + _shards: { + total: 3, + successful: 3, + skipped: 0, + failed: 0, + }, + }, + }, + }, + hits: { hits: [] }, + }; + expect(extractWarnings(response)).toEqual([ + { + type: 'incomplete', + message: 'The data might be incomplete or wrong.', + clusters: response._clusters.details, + }, + ]); + }); + + it('should not include warnings when there are none', () => { + const warnings = extractWarnings({ + took: 10, + timed_out: false, + _shards: { + total: 4, + successful: 4, + skipped: 0, + failed: 0, + }, + _clusters: { + total: 2, + successful: 2, + skipped: 0, + details: { + '(local)': { + status: 'successful', + indices: 'kibana_sample_data_logs,kibana_sample_data_flights', + took: 0, + timed_out: false, + _shards: { + total: 2, + successful: 2, + skipped: 0, + failed: 0, + }, + }, + remote1: { + status: 'successful', + indices: 'kibana_sample_data_logs,kibana_sample_data_flights', + took: 1, + timed_out: false, + _shards: { + total: 2, + successful: 2, + skipped: 0, + failed: 0, + }, + }, + }, + }, + hits: { hits: [] }, + } as estypes.SearchResponse); - expect(warnings).toEqual([]); + expect(warnings).toEqual([]); + }); }); }); diff --git a/src/plugins/data/public/search/fetch/extract_warnings.ts b/src/plugins/data/public/search/fetch/extract_warnings.ts index 7c574acba472c..34b30d5f971bf 100644 --- a/src/plugins/data/public/search/fetch/extract_warnings.ts +++ b/src/plugins/data/public/search/fetch/extract_warnings.ts @@ -8,6 +8,7 @@ import { estypes } from '@elastic/elasticsearch'; import { i18n } from '@kbn/i18n'; +import type { ClusterDetails } from '@kbn/es-types'; import { SearchResponseWarning } from '../types'; /** @@ -16,53 +17,38 @@ import { SearchResponseWarning } from '../types'; export function extractWarnings(rawResponse: estypes.SearchResponse): SearchResponseWarning[] { const warnings: SearchResponseWarning[] = []; - if (rawResponse.timed_out === true) { + const isPartial = rawResponse._clusters + ? Object.values( + ( + rawResponse._clusters as estypes.ClusterStatistics & { + details: Record; + } + ).details + ).some((clusterDetails) => clusterDetails.status !== 'successful') + : rawResponse.timed_out || rawResponse._shards.failed > 0; + if (isPartial) { warnings.push({ - type: 'timed_out', - message: i18n.translate('data.search.searchSource.fetch.requestTimedOutNotificationMessage', { - defaultMessage: 'Data might be incomplete because your request timed out', + type: 'incomplete', + message: i18n.translate('data.search.searchSource.fetch.incompleteResultsMessage', { + defaultMessage: 'The data might be incomplete or wrong.', }), - reason: undefined, // exists so that callers do not have to cast when working with shard warnings. - }); - } - - if (rawResponse._shards && rawResponse._shards.failed) { - const message = i18n.translate( - 'data.search.searchSource.fetch.shardsFailedNotificationMessage', - { - defaultMessage: '{shardsFailed} of {shardsTotal} shards failed', - values: { - shardsFailed: rawResponse._shards.failed, - shardsTotal: rawResponse._shards.total, - }, - } - ); - const text = i18n.translate( - 'data.search.searchSource.fetch.shardsFailedNotificationDescription', - { defaultMessage: 'The data might be incomplete or wrong.' } - ); - - if (rawResponse._shards.failures) { - rawResponse._shards.failures?.forEach((f) => { - warnings.push({ - type: 'shard_failure', - message, - text, - reason: { - type: f.reason.type, - reason: f.reason.reason, + clusters: rawResponse._clusters + ? ( + rawResponse._clusters as estypes.ClusterStatistics & { + details: Record; + } + ).details + : { + '(local)': { + status: 'partial', + indices: '', + took: rawResponse.took, + timed_out: rawResponse.timed_out, + _shards: rawResponse._shards, + failures: rawResponse._shards.failures, + }, }, - }); - }); - } else { - // unknown type and reason - warnings.push({ - type: 'shard_failure', - message, - text, - reason: { type: 'generic_shard_warning' }, - }); - } + }); } return warnings; diff --git a/src/plugins/data/public/search/fetch/handle_warnings.test.ts b/src/plugins/data/public/search/fetch/handle_warnings.test.ts deleted file mode 100644 index bc07eb3673991..0000000000000 --- a/src/plugins/data/public/search/fetch/handle_warnings.test.ts +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { estypes } from '@elastic/elasticsearch'; -import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; -import { themeServiceMock } from '@kbn/core/public/mocks'; -import { setNotifications } from '../../services'; -import { SearchResponseWarning } from '../types'; -import { filterWarnings, handleWarnings } from './handle_warnings'; -import * as extract from './extract_warnings'; -import { SearchRequest } from '../../../common'; - -jest.mock('@kbn/i18n', () => { - return { - i18n: { - translate: (_id: string, { defaultMessage }: { defaultMessage: string }) => defaultMessage, - }, - }; -}); -jest.mock('./extract_warnings', () => ({ - extractWarnings: jest.fn(() => []), -})); - -const theme = themeServiceMock.createStartContract(); -const warnings: SearchResponseWarning[] = [ - { - type: 'timed_out' as const, - message: 'Something timed out!', - reason: undefined, - }, - { - type: 'shard_failure' as const, - message: 'Some shards failed!', - text: 'test text', - reason: { type: 'illegal_argument_exception', reason: 'Illegal argument! Go to jail!' }, - }, - { - type: 'shard_failure' as const, - message: 'Some shards failed!', - reason: { type: 'generic_shard_failure' }, - }, -]; - -const sessionId = 'abcd'; - -describe('Filtering and showing warnings', () => { - const notifications = notificationServiceMock.createStartContract(); - jest.useFakeTimers(); - - describe('handleWarnings', () => { - const request = { body: {} }; - beforeEach(() => { - jest.resetAllMocks(); - jest.advanceTimersByTime(30000); - setNotifications(notifications); - (notifications.toasts.addWarning as jest.Mock).mockReset(); - (extract.extractWarnings as jest.Mock).mockImplementation(() => warnings); - }); - - test('should notify if timed out', () => { - (extract.extractWarnings as jest.Mock).mockImplementation(() => [warnings[0]]); - const response = { rawResponse: { timed_out: true } } as unknown as estypes.SearchResponse; - handleWarnings({ request, response, theme }); - // test debounce, addWarning should only be called once - handleWarnings({ request, response, theme }); - - expect(notifications.toasts.addWarning).toBeCalledTimes(1); - expect(notifications.toasts.addWarning).toBeCalledWith({ title: 'Something timed out!' }); - - // test debounce, call addWarning again due to sessionId - handleWarnings({ request, response, theme, sessionId }); - expect(notifications.toasts.addWarning).toBeCalledTimes(2); - }); - - test('should notify if shards failed for unknown type/reason', () => { - (extract.extractWarnings as jest.Mock).mockImplementation(() => [warnings[2]]); - const response = { - rawResponse: { _shards: { failed: 1, total: 2, successful: 1, skipped: 1 } }, - } as unknown as estypes.SearchResponse; - handleWarnings({ request, response, theme }); - // test debounce, addWarning should only be called once - handleWarnings({ request, response, theme }); - - expect(notifications.toasts.addWarning).toBeCalledTimes(1); - expect(notifications.toasts.addWarning).toBeCalledWith({ title: 'Some shards failed!' }); - - // test debounce, call addWarning again due to sessionId - handleWarnings({ request, response, theme, sessionId }); - expect(notifications.toasts.addWarning).toBeCalledTimes(2); - }); - - test('should add mount point for shard modal failure button if warning.text is provided', () => { - (extract.extractWarnings as jest.Mock).mockImplementation(() => [warnings[1]]); - const response = { - rawResponse: { _shards: { failed: 1, total: 2, successful: 1, skipped: 1 } }, - } as unknown as estypes.SearchResponse; - handleWarnings({ request, response, theme }); - // test debounce, addWarning should only be called once - handleWarnings({ request, response, theme }); - - expect(notifications.toasts.addWarning).toBeCalledTimes(1); - expect(notifications.toasts.addWarning).toBeCalledWith({ - title: 'Some shards failed!', - text: expect.any(Function), - }); - - // test debounce, call addWarning again due to sessionId - handleWarnings({ request, response, theme, sessionId }); - expect(notifications.toasts.addWarning).toBeCalledTimes(2); - }); - - test('should notify once if the response contains multiple failures', () => { - (extract.extractWarnings as jest.Mock).mockImplementation(() => [warnings[1], warnings[2]]); - const response = { - rawResponse: { _shards: { failed: 1, total: 2, successful: 1, skipped: 1 } }, - } as unknown as estypes.SearchResponse; - handleWarnings({ request, response, theme }); - - expect(notifications.toasts.addWarning).toBeCalledTimes(1); - expect(notifications.toasts.addWarning).toBeCalledWith({ - title: 'Some shards failed!', - text: expect.any(Function), - }); - }); - - test('should notify once if the response contains some unfiltered failures', () => { - const callback = (warning: SearchResponseWarning) => - warning.reason?.type !== 'generic_shard_failure'; - const response = { - rawResponse: { _shards: { failed: 1, total: 2, successful: 1, skipped: 1 } }, - } as unknown as estypes.SearchResponse; - handleWarnings({ request, response, theme, callback }); - - expect(notifications.toasts.addWarning).toBeCalledTimes(1); - expect(notifications.toasts.addWarning).toBeCalledWith({ title: 'Some shards failed!' }); - }); - - test('should not notify if the response contains no unfiltered failures', () => { - const callback = () => true; - const response = { - rawResponse: { _shards: { failed: 1, total: 2, successful: 1, skipped: 1 } }, - } as unknown as estypes.SearchResponse; - handleWarnings({ request, response, theme, callback }); - - expect(notifications.toasts.addWarning).toBeCalledTimes(0); - }); - }); - - describe('filterWarnings', () => { - const callback = jest.fn(); - const request = {} as SearchRequest; - const response = {} as estypes.SearchResponse; - - beforeEach(() => { - callback.mockImplementation(() => { - throw new Error('not initialized'); - }); - }); - - it('filters out all', () => { - callback.mockImplementation(() => true); - expect(filterWarnings(warnings, callback, request, response, 'id')).toEqual([]); - }); - - it('filters out some', () => { - callback.mockImplementation( - (warning: SearchResponseWarning) => warning.reason?.type !== 'generic_shard_failure' - ); - expect(filterWarnings(warnings, callback, request, response, 'id')).toEqual([warnings[2]]); - }); - - it('filters out none', () => { - callback.mockImplementation(() => false); - expect(filterWarnings(warnings, callback, request, response, 'id')).toEqual(warnings); - }); - }); -}); diff --git a/src/plugins/data/public/search/fetch/handle_warnings.tsx b/src/plugins/data/public/search/fetch/handle_warnings.tsx index 3e1353ee2f9a7..3380ffe0c8c99 100644 --- a/src/plugins/data/public/search/fetch/handle_warnings.tsx +++ b/src/plugins/data/public/search/fetch/handle_warnings.tsx @@ -7,49 +7,23 @@ */ import { estypes } from '@elastic/elasticsearch'; -import { debounce } from 'lodash'; -import { EuiSpacer, EuiTextAlign } from '@elastic/eui'; +import { EuiTextAlign } from '@elastic/eui'; import { ThemeServiceStart } from '@kbn/core/public'; import { toMountPoint } from '@kbn/kibana-react-plugin/public'; import React from 'react'; -import type { MountPoint } from '@kbn/core/public'; import { SearchRequest } from '..'; import { getNotifications } from '../../services'; -import { ShardFailureOpenModalButton, ShardFailureRequest } from '../../shard_failure_modal'; +import { OpenIncompleteResultsModalButton } from '../../incomplete_results_modal'; import { - SearchResponseShardFailureWarning, + SearchResponseIncompleteWarning, SearchResponseWarning, WarningHandlerCallback, } from '../types'; import { extractWarnings } from './extract_warnings'; -const getDebouncedWarning = () => { - const addWarning = () => { - const { toasts } = getNotifications(); - return debounce(toasts.addWarning.bind(toasts), 30000, { - leading: true, - }); - }; - const memory: Record> = {}; - - return ( - debounceKey: string, - title: string, - text?: string | MountPoint | undefined - ) => { - memory[debounceKey] = memory[debounceKey] || addWarning(); - return memory[debounceKey]({ title, text }); - }; -}; - -const debouncedWarningWithoutReason = getDebouncedWarning(); -const debouncedTimeoutWarning = getDebouncedWarning(); -const debouncedWarning = getDebouncedWarning(); - /** * @internal - * All warnings are expected to come from the same response. Therefore all "text" properties, which contain the - * response, will be the same. + * All warnings are expected to come from the same response. */ export function handleWarnings({ request, @@ -78,47 +52,29 @@ export function handleWarnings({ return; } - // timeout notification - const [timeout] = internal.filter((w) => w.type === 'timed_out'); - if (timeout) { - debouncedTimeoutWarning(sessionId + timeout.message, timeout.message); - } - - // shard warning failure notification - const shardFailures = internal.filter((w) => w.type === 'shard_failure'); - if (shardFailures.length === 0) { + // Incomplete data failure notification + const incompleteWarnings = internal.filter((w) => w.type === 'incomplete'); + if (incompleteWarnings.length === 0) { return; } - const [warning] = shardFailures as SearchResponseShardFailureWarning[]; - const title = warning.message; - - // if warning message contains text (warning response), show in ShardFailureOpenModalButton - if (warning.text) { - const text = toMountPoint( - <> - {warning.text} - - - ({ - request: request as ShardFailureRequest, - response, - })} - /> - - , + const [incompleteWarning] = incompleteWarnings as SearchResponseIncompleteWarning[]; + getNotifications().toasts.addWarning({ + title: incompleteWarning.message, + text: toMountPoint( + + ({ + request, + response, + })} + warning={incompleteWarning} + /> + , { theme$: theme.theme$ } - ); - - debouncedWarning(sessionId + warning.text, title, text); - return; - } - - // timeout warning, or shard warning with no failure reason - debouncedWarningWithoutReason(sessionId + title, title); + ), + }); } /** diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 46024da1096d0..fe193c867475f 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -10,6 +10,7 @@ export * from './expressions'; export type { SearchResponseWarning, + SearchResponseIncompleteWarning, ISearchSetup, ISearchStart, ISearchStartSearchSource, diff --git a/src/plugins/data/public/search/search_service.test.ts b/src/plugins/data/public/search/search_service.test.ts index c94cde6b8f747..784a41a299503 100644 --- a/src/plugins/data/public/search/search_service.test.ts +++ b/src/plugins/data/public/search/search_service.test.ts @@ -142,7 +142,7 @@ describe('Search service', () => { expect(notifications.toasts.addWarning).toBeCalledTimes(1); expect(notifications.toasts.addWarning).toBeCalledWith({ - title: '2 of 4 shards failed', + title: 'The data might be incomplete or wrong.', text: expect.any(Function), }); }); @@ -155,90 +155,6 @@ describe('Search service', () => { expect(notifications.toasts.addWarning).toBeCalledTimes(0); }); - - it('will show single notification when some warnings are filtered', () => { - callback = (warning) => warning.reason?.type === 'illegal_argument_exception'; - shards.failures = [ - { - reason: { - type: 'illegal_argument_exception', - reason: 'reason of "illegal_argument_exception"', - }, - }, - { - reason: { - type: 'other_kind_of_exception', - reason: 'reason of other_kind_of_exception', - }, - }, - { reason: { type: 'fatal_warning', reason: 'this is a fatal warning message' } }, - ] as unknown as estypes.ShardFailure[]; - - const responder = inspector.adapter.start('request1'); - responder.ok(getMockResponseWithShards(shards)); - data.showWarnings(inspector.adapter, callback); - - expect(notifications.toasts.addWarning).toBeCalledTimes(1); - expect(notifications.toasts.addWarning).toBeCalledWith({ - title: '2 of 4 shards failed', - text: expect.any(Function), - }); - }); - - it('can show a timed_out warning', () => { - const responder = inspector.adapter.start('request1'); - shards = { total: 4, successful: 4, skipped: 0, failed: 0 }; - const response1 = getMockResponseWithShards(shards); - response1.json.rawResponse.timed_out = true; - responder.ok(response1); - data.showWarnings(inspector.adapter, callback); - - expect(notifications.toasts.addWarning).toBeCalledTimes(1); - expect(notifications.toasts.addWarning).toBeCalledWith({ - title: 'Data might be incomplete because your request timed out', - }); - }); - - it('can show two warnings if response has shard failures and also timed_out', () => { - const responder = inspector.adapter.start('request1'); - const response1 = getMockResponseWithShards(shards); - response1.json.rawResponse.timed_out = true; - responder.ok(response1); - data.showWarnings(inspector.adapter, callback); - - expect(notifications.toasts.addWarning).toBeCalledTimes(2); - expect(notifications.toasts.addWarning).nthCalledWith(1, { - title: 'Data might be incomplete because your request timed out', - }); - expect(notifications.toasts.addWarning).nthCalledWith(2, { - title: '2 of 4 shards failed', - text: expect.any(Function), - }); - }); - - it('will show multiple warnings when multiple responses have shard failures', () => { - const responder1 = inspector.adapter.start('request1'); - const responder2 = inspector.adapter.start('request2'); - responder1.ok(getMockResponseWithShards(shards)); - responder2.ok({ - json: { - rawResponse: { - timed_out: true, - }, - }, - }); - - data.showWarnings(inspector.adapter, callback); - - expect(notifications.toasts.addWarning).toBeCalledTimes(2); - expect(notifications.toasts.addWarning).nthCalledWith(1, { - title: '2 of 4 shards failed', - text: expect.any(Function), - }); - expect(notifications.toasts.addWarning).nthCalledWith(2, { - title: 'Data might be incomplete because your request timed out', - }); - }); }); }); }); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 79229eaff91bf..4631425696243 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -243,7 +243,7 @@ export class SearchService implements Plugin { getConfig: uiSettings.get.bind(uiSettings), search, onResponse: (request, response, options) => { - if (!options.disableShardFailureWarning) { + if (!options.disableWarningToasts) { const { rawResponse } = response; handleWarnings({ diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index d1fde7bd4d7e6..2daceefeadb77 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -7,6 +7,7 @@ */ import { estypes } from '@elastic/elasticsearch'; +import type { ClusterDetails } from '@kbn/es-types'; import type { PackageInfo } from '@kbn/core/server'; import { DataViewsContract } from '@kbn/data-views-plugin/common'; import { RequestAdapter } from '@kbn/inspector-plugin/public'; @@ -96,63 +97,35 @@ export interface SearchServiceStartDependencies { } /** - * A warning object for a search response with internal ES timeouts + * A warning object for a search response with incomplete ES results + * ES returns incomplete results when: + * 1) Set timeout flag on search and the timeout expires on cluster + * 2) Some shard failures on a cluster + * 3) skipped remote(s) (skip_unavailable=true) + * a. all shards failed + * b. disconnected/not-connected * @public */ -export interface SearchResponseTimeoutWarning { +export interface SearchResponseIncompleteWarning { /** - * type: for sorting out timeout warnings + * type: for sorting out incomplete warnings */ - type: 'timed_out'; + type: 'incomplete'; /** * message: human-friendly message */ message: string; /** - * reason: not given for timeout. This exists so that callers do not have to cast when working with shard failure warnings. + * clusters: cluster details. */ - reason: undefined; -} - -/** - * A warning object for a search response with internal ES shard failures - * @public - */ -export interface SearchResponseShardFailureWarning { - /** - * type: for sorting out shard failure warnings - */ - type: 'shard_failure'; - /** - * message: human-friendly message - */ - message: string; - /** - * text: text to show in ShardFailureModal (optional) - */ - text?: string; - /** - * reason: ShardFailureReason from es client - */ - reason: { - /** - * type: failure code from Elasticsearch - */ - type: 'generic_shard_warning' | estypes.ShardFailure['reason']['type']; - /** - * reason: failure reason from Elasticsearch - */ - reason?: estypes.ShardFailure['reason']['reason']; - }; + clusters: Record; } /** * A warning object for a search response with warnings * @public */ -export type SearchResponseWarning = - | SearchResponseTimeoutWarning - | SearchResponseShardFailureWarning; +export type SearchResponseWarning = SearchResponseIncompleteWarning; /** * A callback function which can intercept warnings when passed to {@link showWarnings}. Pass `true` from the diff --git a/src/plugins/data/public/shard_failure_modal/__mocks__/shard_failure_request.ts b/src/plugins/data/public/shard_failure_modal/__mocks__/shard_failure_request.ts deleted file mode 100644 index c13ca9e71f48f..0000000000000 --- a/src/plugins/data/public/shard_failure_modal/__mocks__/shard_failure_request.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { ShardFailureRequest } from '../shard_failure_types'; -export const shardFailureRequest = { - version: true, - size: 500, - sort: [], - _source: { - excludes: [], - }, - stored_fields: ['*'], - script_fields: {}, - docvalue_fields: [], - query: {}, - highlight: {}, -} as ShardFailureRequest; diff --git a/src/plugins/data/public/shard_failure_modal/__mocks__/shard_failure_response.ts b/src/plugins/data/public/shard_failure_modal/__mocks__/shard_failure_response.ts index 50355a933ec5d..b45caefd5fe26 100644 --- a/src/plugins/data/public/shard_failure_modal/__mocks__/shard_failure_response.ts +++ b/src/plugins/data/public/shard_failure_modal/__mocks__/shard_failure_response.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { estypes } from '@elastic/elasticsearch'; export const shardFailureResponse: estypes.SearchResponse = { _shards: { @@ -33,4 +33,4 @@ export const shardFailureResponse: estypes.SearchResponse = { }, ], }, -} as any; +} as unknown as estypes.SearchResponse; diff --git a/src/plugins/data/public/shard_failure_modal/__snapshots__/shard_failure_description.test.tsx.snap b/src/plugins/data/public/shard_failure_modal/__snapshots__/shard_failure_description.test.tsx.snap index fbad1c1f3dc80..c8635d69e1fde 100644 --- a/src/plugins/data/public/shard_failure_modal/__snapshots__/shard_failure_description.test.tsx.snap +++ b/src/plugins/data/public/shard_failure_modal/__snapshots__/shard_failure_description.test.tsx.snap @@ -10,7 +10,6 @@ exports[`ShardFailureDescription renders matching snapshot given valid propertie grow={false} > - - - test - - - - , - "data-test-subj": "shardFailuresModalShardButton", - "id": "table", - "name": "Shard failures", - } - } - tabs={ - Array [ - Object { - "content": , - "data-test-subj": "shardFailuresModalShardButton", - "id": "table", - "name": "Shard failures", - }, - Object { - "content": - { - "version": true, - "size": 500, - "sort": [], - "_source": { - "excludes": [] - }, - "stored_fields": [ - "*" - ], - "script_fields": {}, - "docvalue_fields": [], - "query": {}, - "highlight": {} -} - , - "data-test-subj": "shardFailuresModalRequestButton", - "id": "json-request", - "name": "Request", - }, - Object { - "content": - { - "_shards": { - "total": 2, - "successful": 1, - "skipped": 0, - "failed": 1, - "failures": [ - { - "shard": 0, - "index": "repro2", - "node": "itsmeyournode", - "reason": { - "type": "script_exception", - "reason": "runtime error", - "script_stack": [ - "return doc['targetfield'].value;", - " ^---- HERE" - ], - "script": "return doc['targetfield'].value;", - "lang": "painless", - "caused_by": { - "type": "illegal_argument_exception", - "reason": "Gimme reason" - } - } - } - ] - } -} - , - "data-test-subj": "shardFailuresModalResponseButton", - "id": "json-response", - "name": "Response", - }, - ] - } - /> - - - - - - - - - - -`; diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_description.test.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_description.test.tsx index 9664ca1f9f997..23a455ac04c3c 100644 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_description.test.tsx +++ b/src/plugins/data/public/shard_failure_modal/shard_failure_description.test.tsx @@ -14,13 +14,13 @@ import { shardFailureResponse } from './__mocks__/shard_failure_response'; describe('ShardFailureDescription', () => { it('renders matching snapshot given valid properties', () => { - const failure = (shardFailureResponse._shards as any).failures[0]; + const failure = shardFailureResponse._shards.failures![0]; const component = shallowWithIntl(); expect(component).toMatchSnapshot(); }); it('should show more details when button is pressed', async () => { - const failure = (shardFailureResponse._shards as any).failures[0]; + const failure = shardFailureResponse._shards.failures![0]; const component = shallowWithIntl(); await component.find(EuiButtonEmpty).simulate('click'); expect(component).toMatchSnapshot(); diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_description.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_description.tsx index 9d78b0adf9a89..32b54a87294d3 100644 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_description.tsx +++ b/src/plugins/data/public/shard_failure_modal/shard_failure_description.tsx @@ -7,6 +7,7 @@ */ import React, { useState } from 'react'; +import { estypes } from '@elastic/elasticsearch'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; import { getFlattenedObject } from '@kbn/std'; @@ -17,7 +18,6 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import { ShardFailure } from './shard_failure_types'; /** * Provides pretty formatting of a given key string @@ -47,7 +47,7 @@ export function formatValueByKey(value: unknown, key: string): string | JSX.Elem } } -export function ShardFailureDescription(props: ShardFailure) { +export function ShardFailureDescription(props: estypes.ShardFailure) { const [showDetails, setShowDetails] = useState(false); const flattendReason = getFlattenedObject(props.reason); @@ -70,7 +70,7 @@ export function ShardFailureDescription(props: ShardFailure) { title: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.indexTitle', { defaultMessage: 'Index', }), - description: props.index, + description: props.index ?? '', }, { title: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.reasonTypeTitle', { @@ -84,7 +84,7 @@ export function ShardFailureDescription(props: ShardFailure) { title: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.nodeTitle', { defaultMessage: 'Node', }), - description: props.node, + description: props.node ?? '', }, ...reasonItems, ] @@ -99,7 +99,6 @@ export function ShardFailureDescription(props: ShardFailure) { columnWidths={[1, 6]} listItems={items} compressed - className="shardFailureModal__desc" titleProps={{ className: 'shardFailureModal__descTitle' }} descriptionProps={{ className: 'shardFailureModal__descValue' }} /> diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_modal.test.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_modal.test.tsx deleted file mode 100644 index d4b30d5a1923b..0000000000000 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_modal.test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { shallowWithIntl } from '@kbn/test-jest-helpers'; -import { ShardFailureModal } from './shard_failure_modal'; -import { shardFailureRequest } from './__mocks__/shard_failure_request'; -import { shardFailureResponse } from './__mocks__/shard_failure_response'; - -describe('ShardFailureModal', () => { - it('renders matching snapshot given valid properties', () => { - const component = shallowWithIntl( - - ); - - expect(component).toMatchSnapshot(); - }); -}); diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_modal.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_modal.tsx deleted file mode 100644 index 5dd7bebc2b77e..0000000000000 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_modal.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; -import { - EuiCodeBlock, - EuiTabbedContent, - EuiCopy, - EuiButton, - EuiModalBody, - EuiModalHeader, - EuiModalHeaderTitle, - EuiModalFooter, - EuiButtonEmpty, - EuiCallOut, -} from '@elastic/eui'; -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { ShardFailureTable } from './shard_failure_table'; -import { ShardFailureRequest } from './shard_failure_types'; - -export interface Props { - onClose: () => void; - request: ShardFailureRequest; - response: estypes.SearchResponse; - title: string; -} - -export function ShardFailureModal({ request, response, title, onClose }: Props) { - if ( - !response || - !response._shards || - !Array.isArray((response._shards as any).failures) || - !request - ) { - // this should never ever happen, but just in case - return ( - - The ShardFailureModal component received invalid properties - - ); - } - const failures = (response._shards as any).failures; - const requestJSON = JSON.stringify(request, null, 2); - const responseJSON = JSON.stringify(response, null, 2); - - const tabs = [ - { - id: 'table', - name: i18n.translate( - 'data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures', - { - defaultMessage: 'Shard failures', - description: 'Name of the tab displaying shard failures', - } - ), - content: , - ['data-test-subj']: 'shardFailuresModalShardButton', - }, - { - id: 'json-request', - name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest', { - defaultMessage: 'Request', - description: 'Name of the tab displaying the JSON request', - }), - content: ( - - {requestJSON} - - ), - ['data-test-subj']: 'shardFailuresModalRequestButton', - }, - { - id: 'json-response', - name: i18n.translate('data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse', { - defaultMessage: 'Response', - description: 'Name of the tab displaying the JSON response', - }), - content: ( - - {responseJSON} - - ), - ['data-test-subj']: 'shardFailuresModalResponseButton', - }, - ]; - - return ( - - - - {title} - - - - - - - - {(copy) => ( - - - - )} - - onClose()} fill data-test-subj="closeShardFailureModal"> - - - - - ); -} diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.test.mocks.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.test.mocks.tsx deleted file mode 100644 index 948905cf1ce90..0000000000000 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.test.mocks.tsx +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { setOverlays } from '../services'; -import { OverlayStart } from '@kbn/core/public'; - -export const openModal = jest.fn(); - -setOverlays({ - openModal, -} as unknown as OverlayStart); diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.test.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.test.tsx deleted file mode 100644 index 00f0315e69275..0000000000000 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_open_modal_button.test.tsx +++ /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 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 { openModal } from './shard_failure_open_modal_button.test.mocks'; -import React from 'react'; -import { themeServiceMock } from '@kbn/core/public/mocks'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import ShardFailureOpenModalButton from './shard_failure_open_modal_button'; -import { shardFailureRequest } from './__mocks__/shard_failure_request'; -import { shardFailureResponse } from './__mocks__/shard_failure_response'; -import { findTestSubject } from '@elastic/eui/lib/test'; - -const theme = themeServiceMock.createStartContract(); - -describe('ShardFailureOpenModalButton', () => { - it('triggers the openModal function when "Show details" button is clicked', () => { - const component = mountWithIntl( - ({ - request: shardFailureRequest, - response: shardFailureResponse, - })} - theme={theme} - title="test" - /> - ); - findTestSubject(component, 'openShardFailureModalBtn').simulate('click'); - expect(openModal).toHaveBeenCalled(); - }); -}); diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_table.test.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_table.test.tsx index c4a53f850ab6a..567ad8ff80ac2 100644 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_table.test.tsx +++ b/src/plugins/data/public/shard_failure_modal/shard_failure_table.test.tsx @@ -10,12 +10,12 @@ import React from 'react'; import { shallowWithIntl } from '@kbn/test-jest-helpers'; import { ShardFailureTable } from './shard_failure_table'; import { shardFailureResponse } from './__mocks__/shard_failure_response'; -import { ShardFailure } from './shard_failure_types'; describe('ShardFailureTable', () => { it('renders matching snapshot given valid properties', () => { - const failures = (shardFailureResponse._shards as any).failures as ShardFailure[]; - const component = shallowWithIntl(); + const component = shallowWithIntl( + + ); expect(component).toMatchSnapshot(); }); }); diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_table.tsx b/src/plugins/data/public/shard_failure_modal/shard_failure_table.tsx index ab9c376157100..cb4fed32f11eb 100644 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_table.tsx +++ b/src/plugins/data/public/shard_failure_modal/shard_failure_table.tsx @@ -7,13 +7,13 @@ */ import React from 'react'; +import { estypes } from '@elastic/elasticsearch'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; import { EuiInMemoryTable, EuiInMemoryTableProps, euiScreenReaderOnly } from '@elastic/eui'; import { ShardFailureDescription } from './shard_failure_description'; -import { ShardFailure } from './shard_failure_types'; -export interface ListItem extends ShardFailure { +export interface ListItem extends estypes.ShardFailure { id: string; } @@ -24,7 +24,7 @@ const SORTING: EuiInMemoryTableProps['sorting'] = { }, }; -export function ShardFailureTable({ failures }: { failures: ShardFailure[] }) { +export function ShardFailureTable({ failures }: { failures: estypes.ShardFailure[] }) { const itemList = failures.map((failure, idx) => ({ ...{ id: String(idx) }, ...failure })); const columns = [ diff --git a/src/plugins/data/public/shard_failure_modal/shard_failure_types.ts b/src/plugins/data/public/shard_failure_modal/shard_failure_types.ts deleted file mode 100644 index c6533f9f0a850..0000000000000 --- a/src/plugins/data/public/shard_failure_modal/shard_failure_types.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -export interface ShardFailureRequest { - docvalue_fields: string[]; - _source: unknown; - query: unknown; - script_fields: unknown; - sort: unknown; - stored_fields: string[]; -} - -export interface ShardFailure { - index: string; - node: string; - reason: { - caused_by: { - reason: string; - type: string; - }; - reason: string; - lang?: estypes.ScriptLanguage; - script?: string; - script_stack?: string[]; - type: string; - }; - shard: number; -} diff --git a/src/plugins/data/server/search/expressions/esaggs.test.ts b/src/plugins/data/server/search/expressions/esaggs.test.ts index 9954fb2457968..da903f6ff7101 100644 --- a/src/plugins/data/server/search/expressions/esaggs.test.ts +++ b/src/plugins/data/server/search/expressions/esaggs.test.ts @@ -131,7 +131,7 @@ describe('esaggs expression function - server', () => { query: undefined, searchSessionId: 'abc123', searchSourceService: startDependencies.searchSource, - disableShardWarnings: false, + disableWarningToasts: false, timeFields: args.timeFields, timeRange: undefined, }); diff --git a/src/plugins/data/server/search/expressions/esaggs.ts b/src/plugins/data/server/search/expressions/esaggs.ts index eedd1db8d0308..2e1afc0350957 100644 --- a/src/plugins/data/server/search/expressions/esaggs.ts +++ b/src/plugins/data/server/search/expressions/esaggs.ts @@ -72,7 +72,7 @@ export function getFunctionDefinition({ query: get(input, 'query', undefined) as any, searchSessionId: getSearchSessionId(), searchSourceService: searchSource, - disableShardWarnings: false, + disableWarningToasts: false, timeFields: args.timeFields, timeRange: get(input, 'timeRange', undefined), }) diff --git a/src/plugins/data/tsconfig.json b/src/plugins/data/tsconfig.json index 9d46f36ffd29c..81820900557d7 100644 --- a/src/plugins/data/tsconfig.json +++ b/src/plugins/data/tsconfig.json @@ -49,7 +49,8 @@ "@kbn/core-saved-objects-server", "@kbn/core-saved-objects-utils-server", "@kbn/data-service", - "@kbn/react-kibana-context-render" + "@kbn/react-kibana-context-render", + "@kbn/es-types" ], "exclude": [ "target/**/*", diff --git a/src/plugins/discover/common/constants.ts b/src/plugins/discover/common/constants.ts index e80f9d2449ebc..8ac1280592ff6 100644 --- a/src/plugins/discover/common/constants.ts +++ b/src/plugins/discover/common/constants.ts @@ -17,7 +17,6 @@ export enum VIEW_MODE { AGGREGATED_LEVEL = 'aggregated', } -export const DISABLE_SHARD_FAILURE_WARNING = true; export const getDefaultRowsPerPage = (uiSettings: IUiSettingsClient): number => { return parseInt(uiSettings.get(SAMPLE_ROWS_PER_PAGE_SETTING), 10) || DEFAULT_ROWS_PER_PAGE; }; diff --git a/src/plugins/discover/kibana.jsonc b/src/plugins/discover/kibana.jsonc index 0778ebf666851..4a46dd14d689f 100644 --- a/src/plugins/discover/kibana.jsonc +++ b/src/plugins/discover/kibana.jsonc @@ -38,7 +38,8 @@ "savedObjectsTaggingOss", "lens", "serverless", - "noDataPage" + "noDataPage", + "globalSearch" ], "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedSearch"], "extraPublicDirs": ["common"] diff --git a/src/plugins/discover/public/__mocks__/data_view_no_timefield.ts b/src/plugins/discover/public/__mocks__/data_view_no_timefield.ts new file mode 100644 index 0000000000000..ebfc810f1de28 --- /dev/null +++ b/src/plugins/discover/public/__mocks__/data_view_no_timefield.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DataView } from '@kbn/data-views-plugin/public'; +import { buildDataViewMock } from '@kbn/discover-utils/src/__mocks__'; + +const fields = [ + { + name: '_index', + type: 'string', + scripted: false, + filterable: true, + }, + { + name: 'message', + displayName: 'message', + type: 'string', + scripted: false, + filterable: false, + }, + { + name: 'extension', + displayName: 'extension', + type: 'string', + scripted: false, + filterable: true, + aggregatable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + scripted: false, + filterable: true, + aggregatable: true, + }, + { + name: 'scripted', + displayName: 'scripted', + type: 'number', + scripted: true, + filterable: false, + }, +] as DataView['fields']; + +export const dataViewWithNoTimefieldMock = buildDataViewMock({ + name: 'index-pattern-with-timefield', + fields, +}); diff --git a/src/plugins/discover/public/application/context/context_app.tsx b/src/plugins/discover/public/application/context/context_app.tsx index 355c82417f632..de1e0a23c4df2 100644 --- a/src/plugins/discover/public/application/context/context_app.tsx +++ b/src/plugins/discover/public/application/context/context_app.tsx @@ -18,7 +18,6 @@ import { useExecutionContext } from '@kbn/kibana-react-plugin/public'; import { generateFilters } from '@kbn/data-plugin/public'; import { i18n } from '@kbn/i18n'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; -import { removeInterceptedWarningDuplicates } from '@kbn/search-response-warnings'; import { DOC_TABLE_LEGACY, SEARCH_FIELDS_FROM_SOURCE, @@ -177,12 +176,11 @@ export const ContextApp = ({ dataView, anchorId, referrer }: ContextAppProps) => ); const interceptedWarnings = useMemo( - () => - removeInterceptedWarningDuplicates([ - ...(fetchedState.predecessorsInterceptedWarnings || []), - ...(fetchedState.anchorInterceptedWarnings || []), - ...(fetchedState.successorsInterceptedWarnings || []), - ]), + () => [ + ...(fetchedState.predecessorsInterceptedWarnings || []), + ...(fetchedState.anchorInterceptedWarnings || []), + ...(fetchedState.successorsInterceptedWarnings || []), + ], [ fetchedState.predecessorsInterceptedWarnings, fetchedState.anchorInterceptedWarnings, diff --git a/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.test.tsx b/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.test.tsx index 9ff64165f0f24..db0243e7f4ccf 100644 --- a/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.test.tsx +++ b/src/plugins/discover/public/application/context/hooks/use_context_app_fetch.test.tsx @@ -19,15 +19,15 @@ import { mockSuccessorHits, } from '../__mocks__/use_context_app_fetch'; import { dataViewWithTimefieldMock } from '../../../__mocks__/data_view_with_timefield'; -import { searchResponseWarningsMock } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; +import { searchResponseIncompleteWarningLocalCluster } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; import { createContextSearchSourceStub } from '../services/_stubs'; import { DataView } from '@kbn/data-views-plugin/public'; import { themeServiceMock } from '@kbn/core/public/mocks'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -const mockInterceptedWarnings = searchResponseWarningsMock.map((originalWarning) => ({ - originalWarning, -})); +const mockInterceptedWarning = { + originalWarning: searchResponseIncompleteWarningLocalCluster, +}; const mockFilterManager = createFilterManagerMock(); @@ -44,9 +44,7 @@ jest.mock('../services/context', () => { } return { rows: type === 'predecessors' ? mockPredecessorHits : mockSuccessorHits, - interceptedWarnings: mockOverrideInterceptedWarnings - ? [mockInterceptedWarnings[type === 'predecessors' ? 0 : 1]] - : undefined, + interceptedWarnings: mockOverrideInterceptedWarnings ? [mockInterceptedWarning] : undefined, }; }, }; @@ -59,9 +57,7 @@ jest.mock('../services/anchor', () => ({ } return { anchorRow: mockAnchorHit, - interceptedWarnings: mockOverrideInterceptedWarnings - ? [mockInterceptedWarnings[2]] - : undefined, + interceptedWarnings: mockOverrideInterceptedWarnings ? [mockInterceptedWarning] : undefined, }; }, })); @@ -228,13 +224,11 @@ describe('test useContextAppFetch', () => { expect(result.current.fetchedState.predecessors).toEqual(mockPredecessorHits); expect(result.current.fetchedState.successors).toEqual(mockSuccessorHits); expect(result.current.fetchedState.predecessorsInterceptedWarnings).toEqual([ - mockInterceptedWarnings[0], + mockInterceptedWarning, ]); expect(result.current.fetchedState.successorsInterceptedWarnings).toEqual([ - mockInterceptedWarnings[1], - ]); - expect(result.current.fetchedState.anchorInterceptedWarnings).toEqual([ - mockInterceptedWarnings[2], + mockInterceptedWarning, ]); + expect(result.current.fetchedState.anchorInterceptedWarnings).toEqual([mockInterceptedWarning]); }); }); diff --git a/src/plugins/discover/public/application/context/services/anchor.test.ts b/src/plugins/discover/public/application/context/services/anchor.test.ts index 415b468f38afd..deb5a0ed5ca7a 100644 --- a/src/plugins/discover/public/application/context/services/anchor.test.ts +++ b/src/plugins/discover/public/application/context/services/anchor.test.ts @@ -10,7 +10,7 @@ import { SortDirection } from '@kbn/data-plugin/public'; import { createSearchSourceStub } from './_stubs'; import { fetchAnchor, updateSearchSource } from './anchor'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { searchResponseTimeoutWarningMock } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; +import { searchResponseIncompleteWarningLocalCluster } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; import { savedSearchMock } from '../../../__mocks__/saved_search'; import { discoverServiceMock } from '../../../__mocks__/services'; @@ -206,7 +206,7 @@ describe('context app', function () { ).then(({ anchorRow, interceptedWarnings }) => { expect(anchorRow).toHaveProperty('raw._id', '1'); expect(anchorRow).toHaveProperty('isAnchor', true); - expect(interceptedWarnings).toBeUndefined(); + expect(interceptedWarnings).toEqual([]); }); }); @@ -216,20 +216,10 @@ describe('context app', function () { { _id: '3', _index: 't' }, ]); - const mockWarnings = [ - { - originalWarning: searchResponseTimeoutWarningMock, - }, - ]; - const services = discoverServiceMock; services.data.search.showWarnings = jest.fn((adapter, callback) => { // @ts-expect-error for empty meta - callback?.(mockWarnings[0].originalWarning, {}); - - // plus duplicates - // @ts-expect-error for empty meta - callback?.(mockWarnings[0].originalWarning, {}); + callback?.(searchResponseIncompleteWarningLocalCluster, {}); }); return fetchAnchor( @@ -242,7 +232,7 @@ describe('context app', function () { ).then(({ anchorRow, interceptedWarnings }) => { expect(anchorRow).toHaveProperty('raw._id', '1'); expect(anchorRow).toHaveProperty('isAnchor', true); - expect(interceptedWarnings).toEqual(mockWarnings); + expect(interceptedWarnings?.length).toBe(1); }); }); }); diff --git a/src/plugins/discover/public/application/context/services/anchor.ts b/src/plugins/discover/public/application/context/services/anchor.ts index daf99030201a4..f5d0f78a83441 100644 --- a/src/plugins/discover/public/application/context/services/anchor.ts +++ b/src/plugins/discover/public/application/context/services/anchor.ts @@ -17,7 +17,6 @@ import { type SearchResponseInterceptedWarning, } from '@kbn/search-response-warnings'; import type { DiscoverServices } from '../../../build_services'; -import { DISABLE_SHARD_FAILURE_WARNING } from '../../../../common/constants'; export async function fetchAnchor( anchorId: string, @@ -35,7 +34,7 @@ export async function fetchAnchor( const adapter = new RequestAdapter(); const { rawResponse } = await lastValueFrom( searchSource.fetch$({ - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, + disableWarningToasts: true, inspector: { adapter, title: 'anchor', @@ -56,9 +55,6 @@ export async function fetchAnchor( interceptedWarnings: getSearchResponseInterceptedWarnings({ services, adapter, - options: { - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, - }, }), }; } diff --git a/src/plugins/discover/public/application/context/services/context.successors.test.ts b/src/plugins/discover/public/application/context/services/context.successors.test.ts index 9c2a0120c2a72..54037a7071f06 100644 --- a/src/plugins/discover/public/application/context/services/context.successors.test.ts +++ b/src/plugins/discover/public/application/context/services/context.successors.test.ts @@ -16,6 +16,7 @@ import { Query } from '@kbn/es-query'; import { fetchSurroundingDocs, SurrDocType } from './context'; import { buildDataTableRecord, buildDataTableRecordList } from '@kbn/discover-utils'; import { discoverServiceMock } from '../../../__mocks__/services'; +import { searchResponseIncompleteWarningLocalCluster } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; const MS_PER_DAY = 24 * 60 * 60 * 1000; const ANCHOR_TIMESTAMP = new Date(MS_PER_DAY).toJSON(); @@ -257,28 +258,13 @@ describe('context successors', function () { const removeFieldsSpy = mockSearchSource.removeField.withArgs('fieldsFromSource'); expect(removeFieldsSpy.calledOnce).toBe(true); expect(setFieldsSpy.calledOnce).toBe(true); - expect(interceptedWarnings).toBeUndefined(); + expect(interceptedWarnings).toEqual([]); } ); }); }); describe('function fetchSuccessors with shard failures', function () { - const mockWarnings = [ - { - originalWarning: { - message: 'Data might be incomplete because your request timed out 1', - type: 'timed_out', - }, - }, - { - originalWarning: { - message: 'Data might be incomplete because your request timed out 2', - type: 'timed_out', - }, - }, - ]; - beforeEach(() => { mockSearchSource = createContextSearchSourceStub('@timestamp'); @@ -288,11 +274,7 @@ describe('context successors', function () { createEmpty: jest.fn().mockImplementation(() => mockSearchSource), }, showWarnings: jest.fn((adapter, callback) => { - callback(mockWarnings[0].originalWarning, {}); - callback(mockWarnings[1].originalWarning, {}); - // plus duplicates - callback(mockWarnings[0].originalWarning, {}); - callback(mockWarnings[1].originalWarning, {}); + callback(searchResponseIncompleteWarningLocalCluster, {}); }), }, } as unknown as DataPublicPluginStart; @@ -345,7 +327,7 @@ describe('context successors', function () { buildDataTableRecordList(mockSearchSource._stubHits.slice(-3), dataView) ); expect(dataPluginMock.search.showWarnings).toHaveBeenCalledTimes(1); - expect(interceptedWarnings).toEqual(mockWarnings); + expect(interceptedWarnings?.length).toBe(1); } ); }); diff --git a/src/plugins/discover/public/application/context/services/context.ts b/src/plugins/discover/public/application/context/services/context.ts index df47356394821..67a477a8b9a03 100644 --- a/src/plugins/discover/public/application/context/services/context.ts +++ b/src/plugins/discover/public/application/context/services/context.ts @@ -9,10 +9,7 @@ import type { Filter } from '@kbn/es-query'; import { DataView } from '@kbn/data-views-plugin/public'; import { DataPublicPluginStart, ISearchSource } from '@kbn/data-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { - removeInterceptedWarningDuplicates, - type SearchResponseInterceptedWarning, -} from '@kbn/search-response-warnings'; +import type { SearchResponseInterceptedWarning } from '@kbn/search-response-warnings'; import { reverseSortDir, SortDirection } from '../utils/sorting'; import { convertIsoToMillis, extractNanos } from '../utils/date_conversion'; import { fetchHitsInInterval } from '../utils/fetch_hits_in_interval'; @@ -126,7 +123,7 @@ export async function fetchSurroundingDocs( return { rows, - interceptedWarnings: removeInterceptedWarningDuplicates(interceptedWarnings), + interceptedWarnings, }; } diff --git a/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts b/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts index c6fed56de4c19..d9a06e08fbada 100644 --- a/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts +++ b/src/plugins/discover/public/application/context/utils/fetch_hits_in_interval.ts @@ -17,7 +17,6 @@ import { import { RequestAdapter } from '@kbn/inspector-plugin/common'; import { convertTimeValueToIso } from './date_conversion'; import { IntervalValue } from './generate_intervals'; -import { DISABLE_SHARD_FAILURE_WARNING } from '../../../../common/constants'; import type { SurrDocType } from '../services/context'; import type { DiscoverServices } from '../../../build_services'; @@ -91,7 +90,7 @@ export async function fetchHitsInInterval( .setField('sort', sort) .setField('version', true) .fetch$({ - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, + disableWarningToasts: true, inspector: { adapter, title: type, @@ -107,9 +106,6 @@ export async function fetchHitsInInterval( interceptedWarnings: getSearchResponseInterceptedWarnings({ services, adapter, - options: { - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, - }, }), }; } diff --git a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx index 53e35d207507c..ae73126afde88 100644 --- a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx +++ b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.test.tsx @@ -173,6 +173,12 @@ describe('useDiscoverHistogram', () => { 'totalHitsResult', ]); }); + + it('should return the isChartLoading params for text based languages', async () => { + const { hook } = await renderUseDiscoverHistogram({ isPlainRecord: true }); + const isChartLoading = hook.result.current.isChartLoading; + expect(isChartLoading).toBe(false); + }); }); describe('state', () => { @@ -390,6 +396,26 @@ describe('useDiscoverHistogram', () => { }); expect(mockCheckHitCount).not.toHaveBeenCalled(); }); + + it('should set isChartLoading to true for fetch start', async () => { + const fetch$ = new Subject<{ + options: { + reset: boolean; + fetchMore: boolean; + }; + searchSessionId: string; + }>(); + const stateContainer = getStateContainer(); + stateContainer.dataState.fetch$ = fetch$; + const { hook } = await renderUseDiscoverHistogram({ stateContainer, isPlainRecord: true }); + act(() => { + fetch$.next({ + options: { reset: false, fetchMore: false }, + searchSessionId: '1234', + }); + }); + expect(hook.result.current.isChartLoading).toBe(true); + }); }); describe('refetching', () => { diff --git a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts index 68d821580f5a4..764145d72aac1 100644 --- a/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts +++ b/src/plugins/discover/public/application/main/components/layout/use_discover_histogram.ts @@ -59,6 +59,7 @@ export const useDiscoverHistogram = ({ */ const [unifiedHistogram, ref] = useState(); + const [isSuggestionLoading, setIsSuggestionLoading] = useState(false); const getCreationOptions = useCallback(() => { const { @@ -243,6 +244,26 @@ export const useDiscoverHistogram = ({ columns: savedSearchData$.documents$.getValue().textBasedQueryColumns ?? [], }); + useEffect(() => { + if (!isPlainRecord) { + return; + } + + const fetchStart = stateContainer.dataState.fetch$.subscribe(() => { + if (!skipRefetch.current) { + setIsSuggestionLoading(true); + } + }); + const fetchComplete = textBasedFetchComplete$.subscribe(() => { + setIsSuggestionLoading(false); + }); + + return () => { + fetchStart.unsubscribe(); + fetchComplete.unsubscribe(); + }; + }, [isPlainRecord, stateContainer.dataState.fetch$, textBasedFetchComplete$]); + /** * Data fetching */ @@ -319,6 +340,7 @@ export const useDiscoverHistogram = ({ onBrushEnd: histogramCustomization?.onBrushEnd, withDefaultActions: histogramCustomization?.withDefaultActions, disabledActions: histogramCustomization?.disabledActions, + isChartLoading: isSuggestionLoading, }; }; diff --git a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx index 2b406e6a45682..ef2a6fb9ad28b 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx @@ -53,6 +53,7 @@ export const getTopNavLinks = ({ services, stateContainer: state, adHocDataViews, + isPlainRecord, }); }, testId: 'discoverAlertsButton', @@ -232,7 +233,6 @@ export const getTopNavLinks = ({ if ( services.triggersActionsUi && services.capabilities.management?.insightsAndAlerting?.triggersActions && - !isPlainRecord && !defaultMenu?.alertsItem?.disabled ) { entries.push({ data: alerts, order: defaultMenu?.alertsItem?.order ?? 400 }); diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.test.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.test.tsx index 03e5712df5e2e..bea933950200d 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.test.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.test.tsx @@ -13,10 +13,11 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { AlertsPopover } from './open_alerts_popover'; import { discoverServiceMock } from '../../../../__mocks__/services'; import { dataViewWithTimefieldMock } from '../../../../__mocks__/data_view_with_timefield'; +import { dataViewWithNoTimefieldMock } from '../../../../__mocks__/data_view_no_timefield'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; import { getDiscoverStateMock } from '../../../../__mocks__/discover_state.mock'; -const mount = (dataView = dataViewMock) => { +const mount = (dataView = dataViewMock, isPlainRecord = false) => { const stateContainer = getDiscoverStateMock({ isTimeBased: true }); stateContainer.actions.setDataView(dataView); return mountWithIntl( @@ -25,6 +26,7 @@ const mount = (dataView = dataViewMock) => { stateContainer={stateContainer} anchorElement={document.createElement('div')} adHocDataViews={[]} + isPlainRecord={isPlainRecord} services={discoverServiceMock} onClose={jest.fn()} /> @@ -33,18 +35,42 @@ const mount = (dataView = dataViewMock) => { }; describe('OpenAlertsPopover', () => { - it('should render with the create search threshold rule button disabled if the data view has no time field', () => { - const component = mount(); - expect(findTestSubject(component, 'discoverCreateAlertButton').prop('disabled')).toBeTruthy(); - }); + describe('Dataview mode', () => { + it('should render with the create search threshold rule button disabled if the data view has no time field', () => { + const component = mount(); + expect(findTestSubject(component, 'discoverCreateAlertButton').prop('disabled')).toBeTruthy(); + }); + + it('should render with the create search threshold rule button enabled if the data view has a time field', () => { + const component = mount(dataViewWithTimefieldMock); + expect(findTestSubject(component, 'discoverCreateAlertButton').prop('disabled')).toBeFalsy(); + }); - it('should render with the create search threshold rule button enabled if the data view has a time field', () => { - const component = mount(dataViewWithTimefieldMock); - expect(findTestSubject(component, 'discoverCreateAlertButton').prop('disabled')).toBeFalsy(); + it('should render the manage rules and connectors link', () => { + const component = mount(); + expect(findTestSubject(component, 'discoverManageAlertsButton').exists()).toBeTruthy(); + }); }); - it('should render the manage rules and connectors link', () => { - const component = mount(); - expect(findTestSubject(component, 'discoverManageAlertsButton').exists()).toBeTruthy(); + describe('ES|QL mode', () => { + it('should render with the create search threshold rule button enabled if the data view has no timeFieldName but at least one time field', () => { + const component = mount(dataViewMock, true); + expect(findTestSubject(component, 'discoverCreateAlertButton').prop('disabled')).toBeFalsy(); + }); + + it('should render with the create search threshold rule button enabled if the data view has a time field', () => { + const component = mount(dataViewWithTimefieldMock, true); + expect(findTestSubject(component, 'discoverCreateAlertButton').prop('disabled')).toBeFalsy(); + }); + + it('should render with the create search threshold rule button disabled if the data view has no time fields at all', () => { + const component = mount(dataViewWithNoTimefieldMock, true); + expect(findTestSubject(component, 'discoverCreateAlertButton').prop('disabled')).toBeTruthy(); + }); + + it('should render the manage rules and connectors link', () => { + const component = mount(); + expect(findTestSubject(component, 'discoverManageAlertsButton').exists()).toBeTruthy(); + }); }); }); diff --git a/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.tsx b/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.tsx index 75202710945dd..2993193ccc2bf 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/open_alerts_popover.tsx @@ -28,6 +28,7 @@ interface AlertsPopoverProps { savedQueryId?: string; adHocDataViews: DataView[]; services: DiscoverServices; + isPlainRecord?: boolean; } interface EsQueryAlertMetaData { @@ -41,8 +42,13 @@ export function AlertsPopover({ services, stateContainer, onClose: originalOnClose, + isPlainRecord, }: AlertsPopoverProps) { const dataView = stateContainer.internalState.getState().dataView; + const query = stateContainer.appState.getState().query; + const dateFields = dataView?.fields.getByType('date'); + const timeField = dataView?.timeFieldName || dateFields?.[0]?.name; + const { triggersActionsUi } = services; const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); const onClose = useCallback(() => { @@ -54,6 +60,13 @@ export function AlertsPopover({ * Provides the default parameters used to initialize the new rule */ const getParams = useCallback(() => { + if (isPlainRecord) { + return { + searchType: 'esqlQuery', + esqlQuery: query, + timeField, + }; + } const savedQueryId = stateContainer.appState.getState().savedQuery; return { searchType: 'searchSource', @@ -62,7 +75,7 @@ export function AlertsPopover({ .searchSource.getSerializedFields(), savedQueryId, }; - }, [stateContainer]); + }, [isPlainRecord, stateContainer.appState, stateContainer.savedSearchState, query, timeField]); const discoverMetadata: EsQueryAlertMetaData = useMemo( () => ({ @@ -98,7 +111,14 @@ export function AlertsPopover({ }); }, [alertFlyoutVisible, triggersActionsUi, discoverMetadata, getParams, onClose, stateContainer]); - const hasTimeFieldName = Boolean(dataView?.timeFieldName); + const hasTimeFieldName: boolean = useMemo(() => { + if (!isPlainRecord) { + return Boolean(dataView?.timeFieldName); + } else { + return Boolean(timeField); + } + }, [dataView?.timeFieldName, isPlainRecord, timeField]); + const panels = [ { id: 'mainPanel', @@ -165,11 +185,13 @@ export function openAlertsPopover({ stateContainer, services, adHocDataViews, + isPlainRecord, }: { anchorElement: HTMLElement; stateContainer: DiscoverStateContainer; services: DiscoverServices; adHocDataViews: DataView[]; + isPlainRecord?: boolean; }) { if (isOpen) { closeAlertsPopover(); @@ -188,6 +210,7 @@ export function openAlertsPopover({ stateContainer={stateContainer} adHocDataViews={adHocDataViews} services={services} + isPlainRecord={isPlainRecord} /> diff --git a/src/plugins/discover/public/application/main/hooks/use_saved_search_messages.test.ts b/src/plugins/discover/public/application/main/hooks/use_saved_search_messages.test.ts index 7b96c2673f3eb..80fe8b9920227 100644 --- a/src/plugins/discover/public/application/main/hooks/use_saved_search_messages.test.ts +++ b/src/plugins/discover/public/application/main/hooks/use_saved_search_messages.test.ts @@ -26,7 +26,7 @@ import { import { filter } from 'rxjs/operators'; import { dataViewMock, esHitsMockWithSort } from '@kbn/discover-utils/src/__mocks__'; import { buildDataTableRecord } from '@kbn/discover-utils'; -import { searchResponseWarningsMock } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; +import { searchResponseIncompleteWarningLocalCluster } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; describe('test useSavedSearch message generators', () => { test('sendCompleteMsg', (done) => { @@ -103,15 +103,13 @@ describe('test useSavedSearch message generators', () => { if (value.fetchStatus !== FetchStatus.LOADING_MORE) { expect(value.fetchStatus).toBe(FetchStatus.COMPLETE); expect(value.result).toStrictEqual([...initialRecords, ...moreRecords]); - expect(value.interceptedWarnings).toHaveLength(searchResponseWarningsMock.length); + expect(value.interceptedWarnings).toHaveLength(1); done(); } }); sendLoadingMoreFinishedMsg(documents$, { moreRecords, - interceptedWarnings: searchResponseWarningsMock.map((warning) => ({ - originalWarning: warning, - })), + interceptedWarnings: [{ originalWarning: searchResponseIncompleteWarningLocalCluster }], }); }); test('sendLoadingMoreFinishedMsg after an exception', (done) => { @@ -121,9 +119,7 @@ describe('test useSavedSearch message generators', () => { const documents$ = new BehaviorSubject({ fetchStatus: FetchStatus.LOADING_MORE, result: initialRecords, - interceptedWarnings: searchResponseWarningsMock.map((warning) => ({ - originalWarning: warning, - })), + interceptedWarnings: [{ originalWarning: searchResponseIncompleteWarningLocalCluster }], }); documents$.subscribe((value) => { if (value.fetchStatus !== FetchStatus.LOADING_MORE) { diff --git a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts index ba8a09e17e3d1..6de9781b0b58b 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts @@ -25,7 +25,7 @@ import { fetchDocuments } from './fetch_documents'; import { fetchTextBased } from './fetch_text_based'; import { buildDataTableRecord } from '@kbn/discover-utils'; import { dataViewMock, esHitsMockWithSort } from '@kbn/discover-utils/src/__mocks__'; -import { searchResponseWarningsMock } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; +import { searchResponseIncompleteWarningLocalCluster } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; jest.mock('./fetch_documents', () => ({ fetchDocuments: jest.fn().mockResolvedValue([]), @@ -296,9 +296,11 @@ describe('test fetchAll', () => { const initialRecords = [records[0], records[1]]; const moreRecords = [records[2], records[3]]; - const interceptedWarnings = searchResponseWarningsMock.map((warning) => ({ - originalWarning: warning, - })); + const interceptedWarnings = [ + { + originalWarning: searchResponseIncompleteWarningLocalCluster, + }, + ]; test('should add more records', async () => { const collectDocuments = subjectCollector(subjects.documents$); diff --git a/src/plugins/discover/public/application/main/utils/fetch_documents.test.ts b/src/plugins/discover/public/application/main/utils/fetch_documents.test.ts index f850b283b3491..cbc62a3cd6068 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_documents.test.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_documents.test.ts @@ -37,17 +37,20 @@ describe('test fetchDocuments', () => { const documents = hits.map((hit) => buildDataTableRecord(hit, dataViewMock)); savedSearchMock.searchSource.fetch$ = () => of({ rawResponse: { hits: { hits } } } as IKibanaSearchResponse>); - expect(fetchDocuments(savedSearchMock.searchSource, getDeps())).resolves.toEqual({ + expect(await fetchDocuments(savedSearchMock.searchSource, getDeps())).toEqual({ + interceptedWarnings: [], records: documents, }); }); - test('rejects on query failure', () => { + test('rejects on query failure', async () => { savedSearchMock.searchSource.fetch$ = () => throwErrorRx(() => new Error('Oh noes!')); - expect(fetchDocuments(savedSearchMock.searchSource, getDeps())).rejects.toEqual( - new Error('Oh noes!') - ); + try { + await fetchDocuments(savedSearchMock.searchSource, getDeps()); + } catch (e) { + expect(e).toEqual(new Error('Oh noes!')); + } }); test('passes a correct session id', async () => { @@ -66,7 +69,8 @@ describe('test fetchDocuments', () => { jest.spyOn(searchSourceRegular, 'fetch$'); - expect(fetchDocuments(searchSourceRegular, deps)).resolves.toEqual({ + expect(await fetchDocuments(searchSourceRegular, deps)).toEqual({ + interceptedWarnings: [], records: documents, }); @@ -84,7 +88,8 @@ describe('test fetchDocuments', () => { jest.spyOn(searchSourceForLoadMore, 'fetch$'); - expect(fetchDocuments(searchSourceForLoadMore, deps)).resolves.toEqual({ + expect(await fetchDocuments(searchSourceForLoadMore, deps)).toEqual({ + interceptedWarnings: [], records: documents, }); diff --git a/src/plugins/discover/public/application/main/utils/fetch_documents.ts b/src/plugins/discover/public/application/main/utils/fetch_documents.ts index 892da705f4b8f..e849b347a22ff 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_documents.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_documents.ts @@ -13,7 +13,6 @@ import { SAMPLE_SIZE_SETTING, buildDataTableRecordList } from '@kbn/discover-uti import type { EsHitRecord } from '@kbn/discover-utils/types'; import { getSearchResponseInterceptedWarnings } from '@kbn/search-response-warnings'; import type { RecordsFetchResponse } from '../../types'; -import { DISABLE_SHARD_FAILURE_WARNING } from '../../../../common/constants'; import { FetchDeps } from './fetch_all'; /** @@ -60,7 +59,7 @@ export const fetchDocuments = ( }), }, executionContext, - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, + disableWarningToasts: true, }) .pipe( filter((res) => isCompleteResponse(res)), @@ -75,9 +74,6 @@ export const fetchDocuments = ( ? getSearchResponseInterceptedWarnings({ services, adapter, - options: { - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, - }, }) : []; diff --git a/src/plugins/discover/public/application/view_alert/view_alert_route.tsx b/src/plugins/discover/public/application/view_alert/view_alert_route.tsx index 48b7144b9115d..5d8383be5e935 100644 --- a/src/plugins/discover/public/application/view_alert/view_alert_route.tsx +++ b/src/plugins/discover/public/application/view_alert/view_alert_route.tsx @@ -20,7 +20,7 @@ const isActualAlert = (queryParams: QueryParams): queryParams is NonNullableEntr }; export function ViewAlertRoute() { - const { core, data, locator, toastNotifications } = useDiscoverServices(); + const { core, data, locator, toastNotifications, dataViews } = useDiscoverServices(); const { id } = useParams<{ id: string }>(); const history = useHistory(); const { search } = useLocation(); @@ -46,7 +46,8 @@ export function ViewAlertRoute() { queryParams, toastNotifications, core, - data + data, + dataViews ); const navigateWithDiscoverState = (state: DiscoverAppLocatorParams) => { @@ -63,7 +64,17 @@ export function ViewAlertRoute() { .then(buildLocatorParams) .then(navigateWithDiscoverState) .catch(navigateToDiscoverRoot); - }, [core, data, history, id, locator, openActualAlert, queryParams, toastNotifications]); + }, [ + core, + data, + dataViews, + history, + id, + locator, + openActualAlert, + queryParams, + toastNotifications, + ]); return null; } diff --git a/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx b/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx index d8a7bfeae9b34..cc51f11885ea4 100644 --- a/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx +++ b/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx @@ -8,8 +8,9 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; +import { getIndexPatternFromESQLQuery, type AggregateQuery } from '@kbn/es-query'; import { CoreStart, ToastsStart } from '@kbn/core/public'; -import type { DataView } from '@kbn/data-views-plugin/public'; +import type { DataView, DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import type { Rule } from '@kbn/alerting-plugin/common'; import type { RuleTypeParams } from '@kbn/alerting-plugin/common'; import { ISearchSource, SerializedSearchSourceFields, getTime } from '@kbn/data-plugin/common'; @@ -21,6 +22,8 @@ import { DiscoverAppLocatorParams } from '../../../common/locator'; export interface SearchThresholdAlertParams extends RuleTypeParams { searchConfiguration: SerializedSearchSourceFields; + esqlQuery?: AggregateQuery; + timeField?: string; } export interface QueryParams { @@ -50,7 +53,8 @@ export const getAlertUtils = ( queryParams: QueryParams, toastNotifications: ToastsStart, core: CoreStart, - data: DataPublicPluginStart + data: DataPublicPluginStart, + dataViews: DataViewsPublicPluginStart ) => { const showDataViewFetchError = (alertId: string) => { const errorTitle = i18n.translate('discover.viewAlert.dataViewErrorTitle', { @@ -111,14 +115,31 @@ export const getAlertUtils = ( } }; - const buildLocatorParams = ({ + const buildLocatorParams = async ({ alert, searchSource, }: { alert: Rule; searchSource: ISearchSource; - }): DiscoverAppLocatorParams => { - const dataView = searchSource.getField('index'); + }): Promise => { + let dataView = searchSource.getField('index'); + let query = searchSource.getField('query') || data.query.queryString.getDefaultQuery(); + + // Dataview and query for ES|QL alerts + if ( + alert.params && + 'esqlQuery' in alert.params && + alert.params.esqlQuery && + 'esql' in alert.params.esqlQuery + ) { + query = alert.params.esqlQuery; + const indexPattern: string = getIndexPatternFromESQLQuery(alert.params.esqlQuery.esql); + dataView = await dataViews.create({ + title: indexPattern, + timeFieldName: alert.params.timeField, + }); + } + const timeFieldName = dataView?.timeFieldName; // data view fetch error if (!dataView || !timeFieldName) { @@ -131,7 +152,7 @@ export const getAlertUtils = ( : buildTimeRangeFilter(dataView, alert, timeFieldName); return { - query: searchSource.getField('query') || data.query.queryString.getDefaultQuery(), + query, dataViewSpec: dataView.toSpec(false), timeRange, filters: searchSource.getField('filter') as Filter[], diff --git a/src/plugins/discover/public/components/common/error_callout.tsx b/src/plugins/discover/public/components/common/error_callout.tsx index d0e914a81e851..84b5b979c0249 100644 --- a/src/plugins/discover/public/components/common/error_callout.tsx +++ b/src/plugins/discover/public/components/common/error_callout.tsx @@ -41,7 +41,7 @@ export const ErrorCallout = ({ const { euiTheme } = useEuiTheme(); const showErrorMessage = i18n.translate('discover.errorCalloutShowErrorMessage', { - defaultMessage: 'Show details', + defaultMessage: 'View details', }); const overrideDisplay = getSearchErrorOverrideDisplay({ diff --git a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx index 9a44ae3834f7c..6b4856d3a298f 100644 --- a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx @@ -62,11 +62,7 @@ import { import type { UnifiedDataTableProps } from '@kbn/unified-data-table'; import type { UnifiedDataTableSettings } from '@kbn/unified-data-table'; import { columnActions } from '@kbn/unified-data-table'; -import { - VIEW_MODE, - DISABLE_SHARD_FAILURE_WARNING, - getDefaultRowsPerPage, -} from '../../common/constants'; +import { VIEW_MODE, getDefaultRowsPerPage } from '../../common/constants'; import type { ISearchEmbeddable, SearchInput, SearchOutput } from './types'; import type { DiscoverServices } from '../build_services'; import { getSortForEmbeddable, SortPair } from '../utils/sorting'; @@ -371,7 +367,7 @@ export class SavedSearchEmbeddable }), }, executionContext, - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, + disableWarningToasts: true, }) ); @@ -379,9 +375,6 @@ export class SavedSearchEmbeddable searchProps.interceptedWarnings = getSearchResponseInterceptedWarnings({ services: this.services, adapter: this.inspectorAdapters.requests, - options: { - disableShardFailureWarning: DISABLE_SHARD_FAILURE_WARNING, - }, }); } diff --git a/src/plugins/discover/public/global_search/search_provider.test.ts b/src/plugins/discover/public/global_search/search_provider.test.ts new file mode 100644 index 0000000000000..79ec890858c3f --- /dev/null +++ b/src/plugins/discover/public/global_search/search_provider.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 { NEVER, lastValueFrom } from 'rxjs'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { ApplicationStart } from '@kbn/core/public'; +import { getESQLSearchProvider } from './search_provider'; +import { createDiscoverDataViewsMock } from '../__mocks__/data_views'; +import type { DiscoverAppLocator } from '../../common'; + +describe('ES|QL search provider', () => { + const uiCapabilitiesMock = new Promise((resolve) => { + resolve({ navLinks: { discover: true } } as unknown as ApplicationStart['capabilities']); + }); + const dataMock = new Promise((resolve) => { + resolve({ dataViews: createDiscoverDataViewsMock() } as unknown as DataPublicPluginStart); + }); + const locator = { + useUrl: jest.fn(() => ''), + navigate: jest.fn(), + getLocation: jest.fn(() => + Promise.resolve({ + app: 'discover', + path: '/test', + }) + ), + getRedirectUrl: jest.fn(() => ''), + } as unknown as DiscoverAppLocator; + test('returns score 100 if term is esql', async () => { + const esqlSearchProvider = getESQLSearchProvider(true, uiCapabilitiesMock, dataMock, locator); + const observable = esqlSearchProvider.find( + { term: 'esql' }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ); + + await expect(lastValueFrom(observable)).resolves.toEqual([ + { + icon: 'logoKibana', + id: 'esql', + meta: { categoryId: 'kibana', categoryLabel: 'Analytics' }, + score: 100, + title: 'Create ES|QL queries', + type: 'application', + url: '/app/discover/test', + }, + ]); + }); + + test('returns score 90 if user tries to write es|ql', async () => { + const esqlSearchProvider = getESQLSearchProvider(true, uiCapabilitiesMock, dataMock, locator); + const observable = esqlSearchProvider.find( + { term: 'es|' }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ); + + await expect(lastValueFrom(observable)).resolves.toEqual([ + { + icon: 'logoKibana', + id: 'esql', + meta: { categoryId: 'kibana', categoryLabel: 'Analytics' }, + score: 90, + title: 'Create ES|QL queries', + type: 'application', + url: '/app/discover/test', + }, + ]); + }); + + test('returns empty results if user tries to write something irrelevant', async () => { + const esqlSearchProvider = getESQLSearchProvider(true, uiCapabilitiesMock, dataMock, locator); + const observable = esqlSearchProvider.find( + { term: 'woof' }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ); + + await expect(lastValueFrom(observable)).resolves.toEqual([]); + }); + + test('returns empty results if ESQL is disabled', async () => { + const esqlSearchProvider = getESQLSearchProvider(false, uiCapabilitiesMock, dataMock, locator); + const observable = esqlSearchProvider.find( + { term: 'esql' }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ); + + await expect(lastValueFrom(observable)).resolves.toEqual([]); + }); + + test('returns empty results if no default dataview', async () => { + const dataViewMock = createDiscoverDataViewsMock(); + const updatedDataMock = new Promise((resolve) => { + resolve({ + dataViews: { ...dataViewMock, getDefaultDataView: jest.fn(() => undefined) }, + } as unknown as DataPublicPluginStart); + }); + const esqlSearchProvider = getESQLSearchProvider( + true, + uiCapabilitiesMock, + updatedDataMock, + locator + ); + const observable = esqlSearchProvider.find( + { term: 'woof' }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ); + + await expect(lastValueFrom(observable)).resolves.toEqual([]); + }); +}); diff --git a/src/plugins/discover/public/global_search/search_provider.ts b/src/plugins/discover/public/global_search/search_provider.ts new file mode 100644 index 0000000000000..35362f519ab3d --- /dev/null +++ b/src/plugins/discover/public/global_search/search_provider.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ApplicationStart } from '@kbn/core/public'; +import { from, of } from 'rxjs'; +import { i18n } from '@kbn/i18n'; +import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; +import type { GlobalSearchResultProvider } from '@kbn/global-search-plugin/public'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DiscoverAppLocator } from '../../common'; + +/** + * Global search provider adding an ES|QL and ESQL entry. + * This is necessary because ES|QL is part of the Discover application. + * + * It navigates to Discover with a default query extracted from the default dataview + */ +export const getESQLSearchProvider: ( + isESQLEnabled: boolean, + uiCapabilities: Promise, + data: Promise, + locator?: DiscoverAppLocator +) => GlobalSearchResultProvider = (isESQLEnabled, uiCapabilities, data, locator) => ({ + id: 'esql', + find: ({ term = '', types, tags }) => { + if (tags || (types && !types.includes('application')) || !locator || !isESQLEnabled) { + return of([]); + } + + return from( + Promise.all([uiCapabilities, data]).then(async ([{ navLinks }, { dataViews }]) => { + if (!navLinks.discover) { + return []; + } + const title = i18n.translate('discover.globalSearch.esqlSearchTitle', { + defaultMessage: 'Create ES|QL queries', + description: 'ES|QL is a product name and should not be translated', + }); + const defaultDataView = await dataViews.getDefaultDataView({ displayErrors: false }); + + if (!defaultDataView) { + return []; + } + + const params = { + query: { + esql: `from ${defaultDataView?.getIndexPattern()} | limit 10`, + }, + dataViewSpec: defaultDataView?.toSpec(), + }; + + const discoverLocation = await locator?.getLocation(params); + + term = term.toLowerCase(); + let score = 0; + + if (term === 'es|ql' || term === 'esql') { + score = 100; + } else if (term && ('es|ql'.includes(term) || 'esql'.includes(term))) { + score = 90; + } + + if (score === 0) return []; + + return [ + { + id: 'esql', + title, + type: 'application', + icon: 'logoKibana', + meta: { + categoryId: DEFAULT_APP_CATEGORIES.kibana.id, + categoryLabel: DEFAULT_APP_CATEGORIES.kibana.label, + }, + score, + url: `/app/${discoverLocation.app}${discoverLocation.path}`, + }, + ]; + }) + ); + }, + getSearchableTypes: () => ['application'], +}); diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index e00d9d29516c7..a1208f5c84eb7 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -20,6 +20,7 @@ import { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { ExpressionsSetup, ExpressionsStart } from '@kbn/expressions-plugin/public'; import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import type { GlobalSearchPluginSetup } from '@kbn/global-search-plugin/public'; import { NavigationPublicPluginStart as NavigationStart } from '@kbn/navigation-plugin/public'; import { SharePluginStart, SharePluginSetup } from '@kbn/share-plugin/public'; import { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; @@ -43,7 +44,7 @@ import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/ import type { UnifiedDocViewerStart } from '@kbn/unified-doc-viewer-plugin/public'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; -import { TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; +import { TRUNCATE_MAX_HEIGHT, ENABLE_ESQL } from '@kbn/discover-utils'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; import { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import { PLUGIN_ID } from '../common'; @@ -79,6 +80,7 @@ import { DiscoverContainerInternal, type DiscoverContainerProps, } from './components/discover_container'; +import { getESQLSearchProvider } from './global_search/search_provider'; /** * @public @@ -164,6 +166,7 @@ export interface DiscoverSetupPlugins { home?: HomePublicPluginSetup; data: DataPublicPluginSetup; expressions: ExpressionsSetup; + globalSearch?: GlobalSearchPluginSetup; } /** @@ -233,6 +236,27 @@ export class DiscoverPlugin ); } + if (plugins.globalSearch) { + const enableESQL = core.uiSettings.get(ENABLE_ESQL); + plugins.globalSearch.registerResultProvider( + getESQLSearchProvider( + enableESQL, + core.getStartServices().then( + ([ + { + application: { capabilities }, + }, + ]) => capabilities + ), + core.getStartServices().then((deps) => { + const { data } = deps[1]; + return data; + }), + this.locator + ) + ); + } + const { setTrackedUrl, restorePreviousUrl, diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 3328073a026e7..f7b1e45e9a608 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -71,7 +71,8 @@ "@kbn/react-kibana-mount", "@kbn/react-kibana-context-render", "@kbn/unified-data-table", - "@kbn/no-data-page-plugin" + "@kbn/no-data-page-plugin", + "@kbn/global-search-plugin" ], "exclude": [ "target/**/*" diff --git a/src/plugins/unified_histogram/public/chart/chart.test.tsx b/src/plugins/unified_histogram/public/chart/chart.test.tsx index 3ce4f829ebac3..d561a3310ceae 100644 --- a/src/plugins/unified_histogram/public/chart/chart.test.tsx +++ b/src/plugins/unified_histogram/public/chart/chart.test.tsx @@ -43,6 +43,7 @@ async function mountComponent({ allSuggestions, isPlainRecord, hasDashboardPermissions, + isChartLoading, }: { noChart?: boolean; noHits?: boolean; @@ -54,6 +55,7 @@ async function mountComponent({ allSuggestions?: Suggestion[]; isPlainRecord?: boolean; hasDashboardPermissions?: boolean; + isChartLoading?: boolean; } = {}) { (searchSourceInstanceMock.fetch$ as jest.Mock).mockImplementation( jest.fn().mockReturnValue(of({ rawResponse: { hits: { total: noHits ? 0 : 2 } } })) @@ -98,6 +100,7 @@ async function mountComponent({ breakdown: noBreakdown ? undefined : { field: undefined }, currentSuggestion, allSuggestions, + isChartLoading: Boolean(isChartLoading), isPlainRecord, appendHistogram, onResetChartHeight: jest.fn(), @@ -173,6 +176,11 @@ describe('Chart', () => { expect(component.find('[data-test-subj="unifiedHistogramChart"]').exists()).toBeTruthy(); }); + test('render progress bar when text based and request is loading', async () => { + const component = await mountComponent({ isPlainRecord: true, isChartLoading: true }); + expect(component.find('[data-test-subj="unifiedHistogramProgressBar"]').exists()).toBeTruthy(); + }); + test('triggers onEditVisualization on click', async () => { expect(mockUseEditVisualization).not.toHaveBeenCalled(); const component = await mountComponent(); diff --git a/src/plugins/unified_histogram/public/chart/chart.tsx b/src/plugins/unified_histogram/public/chart/chart.tsx index 0172b1b6107c1..56b6ed223df2b 100644 --- a/src/plugins/unified_histogram/public/chart/chart.tsx +++ b/src/plugins/unified_histogram/public/chart/chart.tsx @@ -14,6 +14,7 @@ import { EuiFlexItem, EuiPopover, EuiToolTip, + EuiProgress, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { EmbeddableComponentProps, Suggestion } from '@kbn/lens-plugin/public'; @@ -70,6 +71,7 @@ export interface ChartProps { input$?: UnifiedHistogramInput$; lensTablesAdapter?: Record; isOnHistogramMode?: boolean; + isChartLoading?: boolean; onResetChartHeight?: () => void; onChartHiddenChange?: (chartHidden: boolean) => void; onTimeIntervalChange?: (timeInterval: string) => void; @@ -107,6 +109,7 @@ export function Chart({ input$: originalInput$, lensTablesAdapter, isOnHistogramMode, + isChartLoading, onResetChartHeight, onChartHiddenChange, onTimeIntervalChange, @@ -416,6 +419,14 @@ export function Chart({ })} css={histogramCss} > + {isChartLoading && ( + + )} isCompleteResponse(res)), diff --git a/src/plugins/unified_histogram/public/container/container.tsx b/src/plugins/unified_histogram/public/container/container.tsx index 311a380790dec..74ecf5837c02e 100644 --- a/src/plugins/unified_histogram/public/container/container.tsx +++ b/src/plugins/unified_histogram/public/container/container.tsx @@ -42,6 +42,7 @@ export type UnifiedHistogramContainerProps = { | Promise; searchSessionId?: UnifiedHistogramRequestContext['searchSessionId']; requestAdapter?: UnifiedHistogramRequestContext['adapter']; + isChartLoading?: boolean; } & Pick< UnifiedHistogramLayoutProps, | 'services' @@ -124,8 +125,7 @@ export const UnifiedHistogramContainer = forwardRef< ), }); }, [input$, stateService]); - - const { dataView, query, searchSessionId, requestAdapter } = containerProps; + const { dataView, query, searchSessionId, requestAdapter, isChartLoading } = containerProps; const currentSuggestion = useStateSelector(stateService?.state$, currentSuggestionSelector); const topPanelHeight = useStateSelector(stateService?.state$, topPanelHeightSelector); const stateProps = useStateProps({ @@ -147,6 +147,7 @@ export const UnifiedHistogramContainer = forwardRef< {...layoutProps} {...stateProps} currentSuggestion={currentSuggestion} + isChartLoading={Boolean(isChartLoading)} topPanelHeight={topPanelHeight} input$={input$} lensSuggestionsApi={lensSuggestionsApi} diff --git a/src/plugins/unified_histogram/public/container/services/state_service.ts b/src/plugins/unified_histogram/public/container/services/state_service.ts index 1fd0905d86c7a..4cb2950763094 100644 --- a/src/plugins/unified_histogram/public/container/services/state_service.ts +++ b/src/plugins/unified_histogram/public/container/services/state_service.ts @@ -190,7 +190,6 @@ export const createStateService = ( setCurrentSuggestion: (suggestion: Suggestion | undefined) => { updateState({ currentSuggestion: suggestion }); }, - setTimeInterval: (timeInterval: string) => { updateState({ timeInterval }); }, diff --git a/src/plugins/unified_histogram/public/layout/layout.test.tsx b/src/plugins/unified_histogram/public/layout/layout.test.tsx index ee51ad99b4053..f75fa0b1d4b9c 100644 --- a/src/plugins/unified_histogram/public/layout/layout.test.tsx +++ b/src/plugins/unified_histogram/public/layout/layout.test.tsx @@ -77,6 +77,7 @@ describe('Layout', () => { to: '2020-05-14T11:20:13.590', }} lensSuggestionsApi={jest.fn()} + isChartLoading={false} {...rest} /> ); diff --git a/src/plugins/unified_histogram/public/layout/layout.tsx b/src/plugins/unified_histogram/public/layout/layout.tsx index 95661ed9b3f2f..e3c80679c5c3f 100644 --- a/src/plugins/unified_histogram/public/layout/layout.tsx +++ b/src/plugins/unified_histogram/public/layout/layout.tsx @@ -120,6 +120,10 @@ export interface UnifiedHistogramLayoutProps extends PropsWithChildren * Input observable */ input$?: UnifiedHistogramInput$; + /** + * Flag indicating that the chart is currently loading + */ + isChartLoading: boolean; /** * The Lens suggestions API */ @@ -174,6 +178,7 @@ export const UnifiedHistogramLayout = ({ query, filters, currentSuggestion: originalSuggestion, + isChartLoading, isPlainRecord, timeRange, relativeTimeRange, @@ -217,7 +222,6 @@ export const UnifiedHistogramLayout = ({ }); const chart = suggestionUnsupported ? undefined : originalChart; - const topPanelNode = useMemo( () => createHtmlPortalNode({ attributes: { class: 'eui-fullHeight' } }), [] @@ -270,6 +274,7 @@ export const UnifiedHistogramLayout = ({ request={request} hits={hits} currentSuggestion={currentSuggestion} + isChartLoading={isChartLoading} allSuggestions={allSuggestions} isPlainRecord={isPlainRecord} chart={chart} diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index 9d34d2fb26ca6..735c5e6572d43 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -19,6 +19,7 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { TimefilterContract } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { Warnings } from '@kbn/charts-plugin/public'; +import { hasUnsupportedDownsampledAggregationFailure } from '@kbn/search-response-warnings'; import { Adapters, AttributeService, @@ -351,11 +352,13 @@ export class VisualizeEmbeddable this.deps .start() .plugins.data.search.showWarnings(this.getInspectorAdapters()!.requests!, (warning) => { - if ( - warning.type === 'shard_failure' && - warning.reason.type === 'unsupported_aggregation_on_downsampled_index' - ) { - warnings.push(warning.reason.reason || warning.message); + if (hasUnsupportedDownsampledAggregationFailure(warning)) { + warnings.push( + i18n.translate('visualizations.embeddable.tsdbRollupWarning', { + defaultMessage: + 'Visualization uses a function that is unsupported by rolled up data. Select a different function or change the time range.', + }) + ); return true; } if (this.vis.type.suppressWarnings?.()) { @@ -582,7 +585,7 @@ export class VisualizeEmbeddable timeRange: this.timeRange, query: this.input.query, filters: this.input.filters, - disableShardWarnings: true, + disableWarningToasts: true, }, variables: { embeddableTitle: this.getTitle(), diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index e643d9fa1fd61..a835f3151c60c 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -63,7 +63,8 @@ "@kbn/content-management-table-list-view", "@kbn/content-management-utils", "@kbn/serverless", - "@kbn/no-data-page-plugin" + "@kbn/no-data-page-plugin", + "@kbn/search-response-warnings" ], "exclude": [ "target/**/*", diff --git a/test/examples/search/warnings.ts b/test/examples/search/warnings.ts index 5ec4f59586a13..f1856f0b0e611 100644 --- a/test/examples/search/warnings.ts +++ b/test/examples/search/warnings.ts @@ -26,7 +26,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const esArchiver = getService('esArchiver'); - describe('handling warnings with search source fetch', function () { + // Failing: See https://github.com/elastic/kibana/issues/166484 + describe.skip('handling warnings with search source fetch', function () { const dataViewTitle = 'sample-01,sample-01-rollup'; const fromTime = 'Jun 17, 2022 @ 00:00:00.000'; const toTime = 'Jun 23, 2022 @ 00:00:00.000'; @@ -100,7 +101,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.clearAllToasts(); }); - it('shows shard failure warning notifications by default', async () => { + it('should show search warnings as toasts', async () => { await testSubjects.click('searchSourceWithOther'); // wait for response - toasts appear before the response is rendered @@ -113,30 +114,25 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // toasts const toasts = await find.allByCssSelector(toastsSelector); expect(toasts.length).to.be(2); - const expects = ['2 of 4 shards failed', 'Query result']; + const expects = ['The data might be incomplete or wrong.', 'Query result']; await asyncForEach(toasts, async (t, index) => { expect(await t.getVisibleText()).to.eql(expects[index]); }); // click "see full error" button in the toast - const [openShardModalButton] = await testSubjects.findAll('openShardFailureModalBtn'); + const [openShardModalButton] = await testSubjects.findAll('openIncompleteResultsModalBtn'); await openShardModalButton.click(); - await retry.waitFor('modal title visible', async () => { - const modalHeader = await testSubjects.find('shardFailureModalTitle'); - return (await modalHeader.getVisibleText()) === '2 of 4 shards failed'; - }); - // request - await testSubjects.click('shardFailuresModalRequestButton'); - const requestBlock = await testSubjects.find('shardsFailedModalRequestBlock'); + await testSubjects.click('showRequestButton'); + const requestBlock = await testSubjects.find('incompleteResultsModalRequestBlock'); expect(await requestBlock.getVisibleText()).to.contain(testRollupField); // response - await testSubjects.click('shardFailuresModalResponseButton'); - const responseBlock = await testSubjects.find('shardsFailedModalResponseBlock'); + await testSubjects.click('showResponseButton'); + const responseBlock = await testSubjects.find('incompleteResultsModalResponseBlock'); expect(await responseBlock.getVisibleText()).to.contain(shardFailureReason); - await testSubjects.click('closeShardFailureModal'); + await testSubjects.click('closeIncompleteResultsModal'); // response tab assert(response && response._shards.failures); @@ -154,7 +150,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(warnings).to.eql([]); }); - it('able to handle shard failure warnings and prevent default notifications', async () => { + it('should show search warnings in results tab', async () => { await testSubjects.click('searchSourceWithoutOther'); // wait for toasts - toasts appear after the response is rendered @@ -163,53 +159,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { toasts = await find.allByCssSelector(toastsSelector); expect(toasts.length).to.be(2); }); - const expects = ['Query result', '2 of 4 shards failed']; + const expects = ['The data might be incomplete or wrong.', 'Query result']; await asyncForEach(toasts, async (t, index) => { expect(await t.getVisibleText()).to.eql(expects[index]); }); - // click "see full error" button in the toast - const [openShardModalButton] = await testSubjects.findAll('openShardFailureModalBtn'); - await openShardModalButton.click(); - await testSubjects.exists('shardFailureModalTitle'); - - await retry.waitFor('modal title visible', async () => { - const modalHeader = await testSubjects.find('shardFailureModalTitle'); - return (await modalHeader.getVisibleText()) === '2 of 4 shards failed'; - }); - - // request - await testSubjects.click('shardFailuresModalRequestButton'); - const requestBlock = await testSubjects.find('shardsFailedModalRequestBlock'); - expect(await requestBlock.getVisibleText()).to.contain(testRollupField); - // response - await testSubjects.click('shardFailuresModalResponseButton'); - const responseBlock = await testSubjects.find('shardsFailedModalResponseBlock'); - expect(await responseBlock.getVisibleText()).to.contain(shardFailureReason); - - await testSubjects.click('closeShardFailureModal'); - - // response tab - const response = await getTestJson('responseTab', 'responseCodeBlock'); - expect(response._shards.total).to.be(4); - expect(response._shards.successful).to.be(2); - expect(response._shards.skipped).to.be(0); - expect(response._shards.failed).to.be(2); - expect(response._shards.failures.length).to.equal(1); - expect(response._shards.failures[0].index).to.equal(testRollupIndex); - expect(response._shards.failures[0].reason.type).to.equal(shardFailureType); - expect(response._shards.failures[0].reason.reason).to.equal(shardFailureReason); - // warnings tab const warnings = await getTestJson('warningsTab', 'warningsCodeBlock'); - expect(warnings).to.eql([ - { - type: 'shard_failure', - message: '2 of 4 shards failed', - reason: { reason: shardFailureReason, type: shardFailureType }, - text: 'The data might be incomplete or wrong.', - }, - ]); + expect(warnings.length).to.be(1); + expect(warnings[0].type).to.be('incomplete'); }); }); } diff --git a/test/functional/apps/discover/group2/_esql_view.ts b/test/functional/apps/discover/group2/_esql_view.ts index 1f7493b6ff905..d820841b16cd0 100644 --- a/test/functional/apps/discover/group2/_esql_view.ts +++ b/test/functional/apps/discover/group2/_esql_view.ts @@ -75,7 +75,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // when Lens suggests a table, we render an ESQL based histogram expect(await testSubjects.exists('unifiedHistogramChart')).to.be(true); expect(await testSubjects.exists('unifiedHistogramQueryHits')).to.be(true); - expect(await testSubjects.exists('discoverAlertsButton')).to.be(false); + expect(await testSubjects.exists('discoverAlertsButton')).to.be(true); expect(await testSubjects.exists('shareTopNavButton')).to.be(true); expect(await testSubjects.exists('dataGridColumnSortingButton')).to.be(false); expect(await testSubjects.exists('docTableExpandToggleColumn')).to.be(true); diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index ea5ac251ae6a0..f3f6d8b8ac4e9 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -230,6 +230,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.cloud.projects_url (any)', // It's a string (any because schema.conditional) // can't be used to infer urls or customer id from the outside 'xpack.cloud.serverless.project_id (string)', + 'xpack.cloud.serverless.project_name (string)', 'xpack.discoverEnhanced.actions.exploreDataInChart.enabled (boolean)', 'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean)', 'xpack.fleet.agents.enabled (boolean)', diff --git a/tsconfig.base.json b/tsconfig.base.json index 2c1168feaf0c5..178df4e7c449f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -984,6 +984,8 @@ "@kbn/maps-plugin/*": ["x-pack/plugins/maps/*"], "@kbn/maps-vector-tile-utils": ["x-pack/packages/maps/vector_tile_utils"], "@kbn/maps-vector-tile-utils/*": ["x-pack/packages/maps/vector_tile_utils/*"], + "@kbn/metrics-data-access-plugin": ["x-pack/plugins/metrics_data_access"], + "@kbn/metrics-data-access-plugin/*": ["x-pack/plugins/metrics_data_access/*"], "@kbn/ml-agg-utils": ["x-pack/packages/ml/agg_utils"], "@kbn/ml-agg-utils/*": ["x-pack/packages/ml/agg_utils/*"], "@kbn/ml-anomaly-utils": ["x-pack/packages/ml/anomaly_utils"], diff --git a/x-pack/examples/reporting_example/public/containers/capture_test.tsx b/x-pack/examples/reporting_example/public/containers/capture_test.tsx index c74e65df3df79..5ff5a1d6a7a03 100644 --- a/x-pack/examples/reporting_example/public/containers/capture_test.tsx +++ b/x-pack/examples/reporting_example/public/containers/capture_test.tsx @@ -19,8 +19,7 @@ import { EuiPage, EuiPageHeader, EuiPageBody, - EuiPageContent_Deprecated as EuiPageContent, - EuiPageContentBody_Deprecated as EuiPageContentBody, + EuiPageSection, } from '@elastic/eui'; import { TestImageA } from '../components'; @@ -62,7 +61,7 @@ export const CaptureTest: FunctionComponent = () => { return ( - + @@ -75,16 +74,16 @@ export const CaptureTest: FunctionComponent = () => { - - - tab.id === tabToRender) : undefined - } - /> - - + + + + tab.id === tabToRender) : undefined + } + /> + ); diff --git a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx index ee8922a8e7631..e3e5a1de3d65f 100644 --- a/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx +++ b/x-pack/packages/ml/date_picker/src/components/full_time_range_selector.tsx @@ -72,6 +72,10 @@ export interface FullTimeRangeSelectorProps { * @param value - The time field range response. */ apiPath?: SetFullTimeRangeApiPath; + /** + * Optional flag to disable the frozen data tier choice. + */ + hideFrozenDataTierChoice?: boolean; } /** @@ -92,10 +96,12 @@ export const FullTimeRangeSelector: FC = (props) => disabled, callback, apiPath, + hideFrozenDataTierChoice = false, } = props; const { http, notifications: { toasts }, + isServerless, } = useDatePickerContext(); // wrapper around setFullTimeRange to allow for the calling of the optional callBack prop @@ -107,7 +113,9 @@ export const FullTimeRangeSelector: FC = (props) => toasts, http, query, - frozenDataPreference === FROZEN_TIER_PREFERENCE.EXCLUDE, + isServerless || hideFrozenDataTierChoice + ? false + : frozenDataPreference === FROZEN_TIER_PREFERENCE.EXCLUDE, apiPath ); if (typeof callback === 'function' && fullTimeRange !== undefined) { @@ -123,7 +131,18 @@ export const FullTimeRangeSelector: FC = (props) => ) ); } - }, [callback, dataView, frozenDataPreference, http, query, timefilter, toasts, apiPath]); + }, [ + timefilter, + dataView, + toasts, + http, + query, + isServerless, + hideFrozenDataTierChoice, + frozenDataPreference, + apiPath, + callback, + ]); const [isPopoverOpen, setPopover] = useState(false); @@ -210,31 +229,33 @@ export const FullTimeRangeSelector: FC = (props) => /> - - - } - isOpen={isPopoverOpen} - closePopover={closePopover} - panelPaddingSize="none" - anchorPosition="downRight" - > - {popoverContent} - - + {isServerless || hideFrozenDataTierChoice ? null : ( + + + } + isOpen={isPopoverOpen} + closePopover={closePopover} + panelPaddingSize="none" + anchorPosition="downRight" + > + {popoverContent} + + + )} ); }; diff --git a/x-pack/packages/ml/date_picker/src/hooks/use_date_picker_context.tsx b/x-pack/packages/ml/date_picker/src/hooks/use_date_picker_context.tsx index 28ad6a12de745..60b1c66f95984 100644 --- a/x-pack/packages/ml/date_picker/src/hooks/use_date_picker_context.tsx +++ b/x-pack/packages/ml/date_picker/src/hooks/use_date_picker_context.tsx @@ -44,6 +44,10 @@ export interface DatePickerDependencies { * Internationalisation service */ i18n: I18nStart; + /** + * Optional flag to indicate whether kibana is running in serverless + */ + isServerless?: boolean; } /** diff --git a/x-pack/packages/security-solution/navigation/src/links.tsx b/x-pack/packages/security-solution/navigation/src/links.tsx index 97434162b9879..172d7361a3420 100644 --- a/x-pack/packages/security-solution/navigation/src/links.tsx +++ b/x-pack/packages/security-solution/navigation/src/links.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import type { HTMLAttributeAnchorTarget } from 'react'; import React, { type MouseEventHandler, type MouseEvent, useCallback } from 'react'; import { EuiButton, EuiLink, type EuiLinkProps } from '@elastic/eui'; import { useGetAppUrl, useNavigateTo } from './navigation'; @@ -13,6 +14,7 @@ export interface BaseLinkProps { id: string; path?: string; urlState?: string; + target?: HTMLAttributeAnchorTarget | undefined; } export type GetLinkUrlProps = BaseLinkProps & { absolute?: boolean }; @@ -26,7 +28,16 @@ export type WrappedLinkProps = BaseLinkProps & { **/ onClick?: MouseEventHandler; }; -export type GetLinkProps = (params: WrappedLinkProps) => LinkProps; +export type GetLinkProps = ( + params: WrappedLinkProps & { + /** + * Optional `overrideNavigation` boolean prop. + * It overrides the default browser navigation action with history navigation using kibana tools. + * It is `true` by default. + **/ + overrideNavigation?: boolean; + } +) => LinkProps; export interface LinkProps { onClick: MouseEventHandler; @@ -60,7 +71,7 @@ export const useGetLinkProps = (): GetLinkProps => { const { navigateTo } = useNavigateTo(); const getLinkProps = useCallback( - ({ id, path, urlState, onClick: onClickProps }) => { + ({ id, path, urlState, onClick: onClickProps, overrideNavigation = true }) => { const url = getLinkUrl({ id, path, urlState }); return { href: url, @@ -71,8 +82,10 @@ export const useGetLinkProps = (): GetLinkProps => { if (onClickProps) { onClickProps(ev); } - ev.preventDefault(); - navigateTo({ url }); + if (overrideNavigation) { + ev.preventDefault(); + navigateTo({ url }); + } }, }; }, @@ -90,7 +103,13 @@ export const withLink = >( ): React.FC & WrappedLinkProps> => React.memo(function WithLink({ id, path, urlState, onClick: _onClick, ...rest }) { const getLink = useGetLinkProps(); - const { onClick, href } = getLink({ id, path, urlState, onClick: _onClick }); + const { onClick, href } = getLink({ + id, + path, + urlState, + onClick: _onClick, + ...(rest.target === '_blank' && { overrideNavigation: false }), + }); return ; }); diff --git a/x-pack/plugins/actions/docs/openapi/bundled.json b/x-pack/plugins/actions/docs/openapi/bundled.json index 000205bddfebd..360ba08302bf6 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.json +++ b/x-pack/plugins/actions/docs/openapi/bundled.json @@ -123,6 +123,9 @@ } }, "examples": { + "createEmailConnectorRequest": { + "$ref": "#/components/examples/create_email_connector_request" + }, "createIndexConnectorRequest": { "$ref": "#/components/examples/create_index_connector_request" }, @@ -145,6 +148,9 @@ "$ref": "#/components/schemas/connector_response_properties" }, "examples": { + "createEmailConnectorResponse": { + "$ref": "#/components/examples/create_email_connector_response" + }, "createIndexConnectorResponse": { "$ref": "#/components/examples/create_index_connector_response" }, @@ -460,6 +466,9 @@ { "$ref": "#/components/schemas/update_connector_request_d3security" }, + { + "$ref": "#/components/schemas/update_connector_request_email" + }, { "$ref": "#/components/schemas/update_connector_request_index" }, @@ -496,6 +505,9 @@ { "$ref": "#/components/schemas/update_connector_request_teams" }, + { + "$ref": "#/components/schemas/update_connector_request_webhook" + }, { "$ref": "#/components/schemas/update_connector_request_xmatters" } @@ -1635,14 +1647,78 @@ "config_properties_email": { "title": "Connector request properties for an email connector", "description": "Defines properties for connectors when type is `.email`.", + "required": [ + "from" + ], "type": "object", - "additionalProperties": true + "properties": { + "clientId": { + "description": "The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", + "type": "string", + "nullable": true + }, + "from": { + "description": "The from address for all emails sent by the connector. It must be specified in `user@host-name` format.\n", + "type": "string" + }, + "hasAuth": { + "description": "Specifies whether a user and password are required inside the secrets configuration.\n", + "default": true, + "type": "boolean" + }, + "host": { + "description": "The host name of the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. \n", + "type": "string" + }, + "oauthTokenUrl": { + "type": "string", + "nullable": true + }, + "port": { + "description": "The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. \n", + "type": "integer" + }, + "secure": { + "description": "Specifies whether the connection to the service provider will use TLS. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored.\n", + "type": "boolean" + }, + "service": { + "description": "The name of the email service.\n", + "type": "string", + "enum": [ + "elastic_cloud", + "exchange_server", + "gmail", + "other", + "outlook365", + "ses" + ] + }, + "tenantId": { + "description": "The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required.\n", + "type": "string", + "nullable": true + } + } }, "secrets_properties_email": { "title": "Connector secrets properties for an email connector", "description": "Defines secrets for connectors when type is `.email`.", "type": "object", - "additionalProperties": true + "properties": { + "clientSecret": { + "type": "string", + "description": "The Microsoft Exchange Client secret for OAuth 2.0 client credentials authentication. It must be URL-encoded. If `service` is `exchange_server`, this property is required.\n" + }, + "password": { + "type": "string", + "description": "The password for HTTP basic authentication. If `hasAuth` is set to `true`, this property is required.\n" + }, + "user": { + "type": "string", + "description": "The username for HTTP basic authentication. If `hasAuth` is set to `true`, this property is required.\n" + } + } }, "create_connector_request_email": { "title": "Create email connector request", @@ -3855,6 +3931,26 @@ } } }, + "update_connector_request_email": { + "title": "Update email connector request", + "type": "object", + "required": [ + "config", + "name" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/config_properties_email" + }, + "name": { + "type": "string", + "description": "The display name for the connector." + }, + "secrets": { + "$ref": "#/components/schemas/secrets_properties_email" + } + } + }, "update_connector_request_index": { "title": "Update index connector request", "type": "object", @@ -4084,6 +4180,27 @@ } } }, + "update_connector_request_webhook": { + "title": "Update Webhook connector request", + "type": "object", + "required": [ + "config", + "name", + "secrets" + ], + "properties": { + "config": { + "$ref": "#/components/schemas/config_properties_webhook" + }, + "name": { + "type": "string", + "description": "The display name for the connector." + }, + "secrets": { + "$ref": "#/components/schemas/secrets_properties_webhook" + } + } + }, "update_connector_request_xmatters": { "title": "Update xMatters connector request", "type": "object", @@ -4858,6 +4975,25 @@ } }, "examples": { + "create_email_connector_request": { + "summary": "Create an email connector.", + "value": { + "name": "email-connector-1", + "connector_type_id": ".email", + "config": { + "from": "tester@example.com", + "hasAuth": true, + "host": "https://example.com", + "port": 1025, + "secure": false, + "service": "other" + }, + "secrets": { + "user": "username", + "password": "password" + } + } + }, "create_index_connector_request": { "summary": "Create an index connector.", "value": { @@ -4899,6 +5035,29 @@ } } }, + "create_email_connector_response": { + "summary": "A new email connector.", + "value": { + "id": "90a82c60-478f-11ee-a343-f98a117c727f", + "connector_type_id": ".email", + "name": "email-connector-1", + "config": { + "from": "tester@example.com", + "service": "other", + "host": "https://example.com", + "port": 1025, + "secure": false, + "hasAuth": true, + "tenantId": null, + "clientId": null, + "oauthTokenUrl": null + }, + "is_preconfigured": false, + "is_deprecated": false, + "is_missing_secrets": false, + "is_system_action": false + } + }, "create_index_connector_response": { "summary": "A new index connector.", "value": { diff --git a/x-pack/plugins/actions/docs/openapi/bundled.yaml b/x-pack/plugins/actions/docs/openapi/bundled.yaml index c2baa9a365adf..bb83bdf65071c 100644 --- a/x-pack/plugins/actions/docs/openapi/bundled.yaml +++ b/x-pack/plugins/actions/docs/openapi/bundled.yaml @@ -60,6 +60,8 @@ paths: discriminator: propertyName: connector_type_id examples: + createEmailConnectorRequest: + $ref: '#/components/examples/create_email_connector_request' createIndexConnectorRequest: $ref: '#/components/examples/create_index_connector_request' createWebhookConnectorRequest: @@ -74,6 +76,8 @@ paths: schema: $ref: '#/components/schemas/connector_response_properties' examples: + createEmailConnectorResponse: + $ref: '#/components/examples/create_email_connector_response' createIndexConnectorResponse: $ref: '#/components/examples/create_index_connector_response' createWebhookConnectorResponse: @@ -246,6 +250,7 @@ paths: oneOf: - $ref: '#/components/schemas/update_connector_request_cases_webhook' - $ref: '#/components/schemas/update_connector_request_d3security' + - $ref: '#/components/schemas/update_connector_request_email' - $ref: '#/components/schemas/update_connector_request_index' - $ref: '#/components/schemas/update_connector_request_jira' - $ref: '#/components/schemas/update_connector_request_opsgenie' @@ -258,6 +263,7 @@ paths: - $ref: '#/components/schemas/update_connector_request_slack_webhook' - $ref: '#/components/schemas/update_connector_request_swimlane' - $ref: '#/components/schemas/update_connector_request_teams' + - $ref: '#/components/schemas/update_connector_request_webhook' - $ref: '#/components/schemas/update_connector_request_xmatters' examples: updateIndexConnectorRequest: @@ -1000,13 +1006,72 @@ components: config_properties_email: title: Connector request properties for an email connector description: Defines properties for connectors when type is `.email`. + required: + - from type: object - additionalProperties: true + properties: + clientId: + description: | + The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. + type: string + nullable: true + from: + description: | + The from address for all emails sent by the connector. It must be specified in `user@host-name` format. + type: string + hasAuth: + description: | + Specifies whether a user and password are required inside the secrets configuration. + default: true + type: boolean + host: + description: | + The host name of the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. + type: string + oauthTokenUrl: + type: string + nullable: true + port: + description: | + The port to connect to on the service provider. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. If `service` is `other`, this property must be defined. + type: integer + secure: + description: | + Specifies whether the connection to the service provider will use TLS. If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. + type: boolean + service: + description: | + The name of the email service. + type: string + enum: + - elastic_cloud + - exchange_server + - gmail + - other + - outlook365 + - ses + tenantId: + description: | + The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. If `service` is `exchange_server`, this property is required. + type: string + nullable: true secrets_properties_email: title: Connector secrets properties for an email connector description: Defines secrets for connectors when type is `.email`. type: object - additionalProperties: true + properties: + clientSecret: + type: string + description: | + The Microsoft Exchange Client secret for OAuth 2.0 client credentials authentication. It must be URL-encoded. If `service` is `exchange_server`, this property is required. + password: + type: string + description: | + The password for HTTP basic authentication. If `hasAuth` is set to `true`, this property is required. + user: + type: string + description: | + The username for HTTP basic authentication. If `hasAuth` is set to `true`, this property is required. create_connector_request_email: title: Create email connector request description: | @@ -2655,6 +2720,20 @@ components: description: The display name for the connector. secrets: $ref: '#/components/schemas/secrets_properties_d3security' + update_connector_request_email: + title: Update email connector request + type: object + required: + - config + - name + properties: + config: + $ref: '#/components/schemas/config_properties_email' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/secrets_properties_email' update_connector_request_index: title: Update index connector request type: object @@ -2818,6 +2897,21 @@ components: description: The display name for the connector. secrets: $ref: '#/components/schemas/secrets_properties_teams' + update_connector_request_webhook: + title: Update Webhook connector request + type: object + required: + - config + - name + - secrets + properties: + config: + $ref: '#/components/schemas/config_properties_webhook' + name: + type: string + description: The display name for the connector. + secrets: + $ref: '#/components/schemas/secrets_properties_webhook' update_connector_request_xmatters: title: Update xMatters connector request type: object @@ -3380,6 +3474,21 @@ components: name: type: string examples: + create_email_connector_request: + summary: Create an email connector. + value: + name: email-connector-1 + connector_type_id: .email + config: + from: tester@example.com + hasAuth: true + host: https://example.com + port: 1025 + secure: false + service: other + secrets: + user: username + password: password create_index_connector_request: summary: Create an index connector. value: @@ -3410,6 +3519,26 @@ components: usesBasic: false secrets: secretsUrl: https://example.com?apiKey=xxxxx + create_email_connector_response: + summary: A new email connector. + value: + id: 90a82c60-478f-11ee-a343-f98a117c727f + connector_type_id: .email + name: email-connector-1 + config: + from: tester@example.com + service: other + host: https://example.com + port: 1025 + secure: false + hasAuth: true + tenantId: null + clientId: null + oauthTokenUrl: null + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false create_index_connector_response: summary: A new index connector. value: diff --git a/x-pack/plugins/actions/docs/openapi/components/examples/create_email_connector_request.yaml b/x-pack/plugins/actions/docs/openapi/components/examples/create_email_connector_request.yaml new file mode 100644 index 0000000000000..df37ace78fb4b --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/examples/create_email_connector_request.yaml @@ -0,0 +1,14 @@ +summary: Create an email connector. +value: + name: email-connector-1 + connector_type_id: .email + config: + from: tester@example.com + hasAuth: true + host: https://example.com + port: 1025 + secure: false + service: other + secrets: + user: username + password: password \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/examples/create_email_connector_response.yaml b/x-pack/plugins/actions/docs/openapi/components/examples/create_email_connector_response.yaml new file mode 100644 index 0000000000000..b8405a1d61123 --- /dev/null +++ b/x-pack/plugins/actions/docs/openapi/components/examples/create_email_connector_response.yaml @@ -0,0 +1,19 @@ +summary: A new email connector. +value: + id: 90a82c60-478f-11ee-a343-f98a117c727f + connector_type_id: .email + name: email-connector-1 + config: + from: tester@example.com + service: other + host: https://example.com + port: 1025 + secure: false + hasAuth: true + tenantId: null + clientId: null + oauthTokenUrl: null + is_preconfigured: false + is_deprecated: false + is_missing_secrets: false + is_system_action: false \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml index d87c36be08936..6d3618e2bba27 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/config_properties_email.yaml @@ -1,5 +1,59 @@ title: Connector request properties for an email connector description: Defines properties for connectors when type is `.email`. +required: + - from type: object -additionalProperties: true -# TO-DO: Add the properties for this connector. \ No newline at end of file +properties: + clientId: + description: > + The client identifier, which is a part of OAuth 2.0 client credentials authentication, in GUID format. + If `service` is `exchange_server`, this property is required. + type: string + nullable: true + from: + description: > + The from address for all emails sent by the connector. It must be specified in `user@host-name` format. + type: string + hasAuth: + description: > + Specifies whether a user and password are required inside the secrets configuration. + default: true + type: boolean + host: + description: > + The host name of the service provider. + If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. + If `service` is `other`, this property must be defined. + type: string + oauthTokenUrl: + # description: TBD + type: string + nullable: true + port: + description: > + The port to connect to on the service provider. + If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. + If `service` is `other`, this property must be defined. + type: integer + secure: + description: > + Specifies whether the connection to the service provider will use TLS. + If the `service` is `elastic_cloud` (for Elastic Cloud notifications) or one of Nodemailer's well-known email service providers, this property is ignored. + type: boolean + service: + description: > + The name of the email service. + type: string + enum: + - elastic_cloud + - exchange_server + - gmail + - other + - outlook365 + - ses + tenantId: + description: > + The tenant identifier, which is part of OAuth 2.0 client credentials authentication, in GUID format. + If `service` is `exchange_server`, this property is required. + type: string + nullable: true \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_email.yaml b/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_email.yaml index 04a3526b72ce3..dbfca0230c79a 100644 --- a/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_email.yaml +++ b/x-pack/plugins/actions/docs/openapi/components/schemas/secrets_properties_email.yaml @@ -1,5 +1,20 @@ title: Connector secrets properties for an email connector description: Defines secrets for connectors when type is `.email`. type: object -additionalProperties: true -# TO-DO: Add the properties for this connector. \ No newline at end of file +properties: + clientSecret: + type: string + description: > + The Microsoft Exchange Client secret for OAuth 2.0 client credentials authentication. + It must be URL-encoded. + If `service` is `exchange_server`, this property is required. + password: + type: string + description: > + The password for HTTP basic authentication. + If `hasAuth` is set to `true`, this property is required. + user: + type: string + description: > + The username for HTTP basic authentication. + If `hasAuth` is set to `true`, this property is required. \ No newline at end of file diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml index 052852471d865..f32def50706b2 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector.yaml @@ -39,6 +39,8 @@ post: discriminator: propertyName: connector_type_id examples: + createEmailConnectorRequest: + $ref: '../components/examples/create_email_connector_request.yaml' createIndexConnectorRequest: $ref: '../components/examples/create_index_connector_request.yaml' createWebhookConnectorRequest: @@ -53,6 +55,8 @@ post: schema: $ref: '../components/schemas/connector_response_properties.yaml' examples: + createEmailConnectorResponse: + $ref: '../components/examples/create_email_connector_response.yaml' createIndexConnectorResponse: $ref: '../components/examples/create_index_connector_response.yaml' createWebhookConnectorResponse: diff --git a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml index 96ddfa168a270..54b164cf48d14 100644 --- a/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml +++ b/x-pack/plugins/actions/docs/openapi/paths/s@{spaceid}@api@actions@connector@{connectorid}.yaml @@ -161,7 +161,7 @@ put: oneOf: - $ref: '../components/schemas/update_connector_request_cases_webhook.yaml' - $ref: '../components/schemas/update_connector_request_d3security.yaml' -# - $ref: '../components/schemas/update_connector_request_email.yaml' + - $ref: '../components/schemas/update_connector_request_email.yaml' # - $ref: '../components/schemas/create_connector_request_genai.yaml' - $ref: '../components/schemas/update_connector_request_index.yaml' - $ref: '../components/schemas/update_connector_request_jira.yaml' @@ -176,7 +176,7 @@ put: - $ref: '../components/schemas/update_connector_request_swimlane.yaml' - $ref: '../components/schemas/update_connector_request_teams.yaml' # - $ref: '../components/schemas/update_connector_request_tines.yaml' -# - $ref: '../components/schemas/update_connector_request_webhook.yaml' + - $ref: '../components/schemas/update_connector_request_webhook.yaml' - $ref: '../components/schemas/update_connector_request_xmatters.yaml' examples: updateIndexConnectorRequest: diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts index 233261ea213f7..35860bdfb0c53 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts @@ -37,7 +37,7 @@ import { ActionsAuthorization } from '../authorization/actions_authorization'; import { getAuthorizationModeBySource, AuthorizationMode, - getBulkAuthorizationModeBySource, + bulkGetAuthorizationModeBySource, } from '../authorization/get_authorization_mode_by_source'; import { actionsAuthorizationMock } from '../authorization/actions_authorization.mock'; import { trackLegacyRBACExemption } from '../lib/track_legacy_rbac_exemption'; @@ -71,7 +71,7 @@ jest.mock('../authorization/get_authorization_mode_by_source', () => { getAuthorizationModeBySource: jest.fn(() => { return 1; }), - getBulkAuthorizationModeBySource: jest.fn(() => { + bulkGetAuthorizationModeBySource: jest.fn(() => { return 1; }), AuthorizationMode: { @@ -3007,8 +3007,8 @@ describe('execute()', () => { describe('bulkEnqueueExecution()', () => { describe('authorization', () => { - test('ensures user is authorised to excecute actions', async () => { - (getBulkAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + test('ensures user is authorised to execute actions', async () => { + (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { return { [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }; }); await actionsClient.bulkEnqueueExecution([ @@ -3037,7 +3037,7 @@ describe('bulkEnqueueExecution()', () => { }); test('throws when user is not authorised to create the type of action', async () => { - (getBulkAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { return { [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }; }); authorization.ensureAuthorized.mockRejectedValue( @@ -3073,7 +3073,7 @@ describe('bulkEnqueueExecution()', () => { }); test('tracks legacy RBAC', async () => { - (getBulkAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { return { [AuthorizationMode.RBAC]: 0, [AuthorizationMode.Legacy]: 2 }; }); @@ -3107,7 +3107,7 @@ describe('bulkEnqueueExecution()', () => { }); test('calls the bulkExecutionEnqueuer with the appropriate parameters', async () => { - (getBulkAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { + (bulkGetAuthorizationModeBySource as jest.Mock).mockImplementationOnce(() => { return { [AuthorizationMode.RBAC]: 0, [AuthorizationMode.Legacy]: 0 }; }); const opts = [ diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.ts b/x-pack/plugins/actions/server/actions_client/actions_client.ts index 73a87900db1a7..f5cf395721795 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.ts @@ -11,7 +11,7 @@ import url from 'url'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { i18n } from '@kbn/i18n'; -import { omitBy, isUndefined } from 'lodash'; +import { omitBy, isUndefined, compact } from 'lodash'; import { IScopedClusterClient, SavedObjectsClientContract, @@ -60,7 +60,7 @@ import { import { ActionsAuthorization } from '../authorization/actions_authorization'; import { getAuthorizationModeBySource, - getBulkAuthorizationModeBySource, + bulkGetAuthorizationModeBySource, AuthorizationMode, } from '../authorization/get_authorization_mode_by_source'; import { connectorAuditEvent, ConnectorAuditAction } from '../lib/audit_events'; @@ -770,18 +770,16 @@ export class ActionsClient { public async bulkEnqueueExecution( options: EnqueueExecutionOptions[] ): Promise { - const sources: Array> = []; - options.forEach((option) => { - if (option.source) { - sources.push(option.source); - } - }); + const sources: Array> = compact( + (options ?? []).map((option) => option.source) + ); - const authCounts = await getBulkAuthorizationModeBySource( + const authModes = await bulkGetAuthorizationModeBySource( + this.context.logger, this.context.unsecuredSavedObjectsClient, sources ); - if (authCounts[AuthorizationMode.RBAC] > 0) { + if (authModes[AuthorizationMode.RBAC] > 0) { /** * For scheduled executions the additional authorization check * for system actions (kibana privileges) will be performed @@ -789,11 +787,11 @@ export class ActionsClient { */ await this.context.authorization.ensureAuthorized({ operation: 'execute' }); } - if (authCounts[AuthorizationMode.Legacy] > 0) { + if (authModes[AuthorizationMode.Legacy] > 0) { trackLegacyRBACExemption( 'bulkEnqueueExecution', this.context.usageCounter, - authCounts[AuthorizationMode.Legacy] + authModes[AuthorizationMode.Legacy] ); } return this.context.bulkExecutionEnqueuer(this.context.unsecuredSavedObjectsClient, options); diff --git a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts index 7e2ceb5b653c8..2e264300490f8 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts @@ -41,7 +41,7 @@ jest.mock('../../../../authorization/get_authorization_mode_by_source', () => { getAuthorizationModeBySource: jest.fn(() => { return 1; }), - getBulkAuthorizationModeBySource: jest.fn(() => { + bulkGetAuthorizationModeBySource: jest.fn(() => { return 1; }), AuthorizationMode: { diff --git a/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.test.ts b/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.test.ts index 199d8a97bd623..7ba856b91fb97 100644 --- a/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.test.ts +++ b/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.test.ts @@ -7,14 +7,16 @@ import { getAuthorizationModeBySource, - getBulkAuthorizationModeBySource, + bulkGetAuthorizationModeBySource, AuthorizationMode, } from './get_authorization_mode_by_source'; -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { loggingSystemMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; import { v4 as uuidv4 } from 'uuid'; -import { asSavedObjectExecutionSource } from '../lib'; +import { asHttpRequestExecutionSource, asSavedObjectExecutionSource } from '../lib'; +import { KibanaRequest, Logger } from '@kbn/core/server'; const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); +const logger = loggingSystemMock.create().get() as jest.Mocked; describe(`#getAuthorizationModeBySource`, () => { test('should return RBAC if no source is provided', async () => { @@ -37,7 +39,7 @@ describe(`#getAuthorizationModeBySource`, () => { test('should return RBAC if source alert is not marked as legacy', async () => { const id = uuidv4(); - unsecuredSavedObjectsClient.get.mockResolvedValue(mockAlert({ id })); + unsecuredSavedObjectsClient.get.mockResolvedValue(mockRuleSO({ id })); expect( await getAuthorizationModeBySource( unsecuredSavedObjectsClient, @@ -52,7 +54,7 @@ describe(`#getAuthorizationModeBySource`, () => { test('should return Legacy if source alert is marked as legacy', async () => { const id = uuidv4(); unsecuredSavedObjectsClient.get.mockResolvedValue( - mockAlert({ id, attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }) + mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }) ); expect( await getAuthorizationModeBySource( @@ -68,7 +70,7 @@ describe(`#getAuthorizationModeBySource`, () => { test('should return RBAC if source alert is marked as modern', async () => { const id = uuidv4(); unsecuredSavedObjectsClient.get.mockResolvedValue( - mockAlert({ id, attributes: { meta: { versionApiKeyLastmodified: '7.10.0' } } }) + mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: '7.10.0' } } }) ); expect( await getAuthorizationModeBySource( @@ -83,7 +85,7 @@ describe(`#getAuthorizationModeBySource`, () => { test('should return RBAC if source alert doesnt have a last modified version', async () => { const id = uuidv4(); - unsecuredSavedObjectsClient.get.mockResolvedValue(mockAlert({ id, attributes: { meta: {} } })); + unsecuredSavedObjectsClient.get.mockResolvedValue(mockRuleSO({ id, attributes: { meta: {} } })); expect( await getAuthorizationModeBySource( unsecuredSavedObjectsClient, @@ -96,32 +98,71 @@ describe(`#getAuthorizationModeBySource`, () => { }); }); -describe(`#getBulkAuthorizationModeBySource`, () => { - test('should return RBAC if no source is provided', async () => { - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [] }); - expect(await getBulkAuthorizationModeBySource(unsecuredSavedObjectsClient)).toEqual({ +describe(`#bulkGetAuthorizationModeBySource`, () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + test('should return RBAC if no sources are provided', async () => { + expect(await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient)).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0, }); + expect(unsecuredSavedObjectsClient.bulkGet).not.toHaveBeenCalled(); }); - test('should return RBAC if source is not an alert', async () => { - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [] }); + test('should return RBAC if no alert sources are provided', async () => { expect( - await getBulkAuthorizationModeBySource(unsecuredSavedObjectsClient, [ + await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ asSavedObjectExecutionSource({ type: 'action', id: uuidv4(), }), + asHttpRequestExecutionSource({} as KibanaRequest), ]) ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }); + + expect(unsecuredSavedObjectsClient.bulkGet).not.toHaveBeenCalled(); + }); + + test('should consolidate duplicate alert sources', async () => { + unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ + saved_objects: [mockRuleSO({ id: '1' }), mockRuleSO({ id: '2' })], + }); + expect( + await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ + asSavedObjectExecutionSource({ + type: 'alert', + id: '1', + }), + asSavedObjectExecutionSource({ + type: 'alert', + id: '1', + }), + asSavedObjectExecutionSource({ + type: 'alert', + id: '2', + }), + ]) + ).toEqual({ [AuthorizationMode.RBAC]: 2, [AuthorizationMode.Legacy]: 0 }); + + expect(unsecuredSavedObjectsClient.bulkGet).toHaveBeenCalledWith([ + { + type: 'alert', + id: '1', + }, + { + type: 'alert', + id: '2', + }, + ]); }); test('should return RBAC if source alert is not marked as legacy', async () => { const id = uuidv4(); - unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [mockAlert({ id })] }); + unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [mockRuleSO({ id })] }); expect( - await getBulkAuthorizationModeBySource(unsecuredSavedObjectsClient, [ + await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ asSavedObjectExecutionSource({ type: 'alert', id, @@ -134,11 +175,11 @@ describe(`#getBulkAuthorizationModeBySource`, () => { const id = uuidv4(); unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [ - mockAlert({ id, attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }), + mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }), ], }); expect( - await getBulkAuthorizationModeBySource(unsecuredSavedObjectsClient, [ + await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ asSavedObjectExecutionSource({ type: 'alert', id, @@ -151,11 +192,11 @@ describe(`#getBulkAuthorizationModeBySource`, () => { const id = uuidv4(); unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [ - mockAlert({ id, attributes: { meta: { versionApiKeyLastmodified: '7.10.0' } } }), + mockRuleSO({ id, attributes: { meta: { versionApiKeyLastmodified: '7.10.0' } } }), ], }); expect( - await getBulkAuthorizationModeBySource(unsecuredSavedObjectsClient, [ + await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ asSavedObjectExecutionSource({ type: 'alert', id, @@ -167,10 +208,10 @@ describe(`#getBulkAuthorizationModeBySource`, () => { test('should return RBAC if source alert doesnt have a last modified version', async () => { const id = uuidv4(); unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ - saved_objects: [mockAlert({ id, attributes: { meta: {} } })], + saved_objects: [mockRuleSO({ id, attributes: { meta: {} } })], }); expect( - await getBulkAuthorizationModeBySource(unsecuredSavedObjectsClient, [ + await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ asSavedObjectExecutionSource({ type: 'alert', id, @@ -178,9 +219,39 @@ describe(`#getBulkAuthorizationModeBySource`, () => { ]) ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 0 }); }); + + test('should return RBAC and log warning if error getting source alert', async () => { + unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ + saved_objects: [ + mockRuleSO({ id: '1', attributes: { meta: { versionApiKeyLastmodified: 'pre-7.10.0' } } }), + // @ts-expect-error + { + id: '2', + type: 'alert', + error: { statusCode: 404, error: 'failed to get', message: 'fail' }, + }, + ], + }); + expect( + await bulkGetAuthorizationModeBySource(logger, unsecuredSavedObjectsClient, [ + asSavedObjectExecutionSource({ + type: 'alert', + id: '1', + }), + asSavedObjectExecutionSource({ + type: 'alert', + id: '2', + }), + ]) + ).toEqual({ [AuthorizationMode.RBAC]: 1, [AuthorizationMode.Legacy]: 1 }); + + expect(logger.warn).toHaveBeenCalledWith( + `Error retrieving saved object [alert/2] - fail - default to using RBAC authorization mode.` + ); + }); }); -const mockAlert = (overrides: Record = {}) => ({ +const mockRuleSO = (overrides: Record = {}) => ({ id: '1', type: 'alert', attributes: { diff --git a/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts b/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts index 7980db61ee31c..ace66798b24ba 100644 --- a/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts +++ b/x-pack/plugins/actions/server/authorization/get_authorization_mode_by_source.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { SavedObjectsClientContract } from '@kbn/core/server'; -import { get } from 'lodash'; +import { Logger, SavedObjectsClientContract } from '@kbn/core/server'; import { ActionExecutionSource, isSavedObjectExecutionSource } from '../lib'; import { ALERT_SAVED_OBJECT_TYPE } from '../constants/saved_objects'; +import { SavedObjectExecutionSource } from '../lib/action_execution_source'; const LEGACY_VERSION = 'pre-7.10.0'; @@ -34,36 +34,57 @@ export async function getAuthorizationModeBySource( : AuthorizationMode.RBAC; } -export async function getBulkAuthorizationModeBySource( +export async function bulkGetAuthorizationModeBySource( + logger: Logger, unsecuredSavedObjectsClient: SavedObjectsClientContract, executionSources: Array> = [] -): Promise> { - const count = { [AuthorizationMode.Legacy]: 0, [AuthorizationMode.RBAC]: 0 }; - if (executionSources.length === 0) { - count[AuthorizationMode.RBAC] = 1; - return count; +): Promise> { + const authModes = { [AuthorizationMode.Legacy]: 0, [AuthorizationMode.RBAC]: 0 }; + + const alertSavedObjectExecutionSources: SavedObjectExecutionSource[] = executionSources.filter( + (source) => + isSavedObjectExecutionSource(source) && source?.source?.type === ALERT_SAVED_OBJECT_TYPE + ) as SavedObjectExecutionSource[]; + + // If no ALERT_SAVED_OBJECT_TYPE source, default to RBAC + if (alertSavedObjectExecutionSources.length === 0) { + authModes[AuthorizationMode.RBAC] = 1; + return authModes; } - const alerts = await unsecuredSavedObjectsClient.bulkGet<{ + + // Collect the unique rule IDs for ALERT_SAVED_OBJECT_TYPE sources and bulk get the associated SOs + const rulesIds = new Set( + alertSavedObjectExecutionSources.map((source: SavedObjectExecutionSource) => source?.source?.id) + ); + + // Get rule saved objects to determine whether to use RBAC or legacy authorization source + const ruleSOs = await unsecuredSavedObjectsClient.bulkGet<{ meta?: { versionApiKeyLastmodified?: string; }; }>( - executionSources.map((es) => ({ + [...rulesIds].map((id) => ({ type: ALERT_SAVED_OBJECT_TYPE, - id: get(es, 'source.id'), + id, })) ); - const legacyVersions = alerts.saved_objects.reduce>((acc, so) => { - acc[so.id] = so.attributes.meta?.versionApiKeyLastmodified === LEGACY_VERSION; - return acc; - }, {}); - return executionSources.reduce((acc, es) => { - const isAlertSavedObject = - isSavedObjectExecutionSource(es) && es.source?.type === ALERT_SAVED_OBJECT_TYPE; - const isLegacyVersion = legacyVersions[get(es, 'source.id')]; - const key = - isAlertSavedObject && isLegacyVersion ? AuthorizationMode.Legacy : AuthorizationMode.RBAC; - acc[key]++; + + return ruleSOs.saved_objects.reduce((acc, ruleSO) => { + if (ruleSO.error) { + logger.warn( + `Error retrieving saved object [${ruleSO.type}/${ruleSO.id}] - ${ruleSO.error?.message} - default to using RBAC authorization mode.` + ); + // If there's an error retrieving the saved object, default to RBAC auth mode to avoid privilege de-escalation + authModes[AuthorizationMode.RBAC]++; + } else { + // Check whether this is a legacy rule + const isLegacy = ruleSO.attributes?.meta?.versionApiKeyLastmodified === LEGACY_VERSION; + if (isLegacy) { + authModes[AuthorizationMode.Legacy]++; + } else { + authModes[AuthorizationMode.RBAC]++; + } + } return acc; - }, count); + }, authModes); } diff --git a/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx b/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx index dd2380fedfa32..c18764e45797d 100644 --- a/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx +++ b/x-pack/plugins/aiops/public/components/change_point_detection/change_point_detection_root.tsx @@ -16,7 +16,11 @@ import type { SavedSearch } from '@kbn/saved-search-plugin/public'; import { StorageContextProvider } from '@kbn/ml-local-storage'; import { UrlStateProvider } from '@kbn/ml-url-state'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { DatePickerContextProvider, mlTimefilterRefresh$ } from '@kbn/ml-date-picker'; +import { + DatePickerContextProvider, + type DatePickerDependencies, + mlTimefilterRefresh$, +} from '@kbn/ml-date-picker'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { type Observable } from 'rxjs'; @@ -46,16 +50,20 @@ export interface ChangePointDetectionAppStateProps { savedSearch: SavedSearch | null; /** App dependencies */ appDependencies: AiopsAppDependencies; + /** Optional flag to indicate whether kibana is running in serverless */ + isServerless?: boolean; } export const ChangePointDetectionAppState: FC = ({ dataView, savedSearch, appDependencies, + isServerless = false, }) => { - const datePickerDeps = { + const datePickerDeps: DatePickerDependencies = { ...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), uiSettingsKeys: UI_SETTINGS, + isServerless, }; const warning = timeSeriesDataViewWarning(dataView, 'change_point_detection'); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx index a7c9bc17b6fe9..5ddf65d5b938d 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_app_state.tsx @@ -12,7 +12,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { StorageContextProvider } from '@kbn/ml-local-storage'; import { UrlStateProvider } from '@kbn/ml-url-state'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { DatePickerContextProvider } from '@kbn/ml-date-picker'; +import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { DataSourceContext } from '../../hooks/use_data_source'; @@ -35,12 +35,15 @@ export interface LogCategorizationAppStateProps { savedSearch: SavedSearch | null; /** App dependencies */ appDependencies: AiopsAppDependencies; + /** Optional flag to indicate whether kibana is running in serverless */ + isServerless?: boolean; } export const LogCategorizationAppState: FC = ({ dataView, savedSearch, appDependencies, + isServerless = false, }) => { if (!dataView) return null; @@ -50,9 +53,10 @@ export const LogCategorizationAppState: FC = ({ return <>{warning}; } - const datePickerDeps = { + const datePickerDeps: DatePickerDependencies = { ...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), uiSettingsKeys: UI_SETTINGS, + isServerless, }; return ( diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx index 212d0465b9cc0..0a41900feb9fb 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx @@ -13,7 +13,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { StorageContextProvider } from '@kbn/ml-local-storage'; import { UrlStateProvider } from '@kbn/ml-url-state'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { DatePickerContextProvider } from '@kbn/ml-date-picker'; +import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import type { AiopsAppDependencies } from '../../hooks/use_aiops_app_context'; @@ -40,6 +40,8 @@ export interface LogRateAnalysisAppStateProps { appDependencies: AiopsAppDependencies; /** Option to make main histogram sticky */ stickyHistogram?: boolean; + /** Optional flag to indicate whether kibana is running in serverless */ + isServerless?: boolean; } export const LogRateAnalysisAppState: FC = ({ @@ -47,6 +49,7 @@ export const LogRateAnalysisAppState: FC = ({ savedSearch, appDependencies, stickyHistogram, + isServerless = false, }) => { if (!dataView) return null; @@ -56,9 +59,10 @@ export const LogRateAnalysisAppState: FC = ({ return <>{warning}; } - const datePickerDeps = { + const datePickerDeps: DatePickerDependencies = { ...pick(appDependencies, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), uiSettingsKeys: UI_SETTINGS, + isServerless, }; return ( diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx index ec258081d840d..b19e72e7c4b5a 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper.tsx @@ -57,6 +57,8 @@ export interface LogRateAnalysisContentWrapperProps { * @param d Log rate analysis results data */ onAnalysisCompleted?: (d: LogRateAnalysisResultsData) => void; + /** Optional flag to indicate whether kibana is running in serverless */ + isServerless?: boolean; } export const LogRateAnalysisContentWrapper: FC = ({ @@ -70,6 +72,7 @@ export const LogRateAnalysisContentWrapper: FC { if (!dataView) return null; diff --git a/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts b/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts index 6b8cc0700f28f..aa364a416a046 100644 --- a/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts +++ b/x-pack/plugins/aiops/public/hooks/use_aiops_app_context.ts @@ -114,6 +114,7 @@ export interface AiopsAppDependencies { presentationUtil?: PresentationUtilPluginStart; embeddable?: EmbeddableStart; cases?: CasesUiStart; + isServerless?: boolean; } /** diff --git a/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts b/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts index aea967a056028..e58b795863e48 100644 --- a/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts +++ b/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.test.ts @@ -188,6 +188,7 @@ describe('mappingFromFieldMap', () => { dynamic: 'strict', properties: { '@timestamp': { + ignore_malformed: false, type: 'date', }, event: { diff --git a/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.ts b/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.ts index 038fdaf48fbf5..1d5121883df69 100644 --- a/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.ts +++ b/x-pack/plugins/alerting/common/alert_schema/field_maps/mapping_from_field_map.ts @@ -43,6 +43,10 @@ export function mappingFromFieldMap( : rest; set(mappings.properties, field.name.split('.').join('.properties.'), mapped); + + if (name === '@timestamp') { + set(mappings.properties, `${name}.ignore_malformed`, false); + } }); return mappings; diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts index 90552e1d5b0ac..18a80a0bae31d 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts @@ -141,6 +141,7 @@ const getIndexTemplatePutBody = (opts?: GetIndexTemplatePutBodyOpts) => { rollover_alias: `.alerts-${context ? context : 'test'}.alerts-${namespace}`, }, }), + 'index.mapping.ignore_malformed': true, 'index.mapping.total_fields.limit': 2500, }, mappings: { @@ -808,6 +809,7 @@ describe('Alerts Service', () => { rollover_alias: `.alerts-empty.alerts-default`, }, }), + 'index.mapping.ignore_malformed': true, 'index.mapping.total_fields.limit': 2500, }, mappings: { diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts index bf0ae8797eca5..85113b768860a 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.test.ts @@ -48,6 +48,7 @@ const IndexTemplate = (namespace: string = 'default', useDataStream: boolean = f rollover_alias: `.alerts-test.alerts-${namespace}`, }, }), + 'index.mapping.ignore_malformed': true, 'index.mapping.total_fields.limit': 2500, }, }, diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts index 30ee06a1ddda0..1466c2734ec19 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/create_or_update_index_template.ts @@ -68,6 +68,7 @@ export const getIndexTemplate = ({ : { 'index.lifecycle': indexLifecycle, }), + 'index.mapping.ignore_malformed': true, 'index.mapping.total_fields.limit': totalFieldsLimit, }, mappings: { diff --git a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap index c389d411462d7..d84aa51a0e365 100644 --- a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap @@ -1957,6 +1957,22 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the } } }, + "top_traces": { + "properties": { + "max": { + "type": "long", + "_meta": { + "description": "Max number of documents in top 100 traces withing the last day" + } + }, + "median": { + "type": "long", + "_meta": { + "description": "Median number of documents in top 100 traces within the last day" + } + } + } + }, "tasks": { "properties": { "aggregated_transactions": { @@ -2168,6 +2184,20 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the } } } + }, + "top_traces": { + "properties": { + "took": { + "properties": { + "ms": { + "type": "long", + "_meta": { + "description": "Execution time in milliseconds for the \\"top_traces\\" task" + } + } + } + } + } } } } diff --git a/x-pack/plugins/apm/kibana.jsonc b/x-pack/plugins/apm/kibana.jsonc index 42f969f5a3ee1..5cdc440e0ff24 100644 --- a/x-pack/plugins/apm/kibana.jsonc +++ b/x-pack/plugins/apm/kibana.jsonc @@ -18,6 +18,7 @@ "logsShared", "inspector", "licensing", + "metricsDataAccess", "observability", "observabilityShared", "exploratoryView", diff --git a/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.tsx b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.tsx index 9fd6299a3f67e..0b3d8ea7b7113 100644 --- a/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.tsx +++ b/x-pack/plugins/apm/public/components/shared/search_bar/search_bar.tsx @@ -51,7 +51,7 @@ export function SearchBar({ isXXXL || (!isXl && !showTimeComparison) ? 'row' : 'column'; return ( - <> + - + ); } diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts index fb061eec49baf..ba9d06b78bfae 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts @@ -590,4 +590,56 @@ describe('data telemetry collection tasks', () => { }); }); }); + + describe('top_traces', () => { + const task = tasks.find((t) => t.name === 'top_traces'); + + it('returns max and median number of documents in top traces', async () => { + const search = jest.fn().mockResolvedValueOnce({ + aggregations: { + top_traces: { + buckets: [ + { + key: '521485', + doc_count: 1026, + }, + { + key: '594439', + doc_count: 1025, + }, + { + key: '070251', + doc_count: 1023, + }, + { + key: '108079', + doc_count: 1023, + }, + { + key: '118887', + doc_count: 1023, + }, + ], + }, + max: { + value: 1026, + }, + median: { + values: { + '50.0': 1023, + }, + }, + }, + }); + + expect( + await task?.executor({ indices, telemetryClient: { search } } as any) + ).toEqual({ + top_traces: { + max: 1026, + median: 1023, + }, + }); + }); + }); }); diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts index beb84481e84b7..aad51e5ed1c5d 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts @@ -39,6 +39,7 @@ import { SERVICE_RUNTIME_NAME, SERVICE_RUNTIME_VERSION, SERVICE_VERSION, + TRACE_ID, TRANSACTION_NAME, TRANSACTION_RESULT, TRANSACTION_TYPE, @@ -1484,4 +1485,48 @@ export const tasks: TelemetryTask[] = [ }; }, }, + { + name: 'top_traces', + executor: async ({ indices, telemetryClient }) => { + const response = await telemetryClient.search({ + index: [indices.transaction, indices.span, indices.error], + body: { + size: 0, + track_total_hits: false, + timeout, + query: { + bool: { + filter: [range1d], + }, + }, + aggs: { + top_traces: { + terms: { + field: TRACE_ID, + size: 100, + }, + }, + max: { + max_bucket: { + buckets_path: 'top_traces>_count', + }, + }, + median: { + percentiles_bucket: { + buckets_path: 'top_traces>_count', + percents: [50], + }, + }, + }, + }, + }); + + return { + top_traces: { + max: response.aggregations?.max.value ?? 0, + median: response.aggregations?.median.values['50.0'] ?? 0, + }, + }; + }, + }, ]; diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts index e43fda17a951c..1c41229b47bca 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts @@ -1006,6 +1006,22 @@ export const apmSchema: MakeSchemaFrom = { }, }, per_service: { type: 'array', items: { ...apmPerServiceSchema } }, + top_traces: { + max: { + type: 'long', + _meta: { + description: + 'Max number of documents in top 100 traces withing the last day', + }, + }, + median: { + type: 'long', + _meta: { + description: + 'Median number of documents in top 100 traces within the last day', + }, + }, + }, tasks: { aggregated_transactions: { took: { @@ -1169,5 +1185,16 @@ export const apmSchema: MakeSchemaFrom = { }, }, }, + top_traces: { + took: { + ms: { + type: 'long', + _meta: { + description: + 'Execution time in milliseconds for the "top_traces" task', + }, + }, + }, + }, }, }; diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts index 9c6c312c284f4..d5c16a6b3692a 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts @@ -211,6 +211,10 @@ export interface APMUsage { total: number; }; per_service: APMPerService[]; + top_traces: { + max: number; + median: number; + }; tasks: Record< | 'aggregated_transactions' | 'cloud' @@ -226,7 +230,8 @@ export interface APMUsage { | 'cardinality' | 'environments' | 'service_groups' - | 'per_service', + | 'per_service' + | 'top_traces', { took: { ms: number } } >; } diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts index 0128d6aa92d21..f7ae6ea53147a 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts @@ -6,8 +6,7 @@ */ import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; -import { APMRouteHandlerResources } from '../../../../routes/apm_routes/register_apm_server_routes'; -import { getInfraMetricIndices } from '../../get_infra_metric_indices'; +import { APMRouteHandlerResources } from '../../../../routes/typings'; type InfraMetricsSearchParams = Omit & { size: number; @@ -17,6 +16,8 @@ type InfraMetricsSearchParams = Omit & { export type InfraMetricsClient = ReturnType; export function createInfraMetricsClient(resources: APMRouteHandlerResources) { + const metricsClient = resources.plugins.metricsDataAccess.setup.client; + return { async search( opts: TParams @@ -26,8 +27,7 @@ export function createInfraMetricsClient(resources: APMRouteHandlerResources) { elasticsearch: { client: esClient }, } = await resources.context.core; - const indexName = await getInfraMetricIndices({ - infraPlugin: resources.plugins.infra, + const indexName = await metricsClient.getMetricIndices({ savedObjectsClient, }); diff --git a/x-pack/plugins/apm/server/types.ts b/x-pack/plugins/apm/server/types.ts index ffe875e0e6d91..10687e3757849 100644 --- a/x-pack/plugins/apm/server/types.ts +++ b/x-pack/plugins/apm/server/types.ts @@ -54,7 +54,7 @@ import { FleetSetupContract as FleetPluginSetup, FleetStartContract as FleetPluginStart, } from '@kbn/fleet-plugin/server'; -import { InfraPluginStart, InfraPluginSetup } from '@kbn/infra-plugin/server'; +import { MetricsDataPluginSetup } from '@kbn/metrics-data-access-plugin/server'; import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { @@ -79,7 +79,7 @@ export interface APMPluginSetupDependencies { licensing: LicensingPluginSetup; observability: ObservabilityPluginSetup; ruleRegistry: RuleRegistryPluginSetupContract; - infra?: InfraPluginSetup; + metricsDataAccess: MetricsDataPluginSetup; dataViews: {}; share: SharePluginSetup; @@ -105,7 +105,7 @@ export interface APMPluginStartDependencies { licensing: LicensingPluginStart; observability: undefined; ruleRegistry: RuleRegistryPluginStartContract; - infra: InfraPluginStart; + metricsDataAccess: MetricsDataPluginSetup; dataViews: DataViewsServerPluginStart; share: undefined; diff --git a/x-pack/plugins/apm/tsconfig.json b/x-pack/plugins/apm/tsconfig.json index edfcdda7a2006..fe859abb02ec4 100644 --- a/x-pack/plugins/apm/tsconfig.json +++ b/x-pack/plugins/apm/tsconfig.json @@ -96,6 +96,7 @@ "@kbn/discover-plugin", "@kbn/observability-ai-assistant-plugin", "@kbn/apm-data-access-plugin", + "@kbn/metrics-data-access-plugin", "@kbn/profiling-data-access-plugin", "@kbn/profiling-utils", "@kbn/core-analytics-server", diff --git a/x-pack/plugins/cloud/public/mocks.tsx b/x-pack/plugins/cloud/public/mocks.tsx index c6b849278ab86..fdeaae4210202 100644 --- a/x-pack/plugins/cloud/public/mocks.tsx +++ b/x-pack/plugins/cloud/public/mocks.tsx @@ -29,6 +29,7 @@ function createSetupMock(): jest.Mocked { isServerlessEnabled: false, serverless: { projectId: undefined, + projectName: undefined, }, }; } diff --git a/x-pack/plugins/cloud/public/plugin.test.ts b/x-pack/plugins/cloud/public/plugin.test.ts index 9dd0ec9664ba5..431310de73524 100644 --- a/x-pack/plugins/cloud/public/plugin.test.ts +++ b/x-pack/plugins/cloud/public/plugin.test.ts @@ -148,6 +148,16 @@ describe('Cloud Plugin', () => { }); expect(setup.serverless.projectId).toBe('my-awesome-project'); }); + + it('exposes `serverless.projectName`', () => { + const { setup } = setupPlugin({ + serverless: { + project_id: 'my-awesome-project', + project_name: 'My Awesome Project', + }, + }); + expect(setup.serverless.projectName).toBe('My Awesome Project'); + }); }); }); @@ -222,5 +232,17 @@ describe('Cloud Plugin', () => { const start = plugin.start(coreStart); expect(start.serverless.projectId).toBe('my-awesome-project'); }); + + it('exposes `serverless.projectName`', () => { + const { plugin } = startPlugin({ + serverless: { + project_id: 'my-awesome-project', + project_name: 'My Awesome Project', + }, + }); + const coreStart = coreMock.createStart(); + const start = plugin.start(coreStart); + expect(start.serverless.projectName).toBe('My Awesome Project'); + }); }); }); diff --git a/x-pack/plugins/cloud/public/plugin.tsx b/x-pack/plugins/cloud/public/plugin.tsx index f0fad877a1bd5..88b0333ddc2b7 100644 --- a/x-pack/plugins/cloud/public/plugin.tsx +++ b/x-pack/plugins/cloud/public/plugin.tsx @@ -31,6 +31,7 @@ export interface CloudConfigType { is_elastic_staff_owned?: boolean; serverless?: { project_id: string; + project_name?: string; }; } @@ -91,6 +92,7 @@ export class CloudPlugin implements Plugin { isServerlessEnabled: this.isServerlessEnabled, serverless: { projectId: this.config.serverless?.project_id, + projectName: this.config.serverless?.project_name, }, registerCloudService: (contextProvider) => { this.contextProviders.push(contextProvider); @@ -145,6 +147,7 @@ export class CloudPlugin implements Plugin { isServerlessEnabled: this.isServerlessEnabled, serverless: { projectId: this.config.serverless?.project_id, + projectName: this.config.serverless?.project_name, }, performanceUrl, usersAndRolesUrl, diff --git a/x-pack/plugins/cloud/public/types.ts b/x-pack/plugins/cloud/public/types.ts index a42730905c9c7..766a0050587d8 100644 --- a/x-pack/plugins/cloud/public/types.ts +++ b/x-pack/plugins/cloud/public/types.ts @@ -72,6 +72,11 @@ export interface CloudStart { * Will always be present if `isServerlessEnabled` is `true` */ projectId?: string; + /** + * The serverless project name. + * Will always be present if `isServerlessEnabled` is `true` + */ + projectName?: string; }; } @@ -172,5 +177,10 @@ export interface CloudSetup { * Will always be present if `isServerlessEnabled` is `true` */ projectId?: string; + /** + * The serverless project name. + * Will always be present if `isServerlessEnabled` is `true` + */ + projectName?: string; }; } diff --git a/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap b/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap index 505c66345d77b..fd8942409b388 100644 --- a/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap +++ b/x-pack/plugins/cloud/server/__snapshots__/plugin.test.ts.snap @@ -20,6 +20,7 @@ Object { "projectsUrl": "https://cloud.elastic.co/projects/", "serverless": Object { "projectId": undefined, + "projectName": undefined, }, "trialEndDate": undefined, } diff --git a/x-pack/plugins/cloud/server/config.test.ts b/x-pack/plugins/cloud/server/config.test.ts new file mode 100644 index 0000000000000..e1cc0107d9494 --- /dev/null +++ b/x-pack/plugins/cloud/server/config.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { config } from './config'; + +describe('Cloud plugin config', () => { + it('evicts unknown properties under the `serverless` structure', () => { + const output = config.schema.validate({ + serverless: { + project_id: 'project_id', + unknown_prop: 'some unknown prop', + }, + }); + + expect(output.serverless).toEqual({ + project_id: 'project_id', + }); + }); +}); diff --git a/x-pack/plugins/cloud/server/config.ts b/x-pack/plugins/cloud/server/config.ts index d1fb2bb1f44ab..8ffc0906252cf 100644 --- a/x-pack/plugins/cloud/server/config.ts +++ b/x-pack/plugins/cloud/server/config.ts @@ -33,9 +33,14 @@ const configSchema = schema.object({ trial_end_date: schema.maybe(schema.string()), is_elastic_staff_owned: schema.maybe(schema.boolean()), serverless: schema.maybe( - schema.object({ - project_id: schema.string(), - }) + schema.object( + { + project_id: schema.string(), + project_name: schema.maybe(schema.string()), + }, + // avoid future chicken-and-egg situation with the component populating the config + { unknowns: 'ignore' } + ) ), }); @@ -57,6 +62,7 @@ export const config: PluginConfigDescriptor = { is_elastic_staff_owned: true, serverless: { project_id: true, + project_name: true, }, }, schema: configSchema, diff --git a/x-pack/plugins/cloud/server/mocks.ts b/x-pack/plugins/cloud/server/mocks.ts index 6f06b9639d960..01352ac9dab0a 100644 --- a/x-pack/plugins/cloud/server/mocks.ts +++ b/x-pack/plugins/cloud/server/mocks.ts @@ -28,6 +28,7 @@ function createSetupMock(): jest.Mocked { isServerlessEnabled: false, serverless: { projectId: undefined, + projectName: undefined, }, }; } diff --git a/x-pack/plugins/cloud/server/plugin.test.ts b/x-pack/plugins/cloud/server/plugin.test.ts index 0309271a8ea63..7790be5e36e28 100644 --- a/x-pack/plugins/cloud/server/plugin.test.ts +++ b/x-pack/plugins/cloud/server/plugin.test.ts @@ -124,6 +124,16 @@ describe('Cloud Plugin', () => { }); expect(setup.serverless.projectId).toBe('my-awesome-project'); }); + + it('exposes `serverless.projectName`', () => { + const { setup } = setupPlugin({ + serverless: { + project_id: 'my-awesome-project', + project_name: 'My Awesome Project', + }, + }); + expect(setup.serverless.projectName).toBe('My Awesome Project'); + }); }); }); diff --git a/x-pack/plugins/cloud/server/plugin.ts b/x-pack/plugins/cloud/server/plugin.ts index 5838f5086fa53..efdcf9ebbe216 100644 --- a/x-pack/plugins/cloud/server/plugin.ts +++ b/x-pack/plugins/cloud/server/plugin.ts @@ -106,6 +106,11 @@ export interface CloudSetup { * Will always be present if `isServerlessEnabled` is `true` */ projectId?: string; + /** + * The serverless project name. + * Will always be present if `isServerlessEnabled` is `true` + */ + projectName?: string; }; } @@ -175,6 +180,7 @@ export class CloudPlugin implements Plugin { isServerlessEnabled, serverless: { projectId: this.config.serverless?.project_id, + projectName: this.config.serverless?.project_name, }, }; } diff --git a/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts b/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts index 0cbfeb509e8b3..6eb9e01f333b0 100644 --- a/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts +++ b/x-pack/plugins/cloud_integrations/cloud_experiments/common/constants.ts @@ -21,6 +21,12 @@ export enum FEATURE_FLAG_NAMES { * It resolves the URL that the button "Add Integrations" will point to. */ 'security-solutions.add-integrations-url' = 'security-solutions.add-integrations-url', + /** + * Used in the Security Solutions guided onboarding tour. + * Returns JSON corresponding to the tour guide config as + * defined by type { GuideConfig } from '@kbn/guided-onboarding'; + */ + 'security-solutions.guided-onboarding-content' = 'security-solutions.guided-onboarding-content', } /** diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_cis_kubernetes_integration.tsx b/x-pack/plugins/cloud_security_posture/public/common/api/use_cis_kubernetes_integration.tsx index 0ee08d915c0d1..e5f226a3c3352 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_cis_kubernetes_integration.tsx +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_cis_kubernetes_integration.tsx @@ -10,6 +10,7 @@ import { epmRouteService, type GetInfoResponse, type DefaultPackagesInstallationError, + API_VERSIONS, } from '@kbn/fleet-plugin/common'; import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../../../common/constants'; import { useKibana } from '../hooks/use_kibana'; @@ -21,6 +22,8 @@ export const useCisKubernetesIntegration = () => { const { http } = useKibana().services; return useQuery(['integrations'], () => - http.get(epmRouteService.getInfoPath(CLOUD_SECURITY_POSTURE_PACKAGE_NAME)) + http.get(epmRouteService.getInfoPath(CLOUD_SECURITY_POSTURE_PACKAGE_NAME), { + version: API_VERSIONS.public.v1, + }) ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/common/navigation/use_navigate_to_cis_integration_policies.ts b/x-pack/plugins/cloud_security_posture/public/common/navigation/use_navigate_to_cis_integration_policies.ts index 350d7a8f38dac..af1dc5e795485 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/navigation/use_navigate_to_cis_integration_policies.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/navigation/use_navigate_to_cis_integration_policies.ts @@ -8,18 +8,35 @@ import { pagePathGetters, pkgKeyFromPackageInfo } from '@kbn/fleet-plugin/public'; import { useCisKubernetesIntegration } from '../api/use_cis_kubernetes_integration'; import { useKibana } from '../hooks/use_kibana'; +import { useCspBenchmarkIntegrations } from '../../pages/benchmarks/use_csp_benchmark_integrations'; +import { PostureTypes } from '../../../common/types'; export const useCISIntegrationPoliciesLink = ({ - addAgentToPolicyId = '', - integration = '', + postureType, }: { - addAgentToPolicyId?: string; - integration?: string; + postureType: PostureTypes; }): string | undefined => { const { http } = useKibana().services; const cisIntegration = useCisKubernetesIntegration(); + // using an existing hook to get agent id and package policy id + const cspBenchmarkIntegrations = useCspBenchmarkIntegrations({ + name: '', + page: 1, + perPage: 100, + sortField: 'package_policy.name', + sortOrder: 'asc', + }); if (!cisIntegration.isSuccess) return; + const intergrations = cspBenchmarkIntegrations.data?.items; + const matchedIntegration = intergrations?.find( + (integration) => + integration?.package_policy?.inputs?.find((input) => input?.enabled)?.policy_template === + postureType + ); + const addAgentToPolicyId = matchedIntegration?.agent_policy.id || ''; + const integration = matchedIntegration?.package_policy.id || ''; + const path = pagePathGetters .integration_details_policies({ addAgentToPolicyId, diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.tsx b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.tsx index 292831821173e..422695c7ff576 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states.tsx @@ -22,7 +22,6 @@ import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../common/constants'; import { FullSizeCenteredPage } from './full_size_centered_page'; -import { useCspBenchmarkIntegrations } from '../pages/benchmarks/use_csp_benchmark_integrations'; import { useCISIntegrationPoliciesLink } from '../common/navigation/use_navigate_to_cis_integration_policies'; import { CSPM_NOT_INSTALLED_ACTION_SUBJ, @@ -37,21 +36,9 @@ import noDataIllustration from '../assets/illustrations/no_data_illustration.svg import { useCspIntegrationLink } from '../common/navigation/use_csp_integration_link'; import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../common/constants'; -const NotDeployed = () => { - // using an existing hook to get agent id and package policy id - const benchmarks = useCspBenchmarkIntegrations({ - name: '', - page: 1, - perPage: 1, - sortField: 'package_policy.name', - sortOrder: 'asc', - }); - - // the ids are not a must, but as long as we have them we can open the add agent flyout - const firstBenchmark = benchmarks.data?.items?.[0]; +const NotDeployed = ({ postureType }: { postureType: PostureTypes }) => { const integrationPoliciesLink = useCISIntegrationPoliciesLink({ - addAgentToPolicyId: firstBenchmark?.agent_policy.id || '', - integration: firstBenchmark?.package_policy.id || '', + postureType, }); return ( @@ -280,7 +267,7 @@ export const NoFindingsStates = ({ posturetype }: { posturetype: PostureTypes }) .map((idxDetails: IndexDetails) => idxDetails.index) .sort((a, b) => a.localeCompare(b)); const render = () => { - if (status === 'not-deployed') return ; // integration installed, but no agents added + if (status === 'not-deployed') return ; // integration installed, but no agents added if (status === 'indexing' || status === 'waiting_for_results') return ; // agent added, index timeout hasn't passed since installation if (status === 'index-timeout') return ; // agent added, index timeout has passed if (status === 'unprivileged') diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx b/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx index bfa92c2ef6ece..7dee3e94e70a6 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx @@ -33,7 +33,7 @@ import { import noDataIllustration from '../assets/illustrations/no_data_illustration.svg'; import { useCspIntegrationLink } from '../common/navigation/use_csp_integration_link'; import { useCISIntegrationPoliciesLink } from '../common/navigation/use_navigate_to_cis_integration_policies'; -import { useCspBenchmarkIntegrations } from '../pages/benchmarks/use_csp_benchmark_integrations'; +import { PostureTypes } from '../../common/types'; const REFETCH_INTERVAL_MS = 20000; @@ -191,21 +191,9 @@ const Unprivileged = ({ unprivilegedIndices }: { unprivilegedIndices: string[] } } /> ); -const AgentNotDeployedEmptyPrompt = () => { - // using an existing hook to get agent id and package policy id - const benchmarks = useCspBenchmarkIntegrations({ - name: '', - page: 1, - perPage: 1, - sortField: 'package_policy.name', - sortOrder: 'asc', - }); - - // the ids are not a must, but as long as we have them we can open the add agent flyout - const firstBenchmark = benchmarks.data?.items?.[0]; +const AgentNotDeployedEmptyPrompt = ({ postureType }: { postureType: PostureTypes }) => { const integrationPoliciesLink = useCISIntegrationPoliciesLink({ - addAgentToPolicyId: firstBenchmark?.agent_policy.id || '', - integration: firstBenchmark?.package_policy.id || '', + postureType, }); return ( @@ -268,7 +256,8 @@ export const NoVulnerabilitiesStates = () => { return ( ); - if (status === 'not-deployed') return ; + if (status === 'not-deployed') + return ; if (status === 'unprivileged') return ; // user has no privileges for our indices }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx index d6d4f2acb8c42..b39bf81a5d31a 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/benchmarks/benchmarks.tsx @@ -68,8 +68,8 @@ const BenchmarkEmptyState = ({ name }: { name: string }) => ( {name && ( ( @@ -154,10 +154,9 @@ export const Benchmarks = () => { data-test-subj={TEST_SUBJ.BENCHMARKS_PAGE_HEADER} pageTitle={ } rightSideItems={[]} diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx index 18f36810d03f6..21ab126449470 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx @@ -10,10 +10,11 @@ import { CodeEditor } from '@kbn/kibana-react-plugin/public'; import { XJsonLang } from '@kbn/monaco'; import { CspFinding } from '../../../../common/schemas/csp_finding'; -const offsetHeight = 120; +const offsetTopHeight = 120; +const offsetBottomHeight = 72; export const JsonTab = ({ data }: { data: CspFinding }) => ( -
    +
    ) diff --git a/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_integration.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_integration.tsx index 3743127e9b9bd..6d1a01b3d3c2e 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_integration.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_csp_integration.tsx @@ -10,6 +10,7 @@ import { type GetOnePackagePolicyResponse, packagePolicyRouteService, agentPolicyRouteService, + API_VERSIONS, } from '@kbn/fleet-plugin/common'; import { type PageUrlParams } from './rules_container'; import { useKibana } from '../../common/hooks/use_kibana'; @@ -20,10 +21,14 @@ export const useCspIntegrationInfo = ({ packagePolicyId, policyId }: PageUrlPara return useQuery(['cspRulesInfo', { packagePolicyId, policyId }], () => Promise.all([ http - .get(packagePolicyRouteService.getInfoPath(packagePolicyId)) + .get(packagePolicyRouteService.getInfoPath(packagePolicyId), { + version: API_VERSIONS.public.v1, + }) .then((response) => response.item), http - .get(agentPolicyRouteService.getInfoPath(policyId)) + .get(agentPolicyRouteService.getInfoPath(policyId), { + version: API_VERSIONS.public.v1, + }) .then((response) => response.item), ]) ); diff --git a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx index 9669188f45123..7e1ea426f0637 100644 --- a/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx +++ b/x-pack/plugins/data_visualizer/public/application/index_data_visualizer/index_data_visualizer.tsx @@ -17,7 +17,7 @@ import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-pl import { StorageContextProvider } from '@kbn/ml-local-storage'; import { DataView } from '@kbn/data-views-plugin/public'; import { getNestedProperty } from '@kbn/ml-nested-property'; -import { DatePickerContextProvider } from '@kbn/ml-date-picker'; +import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { Provider as UrlStateContextProvider, @@ -263,9 +263,12 @@ export const DataVisualizerStateContextProvider: FC = ({ getAdditionalLinks }) => { + isServerless?: boolean; +} + +export const IndexDataVisualizer: FC = ({ getAdditionalLinks, isServerless = false }) => { const coreStart = getCoreStart(); const { data, @@ -296,9 +299,10 @@ export const IndexDataVisualizer: FC<{ unifiedSearch, ...coreStart, }; - const datePickerDeps = { + const datePickerDeps: DatePickerDependencies = { ...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), uiSettingsKeys: UI_SETTINGS, + isServerless, }; return ( diff --git a/x-pack/plugins/fleet/.storybook/context/cloud.ts b/x-pack/plugins/fleet/.storybook/context/cloud.ts index fbb0b3f85ac5e..9acbbd221059b 100644 --- a/x-pack/plugins/fleet/.storybook/context/cloud.ts +++ b/x-pack/plugins/fleet/.storybook/context/cloud.ts @@ -21,6 +21,7 @@ export const getCloud = ({ isCloudEnabled }: { isCloudEnabled: boolean }) => { isServerlessEnabled: false, serverless: { projectId: undefined, + projectName: undefined, }, }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx index 89ff4b5d0de7a..9687b81be5698 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_headers.tsx @@ -38,8 +38,15 @@ export const OutputFormKafkaHeaders: React.FunctionComponent<{ inputs: OutputFor const handleKeyValuePairChange = useCallback( (index: number, field: 'key' | 'value', value: string) => { - const updatedPairs = [...keyValuePairs]; - updatedPairs[index][field] = value; + const updatedPairs = keyValuePairs.map((pair, i) => { + if (i === index) { + return { + ...pair, + [field]: value, + }; + } + return pair; + }); onChange(updatedPairs); }, [keyValuePairs, onChange] diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_topics.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_topics.tsx index 55b76ccf84c57..9360a5c35bcd5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_topics.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_form_kafka_topics.tsx @@ -94,17 +94,29 @@ export const OutputFormKafkaTopics: React.FunctionComponent<{ inputs: OutputForm const handleTopicProcessorChange = useCallback( (index: number, field: 'topic' | 'condition' | 'type', value: string) => { - const updatedPairs = [...topics]; - if (field === 'topic') { - updatedPairs[index].topic = value; - } else { - updatedPairs[index].when = { - ...(updatedPairs[index].when || {}), - ...((field === 'condition' ? { condition: value } : {}) as { condition?: string }), - ...((field === 'type' ? { type: value } : {}) as { type?: ValueOf }), - }; - } - onChange(updatedPairs); + const updatedTopics = topics.map((topic, i) => { + if (i === index) { + if (field === 'topic') { + return { + ...topic, + topic: value, + }; + } else { + return { + ...topic, + when: { + ...(topic.when || {}), + ...((field === 'condition' ? { condition: value } : {}) as { condition?: string }), + ...((field === 'type' ? { type: value } : {}) as { + type?: ValueOf; + }), + }, + }; + } + } + return topic; + }); + onChange(updatedTopics); }, [topics, onChange] ); diff --git a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts index e73a6aaac9c30..cbc560cc72dc8 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/handlers.ts @@ -376,7 +376,6 @@ export const updatePackagePolicyHandler: FleetRequestHandler< vars: body.vars ?? packagePolicy.vars, } as NewPackagePolicy; } - const updatedPackagePolicy = await packagePolicyService.update( soClient, esClient, @@ -394,6 +393,12 @@ export const updatePackagePolicyHandler: FleetRequestHandler< }, }); } catch (error) { + if (error.statusCode) { + return response.customError({ + statusCode: error.statusCode, + body: { message: error.message }, + }); + } return defaultFleetErrorHandler({ error, response }); } }; diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 6d47be75b4fd6..46ac72f69ecab 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -705,6 +705,9 @@ class PackagePolicyClientImpl implements PackagePolicyClient { const logger = appContextService.getLogger(); logger.error(`An error occurred executing "packagePolicyUpdate" callback: ${error}`); logger.error(error); + if (error.apiPassThrough) { + throw error; + } enrichedPackagePolicy = packagePolicyUpdate; } diff --git a/x-pack/plugins/infra/kibana.jsonc b/x-pack/plugins/infra/kibana.jsonc index ee8e8baa83337..60731cf699ccd 100644 --- a/x-pack/plugins/infra/kibana.jsonc +++ b/x-pack/plugins/infra/kibana.jsonc @@ -21,6 +21,7 @@ "fieldFormats", "lens", "logsShared", + "metricsDataAccess", "observability", "observabilityAIAssistant", "observabilityShared", diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_render_props.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_render_props.ts index eab5f8326f525..b8b857ae5ab94 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_render_props.ts +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_render_props.ts @@ -21,12 +21,12 @@ export function useAssetDetailsRenderProps({ props }: UseAssetDetailsRenderProps // When the asset asset.name is known we can load the page faster // Otherwise we need to use metadata response. - const loading = !urlState?.name && !asset.name && !metadata?.name; + const loading = !asset.name && !urlState?.name && !metadata?.name; return { asset: { ...asset, - name: urlState?.name || asset.name || metadata?.name || '', + name: asset.name || urlState?.name || metadata?.name || '', }, assetType, overrides, diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts index 525a5b635e19b..305e934c59dce 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_url_state.ts @@ -9,14 +9,13 @@ import * as rt from 'io-ts'; import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; +import { useCallback } from 'react'; import { ContentTabIds } from '../types'; import { useUrlState } from '../../../utils/use_url_state'; import { ASSET_DETAILS_URL_STATE_KEY } from '../constants'; -import { getDefaultDateRange } from '../utils'; export const DEFAULT_STATE: AssetDetailsUrlState = { tabId: ContentTabIds.OVERVIEW, - dateRange: getDefaultDateRange(), }; type SetAssetDetailsState = (newProp: Payload | null) => void; @@ -29,18 +28,21 @@ export const useAssetDetailsUrlState = (): [AssetDetailsUrl, SetAssetDetailsStat urlStateKey: ASSET_DETAILS_URL_STATE_KEY, }); - const setAssetDetailsState = (newProps: Payload | null) => { - if (!newProps) { - setUrlState(DEFAULT_STATE); - } else { - const payload = Object.fromEntries( - Object.entries(newProps).filter(([_, v]) => !!v || v === '') - ); - setUrlState({ ...(urlState ?? DEFAULT_STATE), ...payload }); - } - }; + const setAssetDetailsState = useCallback( + (newProps: Payload | null) => { + if (!newProps) { + setUrlState(null); + } else { + const payload = Object.fromEntries( + Object.entries(newProps ?? {}).filter(([_, v]) => !!v || v === '') + ); + setUrlState((previous) => ({ ...previous, ...payload })); + } + }, + [setUrlState] + ); - return [urlState as AssetDetailsUrl, setAssetDetailsState]; + return [urlState, setAssetDetailsState]; }; const TabIdRT = rt.union([ @@ -52,21 +54,17 @@ const TabIdRT = rt.union([ rt.literal(ContentTabIds.OSQUERY), ]); -const AssetDetailsUrlStateRT = rt.intersection([ - rt.type({ - dateRange: rt.type({ - from: rt.string, - to: rt.string, - }), +const AssetDetailsUrlStateRT = rt.partial({ + dateRange: rt.type({ + from: rt.string, + to: rt.string, }), - rt.partial({ - tabId: TabIdRT, - name: rt.string, - processSearch: rt.string, - metadataSearch: rt.string, - logsSearch: rt.string, - }), -]); + tabId: TabIdRT, + name: rt.string, + processSearch: rt.string, + metadataSearch: rt.string, + logsSearch: rt.string, +}); const AssetDetailsUrlRT = rt.union([AssetDetailsUrlStateRT, rt.null]); diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts index 345d197f23945..3f3e89f7c9a23 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts @@ -14,7 +14,7 @@ import { getDefaultDateRange, toTimestampRange } from '../utils'; import { useAssetDetailsUrlState } from './use_asset_details_url_state'; export interface UseDateRangeProviderProps { - initialDateRange: TimeRange; + initialDateRange?: TimeRange; } export function useDateRangeProvider({ diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx new file mode 100644 index 0000000000000..54305b7212a55 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useMemo } from 'react'; + +import type { DataView } from '@kbn/data-views-plugin/public'; +import { TimeRange } from '@kbn/es-query'; +import { LensChart, TooltipContent } from '../../../../lens'; +import { AVERAGE_SUBTITLE, type KPIChartProps } from '../../../../../common/visualizations'; +import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; + +import { useDateRangeProviderContext } from '../../../hooks/use_date_range'; + +export const Kpi = ({ + id, + title, + layers, + toolTip, + height, + dataView, + assetName, + dateRange, +}: KPIChartProps & { + height: number; + dataView?: DataView; + assetName: string; + dateRange: TimeRange; +}) => { + const { refreshTs } = useDateRangeProviderContext(); + const filters = useMemo(() => { + return [ + buildCombinedHostsFilter({ + field: 'host.name', + values: [assetName], + dataView, + }), + ]; + }, [dataView, assetName]); + + const tooltipContent = useMemo(() => , [toolTip]); + + return ( + + ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx index 011cb94c35253..034d6feaacfcd 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi_grid.tsx @@ -5,57 +5,33 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { TimeRange } from '@kbn/es-query'; -import { LensChart, TooltipContent } from '../../../../lens'; -import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; -import { - assetDetailsDashboards, - KPI_CHART_HEIGHT, - AVERAGE_SUBTITLE, -} from '../../../../../common/visualizations'; -import { useDateRangeProviderContext } from '../../../hooks/use_date_range'; +import { assetDetailsDashboards, KPI_CHART_HEIGHT } from '../../../../../common/visualizations'; +import { Kpi } from './kpi'; interface Props { dataView?: DataView; - nodeName: string; - timeRange: TimeRange; + assetName: string; + dateRange: TimeRange; } -export const KPIGrid = React.memo(({ nodeName, dataView, timeRange }: Props) => { - const { refreshTs } = useDateRangeProviderContext(); - const filters = useMemo(() => { - return [ - buildCombinedHostsFilter({ - field: 'host.name', - values: [nodeName], - dataView, - }), - ]; - }, [dataView, nodeName]); - +export const KPIGrid = ({ assetName, dataView, dateRange }: Props) => { return ( - {assetDetailsDashboards.host.hostKPICharts.map(({ id, layers, title, toolTip }, index) => ( + {assetDetailsDashboards.host.hostKPICharts.map((chartProps, index) => ( - } - visualizationType="lnsMetric" - disableTriggers - hidePanelTitles /> ))} ); -}); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx new file mode 100644 index 0000000000000..b0c3edf983ee7 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useCallback, useMemo } from 'react'; +import type { XYVisualOptions } from '@kbn/lens-embeddable-utils'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import { TimeRange } from '@kbn/es-query'; +import type { XYConfig } from '../../../../../common/visualizations/lens/dashboards/asset_details/metric_charts/types'; +import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; +import { BrushEndArgs, LensChart, OnFilterEvent } from '../../../../lens'; +import { METRIC_CHART_HEIGHT } from '../../../constants'; +import { useDateRangeProviderContext } from '../../../hooks/use_date_range'; +import { extractRangeFromChartFilterEvent } from './chart_utils'; + +export interface ChartProps extends XYConfig { + visualOptions?: XYVisualOptions; + metricsDataView?: DataView; + logsDataView?: DataView; + dateRange: TimeRange; + assetName: string; + ['data-test-subj']: string; +} + +export const Chart = ({ + id, + title, + layers, + metricsDataView, + logsDataView, + visualOptions, + dataViewOrigin, + overrides, + dateRange, + assetName, + ...props +}: ChartProps) => { + const { setDateRange } = useDateRangeProviderContext(); + + const dataView = useMemo(() => { + return dataViewOrigin === 'metrics' ? metricsDataView : logsDataView; + }, [dataViewOrigin, logsDataView, metricsDataView]); + + const filters = useMemo(() => { + return [ + buildCombinedHostsFilter({ + field: 'host.name', + values: [assetName], + dataView, + }), + ]; + }, [assetName, dataView]); + + const handleBrushEnd = useCallback( + ({ range, preventDefault }: BrushEndArgs) => { + setDateRange({ + from: new Date(range[0]).toISOString(), + to: new Date(range[1]).toISOString(), + }); + + preventDefault(); + }, + [setDateRange] + ); + + const handleFilter = useCallback( + (event: OnFilterEvent) => { + const range = extractRangeFromChartFilterEvent(event); + + if (range === null) { + return; + } + + setDateRange(range); + event.preventDefault(); + }, + [setDateRange] + ); + + return ( + + ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart_utils.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart_utils.ts index 1eba3da363559..a141c565d2642 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart_utils.ts +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart_utils.ts @@ -8,12 +8,10 @@ import { MultiValueClickContext } from '@kbn/embeddable-plugin/public'; import { TimeRange } from '@kbn/es-query'; import { DatatableColumn, DatatableRow } from '@kbn/expressions-plugin/common/expression_types'; -import { LensEmbeddableInput } from '@kbn/lens-plugin/public'; +import type { OnFilterEvent } from '../../../../lens'; type ChartClickContextData = MultiValueClickContext['data']['data']; -export type OnFilterEvent = Parameters>[0]; - export function isChartClickContextData(data: unknown): data is ChartClickContextData { return Array.isArray(data) && Array.isArray(data[0]?.cells) && data[0].cells.length > 0; } diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_charts_section.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_charts_section.tsx deleted file mode 100644 index 0b27254fdc146..0000000000000 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_charts_section.tsx +++ /dev/null @@ -1,148 +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, useMemo } from 'react'; - -import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import type { TimeRange } from '@kbn/es-query'; -import { LensEmbeddableInput } from '@kbn/lens-plugin/public'; -import { XY_MISSING_VALUE_DOTTED_LINE_CONFIG } from '../../../../../common/visualizations'; -import type { XYConfig } from '../../../../../common/visualizations/lens/dashboards/asset_details/metric_charts/types'; -import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; -import { LensChart } from '../../../../lens'; -import { METRIC_CHART_HEIGHT } from '../../../constants'; -import { useDateRangeProviderContext } from '../../../hooks/use_date_range'; -import { useMetadataStateProviderContext } from '../../../hooks/use_metadata_state'; -import type { DataViewOrigin } from '../../../types'; -import type { OnFilterEvent } from './chart_utils'; -import { extractRangeFromChartFilterEvent } from './chart_utils'; - -type BrushEndArgs = Parameters>[0]; - -interface ChartGridProps { - assetName: string; - timeRange: TimeRange; - metricsDataView?: DataView; - logsDataView?: DataView; - charts: Array; - ['data-test-subj']: string; -} - -export const ChartGrid = React.memo( - ({ assetName, metricsDataView, logsDataView, timeRange, charts, ...props }: ChartGridProps) => { - const { setDateRange } = useDateRangeProviderContext(); - const getDataView = useCallback( - (dataViewOrigin: DataViewOrigin) => { - return dataViewOrigin === 'metrics' ? metricsDataView : logsDataView; - }, - [logsDataView, metricsDataView] - ); - const { metadata } = useMetadataStateProviderContext(); - - const getFilters = useCallback( - (dataViewOrigin: DataViewOrigin) => { - return [ - buildCombinedHostsFilter({ - field: 'host.name', - values: [assetName], - dataView: getDataView(dataViewOrigin), - }), - ]; - }, - [getDataView, assetName] - ); - - const handleBrushEnd = useCallback( - ({ range, preventDefault }: BrushEndArgs) => { - setDateRange({ - from: new Date(range[0]).toISOString(), - to: new Date(range[1]).toISOString(), - }); - - preventDefault(); - }, - [setDateRange] - ); - - const handleFilter = useCallback( - (event: OnFilterEvent) => { - const range = extractRangeFromChartFilterEvent(event); - - if (range === null) { - return; - } - - setDateRange(range); - event.preventDefault(); - }, - [setDateRange] - ); - - const chartsToRender = useMemo( - () => - charts.filter( - (c) => - !c.dependsOn || - c.dependsOn.every((d) => (metadata?.features ?? []).some((f) => d === f.name)) - ), - [charts, metadata?.features] - ); - - return ( - - {chartsToRender.map(({ dataViewOrigin, id, layers, title, overrides }, index) => ( - - - - ))} - - ); - } -); - -export const Section = ({ - title, - dependsOn = [], - children, -}: { - title: React.FunctionComponent; - dependsOn?: string[]; - children: React.ReactNode; -}) => { - const Title = title; - const { metadata } = useMetadataStateProviderContext(); - - const shouldRender = useMemo( - () => - dependsOn.length === 0 || - dependsOn.some((p) => (metadata?.features ?? []).some((f) => f.name === p)), - [dependsOn, metadata?.features] - ); - - return shouldRender ? ( - - - - </EuiFlexItem> - <EuiFlexItem grow={false}>{children}</EuiFlexItem> - </EuiFlexGroup> - ) : null; -}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx index 0ec0f51dcd18f..d7ed6509f0812 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx @@ -4,77 +4,57 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; - -import { EuiSpacer } from '@elastic/eui'; +import React, { useMemo } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; +import { EuiFlexItem, EuiFlexGrid } from '@elastic/eui'; import type { TimeRange } from '@kbn/es-query'; -import { assetDetailsDashboards } from '../../../../../common/visualizations'; -import { ChartGrid, Section } from './metrics_charts_section'; -import { MetricsSectionTitle, NginxMetricsSectionTitle } from '../../../components/section_titles'; +import type { XYConfig } from '../../../../../common/visualizations/lens/dashboards/asset_details/metric_charts/types'; +import { useMetadataStateProviderContext } from '../../../hooks/use_metadata_state'; +import { Chart } from './chart'; interface Props { assetName: string; dateRange: TimeRange; metricsDataView?: DataView; logsDataView?: DataView; + charts: Array<XYConfig & { dependsOn?: string[] }>; + ['data-test-subj']: string; } -const { host, nginx } = assetDetailsDashboards; +export const MetricsGrid = ({ + assetName, + metricsDataView, + logsDataView, + dateRange, + charts, + ...props +}: Props) => { + const { metadata } = useMetadataStateProviderContext(); -export const MetricsGrid = React.memo( - ({ assetName, metricsDataView, logsDataView, dateRange: timeRange }: Props) => { - return ( - <> - <Section title={MetricsSectionTitle}> - <ChartGrid + const chartsToRender = useMemo( + () => + charts.filter( + (c) => + !c.dependsOn || + c.dependsOn.every((d) => (metadata?.features ?? []).some((f) => d === f.name)) + ), + [charts, metadata?.features] + ); + + return ( + <EuiFlexGrid columns={2} gutterSize="s" data-test-subj={`${props['data-test-subj']}Grid`}> + {chartsToRender.map((chartProp, index) => ( + <EuiFlexItem key={index} grow={false}> + <Chart + {...chartProp} assetName={assetName} - timeRange={timeRange} - charts={host.hostMetricChartsFullPage} - metricsDataView={metricsDataView} + dateRange={dateRange} logsDataView={logsDataView} - data-test-subj="infraAssetDetailsMetricsChart" - /> - </Section> - <EuiSpacer size="s" /> - <Section dependsOn={['nginx.stubstatus', 'nginx.access']} title={NginxMetricsSectionTitle}> - <ChartGrid - assetName={assetName} - timeRange={timeRange} - charts={[ - ...nginx.nginxStubstatusCharts.map((chart) => ({ - ...chart, - dependsOn: ['nginx.stubstatus'], - })), - ...nginx.nginxAccessCharts.map((chart) => ({ - ...chart, - dependsOn: ['nginx.access'], - })), - ]} metricsDataView={metricsDataView} - logsDataView={logsDataView} - data-test-subj="infraAssetDetailsNginxMetricsChart" + data-test-subj={props['data-test-subj']} /> - </Section> - </> - ); - } -); - -export const MetricsGridCompact = ({ - assetName, - metricsDataView, - logsDataView, - dateRange: timeRange, -}: Props) => ( - <Section title={MetricsSectionTitle}> - <ChartGrid - assetName={assetName} - timeRange={timeRange} - charts={host.hostMetricFlyoutCharts} - metricsDataView={metricsDataView} - logsDataView={logsDataView} - data-test-subj="infraAssetDetailsMetricsChart" - /> - </Section> -); + </EuiFlexItem> + ))} + </EuiFlexGrid> + ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx new file mode 100644 index 0000000000000..e76397b689ca9 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx @@ -0,0 +1,109 @@ +/* + * 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 { EuiSpacer, EuiFlexItem } from '@elastic/eui'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import type { TimeRange } from '@kbn/es-query'; +import { EuiFlexGroup } from '@elastic/eui'; +import { assetDetailsDashboards } from '../../../../../common/visualizations'; +import { MetricsSectionTitle, NginxMetricsSectionTitle } from '../../../components/section_titles'; +import { useMetadataStateProviderContext } from '../../../hooks/use_metadata_state'; +import { MetricsGrid } from './metrics_grid'; + +interface Props { + assetName: string; + dateRange: TimeRange; + metricsDataView?: DataView; + logsDataView?: DataView; +} + +const { host, nginx } = assetDetailsDashboards; + +export const MetricsSection = ({ assetName, metricsDataView, logsDataView, dateRange }: Props) => { + return ( + <> + <Section title={MetricsSectionTitle}> + <MetricsGrid + assetName={assetName} + dateRange={dateRange} + charts={host.hostMetricChartsFullPage} + metricsDataView={metricsDataView} + logsDataView={logsDataView} + data-test-subj="infraAssetDetailsMetricsChart" + /> + </Section> + <EuiSpacer size="s" /> + <Section dependsOn={['nginx.stubstatus', 'nginx.access']} title={NginxMetricsSectionTitle}> + <MetricsGrid + assetName={assetName} + dateRange={dateRange} + charts={[ + ...nginx.nginxStubstatusCharts.map((chart) => ({ + ...chart, + dependsOn: ['nginx.stubstatus'], + })), + ...nginx.nginxAccessCharts.map((chart) => ({ + ...chart, + dependsOn: ['nginx.access'], + })), + ]} + metricsDataView={metricsDataView} + logsDataView={logsDataView} + data-test-subj="infraAssetDetailsNginxMetricsChart" + /> + </Section> + </> + ); +}; + +export const MetricsSectionCompact = ({ + assetName, + metricsDataView, + logsDataView, + dateRange, +}: Props) => ( + <Section title={MetricsSectionTitle}> + <MetricsGrid + assetName={assetName} + dateRange={dateRange} + charts={host.hostMetricFlyoutCharts} + metricsDataView={metricsDataView} + logsDataView={logsDataView} + data-test-subj="infraAssetDetailsMetricsChart" + /> + </Section> +); + +const Section = ({ + title, + dependsOn = [], + children, +}: { + title: React.FunctionComponent; + dependsOn?: string[]; + children: React.ReactNode; +}) => { + const Title = title; + const { metadata } = useMetadataStateProviderContext(); + + const shouldRender = useMemo( + () => + dependsOn.length === 0 || + dependsOn.some((p) => (metadata?.features ?? []).some((f) => f.name === p)), + [dependsOn, metadata?.features] + ); + + return shouldRender ? ( + <EuiFlexGroup gutterSize="m" direction="column"> + <EuiFlexItem grow={false}> + <Title /> + </EuiFlexItem> + <EuiFlexItem grow={false}>{children}</EuiFlexItem> + </EuiFlexGroup> + ) : null; +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx index ffc2d46179146..37478884880b8 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -15,7 +15,7 @@ import { } from './metadata_summary/metadata_summary_list'; import { AlertsSummaryContent } from './alerts'; import { KPIGrid } from './kpis/kpi_grid'; -import { MetricsGrid, MetricsGridCompact } from './metrics/metrics_grid'; +import { MetricsSection, MetricsSectionCompact } from './metrics/metrics_section'; import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props'; import { useMetadataStateProviderContext } from '../../hooks/use_metadata_state'; import { useDataViewsProviderContext } from '../../hooks/use_data_views'; @@ -32,18 +32,18 @@ export const Overview = () => { } = useMetadataStateProviderContext(); const { logs, metrics } = useDataViewsProviderContext(); - const parsedDateRange = getParsedDateRange(); + const parsedDateRange = useMemo(() => getParsedDateRange(), [getParsedDateRange]); const isFullPageView = renderMode.mode !== 'flyout'; const metricsSection = isFullPageView ? ( - <MetricsGrid + <MetricsSection dateRange={parsedDateRange} logsDataView={logs.dataView} metricsDataView={metrics.dataView} assetName={asset.name} /> ) : ( - <MetricsGridCompact + <MetricsSectionCompact dateRange={parsedDateRange} logsDataView={logs.dataView} metricsDataView={metrics.dataView} @@ -59,7 +59,7 @@ export const Overview = () => { return ( <EuiFlexGroup direction="column" gutterSize="m"> <EuiFlexItem grow={false}> - <KPIGrid nodeName={asset.name} timeRange={parsedDateRange} dataView={metrics.dataView} /> + <KPIGrid assetName={asset.name} dateRange={parsedDateRange} dataView={metrics.dataView} /> </EuiFlexItem> <EuiFlexItem grow={false}> {fetchMetadataError ? ( diff --git a/x-pack/plugins/infra/public/components/asset_details/template/flyout.tsx b/x-pack/plugins/infra/public/components/asset_details/template/flyout.tsx index f8b4272dae0e6..d7d80c1117ca2 100644 --- a/x-pack/plugins/infra/public/components/asset_details/template/flyout.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/template/flyout.tsx @@ -41,8 +41,8 @@ export const Flyout = ({ }); const handleOnClose = useCallback(() => { - closeFlyout(); setUrlState(null); + closeFlyout(); }, [closeFlyout, setUrlState]); return ( diff --git a/x-pack/plugins/infra/public/components/lens/lens_chart.tsx b/x-pack/plugins/infra/public/components/lens/lens_chart.tsx index c67d659fc3e10..613cfec566572 100644 --- a/x-pack/plugins/infra/public/components/lens/lens_chart.tsx +++ b/x-pack/plugins/infra/public/components/lens/lens_chart.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { CSSProperties, useMemo } from 'react'; +import React from 'react'; import { EuiPanel, EuiToolTip, type EuiPanelProps } from '@elastic/eui'; import { Action } from '@kbn/ui-actions-plugin/public'; import { css } from '@emotion/react'; @@ -22,88 +22,82 @@ export type LensChartProps = UseLensAttributesParams & toolTip?: React.ReactElement<TooltipContentProps>; }; -export const LensChart = ({ - id, - borderRadius, - dateRange, - filters, - hidePanelTitles, - lastReloadRequestTime, - query, - onBrushEnd, - onFilter, - overrides, - toolTip, - disableTriggers = false, - height = MIN_HEIGHT, - loading = false, - ...lensAttributesParams -}: LensChartProps) => { - const { formula, attributes, getExtraActions, error } = useLensAttributes({ - ...lensAttributesParams, - }); +export const LensChart = React.memo( + ({ + id, + borderRadius, + dateRange, + filters, + hidePanelTitles, + lastReloadRequestTime, + query, + onBrushEnd, + onFilter, + overrides, + toolTip, + disableTriggers = false, + height = MIN_HEIGHT, + loading = false, + ...lensAttributesParams + }: LensChartProps) => { + const { formula, attributes, getExtraActions, error } = useLensAttributes(lensAttributesParams); - const isLoading = loading || !attributes; + const isLoading = loading || !attributes; - const extraActions: Action[] = useMemo( - () => - getExtraActions({ - timeRange: dateRange, - query, - filters, - }), - [dateRange, filters, getExtraActions, query] - ); + const extraActions: Action[] = getExtraActions({ + timeRange: dateRange, + query, + filters, + }); - const sytle: CSSProperties = useMemo(() => ({ height }), [height]); - - const lens = ( - <LensWrapper - id={id} - attributes={attributes} - dateRange={dateRange} - disableTriggers={disableTriggers} - extraActions={extraActions} - filters={filters} - hidePanelTitles={hidePanelTitles} - lastReloadRequestTime={lastReloadRequestTime} - loading={isLoading} - style={sytle} - query={query} - overrides={overrides} - onBrushEnd={onBrushEnd} - onFilter={onFilter} - /> - ); - const content = !toolTip ? ( - lens - ) : ( - <EuiToolTip - delay="regular" - content={React.cloneElement(toolTip, { - formula, - })} - anchorClassName="eui-fullWidth" - > - {/* EuiToolTip forwards some event handlers to the child component. + const lens = ( + <LensWrapper + id={id} + attributes={attributes} + dateRange={dateRange} + disableTriggers={disableTriggers} + extraActions={extraActions} + filters={filters} + hidePanelTitles={hidePanelTitles} + lastReloadRequestTime={lastReloadRequestTime} + loading={isLoading} + style={{ height }} + query={query} + overrides={overrides} + onBrushEnd={onBrushEnd} + onFilter={onFilter} + /> + ); + const content = !toolTip ? ( + lens + ) : ( + <EuiToolTip + delay="regular" + content={React.cloneElement(toolTip, { + formula, + })} + anchorClassName="eui-fullWidth" + > + {/* EuiToolTip forwards some event handlers to the child component. Wrapping Lens inside a div prevents that from causing unnecessary re-renders */} - <div>{lens}</div> - </EuiToolTip> - ); + <div>{lens}</div> + </EuiToolTip> + ); - return ( - <EuiPanel - hasBorder={!!borderRadius} - borderRadius={borderRadius} - hasShadow={false} - paddingSize={error ? 'm' : 'none'} - data-test-subj={id} - css={css` - position: relative; - min-height: ${height}px; - `} - > - {error ? <ChartLoadError /> : content} - </EuiPanel> - ); -}; + return ( + <EuiPanel + hasBorder={!!borderRadius} + borderRadius={borderRadius} + hasShadow={false} + paddingSize={error ? 'm' : 'none'} + data-test-subj={id} + css={css` + position: relative; + min-height: ${height}px; + `} + > + {error ? <ChartLoadError /> : content} + </EuiPanel> + ); + } +); diff --git a/x-pack/plugins/infra/public/components/lens/types.ts b/x-pack/plugins/infra/public/components/lens/types.ts index 399c61d87f4b9..2d3f76d38a31b 100644 --- a/x-pack/plugins/infra/public/components/lens/types.ts +++ b/x-pack/plugins/infra/public/components/lens/types.ts @@ -22,6 +22,7 @@ export type LensWrapperProps = Omit< }; export type BrushEndArgs = Parameters<NonNullable<LensEmbeddableInput['onBrushEnd']>>[0]; +export type OnFilterEvent = Parameters<NonNullable<LensEmbeddableInput['onFilter']>>[0]; export type BaseChartProps = Pick< LensWrapperProps, diff --git a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts index 9adf3e52dcdf4..e70e8977027ff 100644 --- a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; import { Filter, Query, TimeRange } from '@kbn/es-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; @@ -25,9 +25,7 @@ import { XYDataLayer, XYReferenceLinesLayer, } from '@kbn/lens-embeddable-utils'; - import { InfraClientSetupDeps } from '../types'; -import { useLazyRef } from './use_lazy_ref'; import type { MetricChartLayerParams, XYChartLayerParams } from '../common/visualizations/types'; interface UseLensAttributesBaseParams { @@ -44,6 +42,7 @@ export interface UseLensAttributesXYChartParams extends UseLensAttributesBasePar export interface UseLensAttributesMetricChartParams extends UseLensAttributesBaseParams { layers: MetricChartLayerParams; visualizationType: 'lnsMetric'; + subtitle?: string; } export type UseLensAttributesParams = @@ -58,7 +57,7 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara const { value, error } = useAsync(lens.stateHelperApi, [lens]); const { formula: formulaAPI } = value ?? {}; - const attributes = useLazyRef(() => { + const attributes = useMemo(() => { if (!dataView || !formulaAPI) { return null; } @@ -72,19 +71,19 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara }); return builder.build(); - }); + }, [dataView, formulaAPI, params]); const injectFilters = useCallback( ({ filters, query }: { filters: Filter[]; query: Query }): LensAttributes | null => { - if (!attributes.current) { + if (!attributes) { return null; } return { - ...attributes.current, + ...attributes, state: { - ...attributes.current.state, + ...attributes.state, query, - filters: [...attributes.current.state.filters, ...filters], + filters: [...attributes.state.filters, ...filters], }, }; }, @@ -143,7 +142,7 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara return mainFormulaConfig.value; }; - return { formula: getFormula(), attributes: attributes.current, getExtraActions, error }; + return { formula: getFormula(), attributes, getExtraActions, error }; }; const chartFactory = ({ @@ -198,7 +197,7 @@ const chartFactory = ({ formulaAPI, layers: new MetricLayer({ data: params.layers.data, - options: params.layers.options, + options: { ...params.layers.options, subtitle: params.subtitle }, }), title: params.title, }); diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx index 18fa090382dc8..24b1ba216d054 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx @@ -22,11 +22,20 @@ export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { he const { data: hostCountData, isRequestRunning: hostCountLoading } = useHostCountContext(); const shouldUseSearchCriteria = hostNodes.length === 0; - const loading = hostsLoading || hostCountLoading; - const getSubtitle = () => { - return searchCriteria.limit < (hostCountData?.count.value ?? 0) + const filters = shouldUseSearchCriteria + ? searchCriteria.filters + : [ + buildCombinedHostsFilter({ + field: 'host.name', + values: hostNodes.map((p) => p.name), + dataView, + }), + ]; + + const subtitle = + searchCriteria.limit < (hostCountData?.count.value ?? 0) ? i18n.translate('xpack.infra.hostsViewPage.kpi.subtitle.average.limit', { defaultMessage: 'Average (of {limit} hosts)', values: { @@ -34,42 +43,34 @@ export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { he }, }) : AVERAGE_SUBTITLE; - }; - - const filters = useMemo(() => { - return shouldUseSearchCriteria - ? searchCriteria.filters - : [ - buildCombinedHostsFilter({ - field: 'host.name', - values: hostNodes.map((p) => p.name), - dataView, - }), - ]; - }, [dataView, hostNodes, searchCriteria.filters, shouldUseSearchCriteria]); // prevents requestTs and searchCriteria state from reloading the chart - // we want it to reload only once the table has finished loading + // we want it to reload only once the table has finished loading. + // attributes passed to useAfterLoadedState don't need to be memoized const { afterLoadedState } = useAfterLoadedState(loading, { lastReloadRequestTime: requestTs, dateRange: parsedDateRange, query: shouldUseSearchCriteria ? searchCriteria.query : undefined, filters, + subtitle, }); + const tooltipComponent = useMemo(() => <TooltipContent description={toolTip} />, [toolTip]); + return ( <LensChart id={`hostsViewKPI-${id}`} dataView={dataView} dateRange={afterLoadedState.dateRange} filters={afterLoadedState.filters} - layers={{ ...layers, options: { ...layers.options, subtitle: getSubtitle() } }} + layers={layers} lastReloadRequestTime={afterLoadedState.lastReloadRequestTime} loading={loading} height={height} query={afterLoadedState.query} title={title} - toolTip={<TooltipContent description={toolTip} />} + subtitle={afterLoadedState.subtitle} + toolTip={tooltipComponent} visualizationType="lnsMetric" disableTriggers hidePanelTitles diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx index e8acd3a05fac3..75f0b25d2b10c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx @@ -30,6 +30,15 @@ export const Chart = ({ id, title, layers, visualOptions, overrides }: ChartProp const shouldUseSearchCriteria = currentPage.length === 0; + // prevents requestTs and searchCriteria state from reloading the chart + // we want it to reload only once the table has finished loading. + // attributes passed to useAfterLoadedState don't need to be memoized + const { afterLoadedState } = useAfterLoadedState(loading, { + lastReloadRequestTime: requestTs, + dateRange: parsedDateRange, + query: shouldUseSearchCriteria ? searchCriteria.query : undefined, + }); + const filters = useMemo(() => { return shouldUseSearchCriteria ? searchCriteria.filters @@ -42,14 +51,6 @@ export const Chart = ({ id, title, layers, visualOptions, overrides }: ChartProp ]; }, [searchCriteria.filters, currentPage, dataView, shouldUseSearchCriteria]); - // prevents requestTs and searchCriteria state from reloading the chart - // we want it to reload only once the table has finished loading - const { afterLoadedState } = useAfterLoadedState(loading, { - lastReloadRequestTime: requestTs, - dateRange: parsedDateRange, - query: shouldUseSearchCriteria ? searchCriteria.query : undefined, - }); - return ( <LensChart id={`hostsView-metricChart-${id}`} diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx index 8a81088fb0460..d9310ae0d816b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/metrics_grid.tsx @@ -14,7 +14,7 @@ import { HostMetricsExplanationContent } from '../../../../../../components/lens import { Chart } from './chart'; import { Popover } from '../../table/popover'; -export const MetricsGrid = React.memo(() => { +export const MetricsGrid = () => { return ( <> <EuiFlexGroup gutterSize="xs" alignItems="center"> @@ -38,4 +38,4 @@ export const MetricsGrid = React.memo(() => { </EuiFlexGrid> </> ); -}); +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts index 177c8d869ac6b..42d0522ffb8fa 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts @@ -11,6 +11,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; import type { DataView } from '@kbn/data-views-plugin/public'; +import { useMemo } from 'react'; import { useUrlState } from '../../../../utils/use_url_state'; const HOST_FILTERS_URL_STATE_KEY = 'controlPanels'; @@ -50,7 +51,7 @@ const availableControlPanelFields = Object.values(availableControlsPanels); export const useControlPanels = ( dataView: DataView | undefined ): [ControlPanels, (state: ControlPanels) => void] => { - const defaultState = getVisibleControlPanelsConfig(dataView); + const defaultState = useMemo(() => getVisibleControlPanelsConfig(dataView), [dataView]); const [controlPanels, setControlPanels] = useUrlState<ControlPanels>({ defaultState, diff --git a/x-pack/plugins/infra/public/utils/use_url_state.ts b/x-pack/plugins/infra/public/utils/use_url_state.ts index 8fc03d2d9dda2..a581e6536e487 100644 --- a/x-pack/plugins/infra/public/utils/use_url_state.ts +++ b/x-pack/plugins/infra/public/utils/use_url_state.ts @@ -47,13 +47,24 @@ export const useUrlState = <State>({ }, [defaultState, decodedState]); const setState = useCallback( - (newState: State | undefined) => { + (patch: State | undefined | ((prevState: State) => State)) => { if (!history || !history.location) { return; } const currentLocation = history.location; + const newState = + patch instanceof Function + ? patch( + decodeUrlState( + decodeRisonUrlState( + getParamFromQueryString(getQueryStringFromLocation(currentLocation), urlStateKey) + ) + ) ?? defaultState + ) + : patch; + const newLocation = replaceQueryStringInLocation( currentLocation, replaceStateKeyInQueryString( @@ -66,7 +77,7 @@ export const useUrlState = <State>({ history.replace(newLocation); } }, - [encodeUrlState, history, urlStateKey] + [decodeUrlState, defaultState, encodeUrlState, history, urlStateKey] ); const [shouldInitialize, setShouldInitialize] = useState( diff --git a/x-pack/plugins/infra/server/features.ts b/x-pack/plugins/infra/server/features.ts index 9698e4c2de3c3..57a9653816e80 100644 --- a/x-pack/plugins/infra/server/features.ts +++ b/x-pack/plugins/infra/server/features.ts @@ -8,6 +8,7 @@ import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { logViewSavedObjectName } from '@kbn/logs-shared-plugin/server'; +import { metricsDataSourceSavedObjectName } from '@kbn/metrics-data-access-plugin/server'; import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/observability-plugin/common/constants'; import { LOG_DOCUMENT_COUNT_RULE_TYPE_ID } from '../common/alerting/logs/log_threshold/types'; import { @@ -42,7 +43,7 @@ export const METRICS_FEATURE = { catalogue: ['infraops', 'metrics'], api: ['infra', 'rac'], savedObject: { - all: ['infrastructure-ui-source'], + all: ['infrastructure-ui-source', metricsDataSourceSavedObjectName], read: ['index-pattern'], }, alerting: { @@ -64,7 +65,7 @@ export const METRICS_FEATURE = { api: ['infra', 'rac'], savedObject: { all: [], - read: ['infrastructure-ui-source', 'index-pattern'], + read: ['infrastructure-ui-source', 'index-pattern', metricsDataSourceSavedObjectName], }, alerting: { rule: { diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts index 61c8b935806ac..986a6a8749511 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -26,6 +26,7 @@ import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/serve import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { LogsSharedPluginSetup, LogsSharedPluginStart } from '@kbn/logs-shared-plugin/server'; import { VersionedRouteConfig } from '@kbn/core-http-server'; +import { MetricsDataPluginSetup } from '@kbn/metrics-data-access-plugin/server'; export interface InfraServerPluginSetupDeps { alerting: AlertingPluginContract; @@ -40,6 +41,7 @@ export interface InfraServerPluginSetupDeps { visTypeTimeseries: VisTypeTimeseriesSetup; ml?: MlPluginSetup; logsShared: LogsSharedPluginSetup; + metricsDataAccess: MetricsDataPluginSetup; } export interface InfraServerPluginStartDeps { diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 99dfbe1f6bdbd..26fbb4d72a7e5 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -18,6 +18,7 @@ import { import { LifecycleAlertServices } from '@kbn/rule-registry-plugin/server'; import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks'; import { createLifecycleRuleExecutorMock } from '@kbn/rule-registry-plugin/server/utils/create_lifecycle_rule_executor_mock'; +import { MetricsDataClient } from '@kbn/metrics-data-access-plugin/server'; import { Aggregators, Comparator, @@ -1908,6 +1909,9 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({ const mockLibs: any = { sources: new InfraSources({ config: createMockStaticConfiguration({}), + metricsClient: { + getMetricIndices: jest.fn().mockResolvedValue('metrics-*,metricbeat-*'), + } as unknown as MetricsDataClient, }), configuration: createMockStaticConfiguration({}), metricsRules: { diff --git a/x-pack/plugins/infra/server/lib/infra_types.ts b/x-pack/plugins/infra/server/lib/infra_types.ts index 6bb24c722fe81..b3c8039423ec5 100644 --- a/x-pack/plugins/infra/server/lib/infra_types.ts +++ b/x-pack/plugins/infra/server/lib/infra_types.ts @@ -12,6 +12,7 @@ import type { AlertsLocatorParams } from '@kbn/observability-plugin/common'; import { ObservabilityConfig } from '@kbn/observability-plugin/server'; import type { LocatorPublic } from '@kbn/share-plugin/common'; import type { ILogsSharedLogEntriesDomain } from '@kbn/logs-shared-plugin/server'; +import type { MetricsDataClient } from '@kbn/metrics-data-access-plugin/server'; import { RulesServiceSetup } from '../services/rules'; import { InfraConfig, InfraPluginStartServicesAccessor } from '../types'; import { KibanaFramework } from './adapters/framework/kibana_framework_adapter'; @@ -39,4 +40,5 @@ export interface InfraBackendLibs extends InfraDomainLibs { handleEsError: typeof handleEsError; logger: Logger; alertsLocator?: LocatorPublic<AlertsLocatorParams>; + metricsClient: MetricsDataClient; } diff --git a/x-pack/plugins/infra/server/lib/metrics/make_get_metric_indices.test.ts b/x-pack/plugins/infra/server/lib/metrics/make_get_metric_indices.test.ts deleted file mode 100644 index 9dedf9b5afaa0..0000000000000 --- a/x-pack/plugins/infra/server/lib/metrics/make_get_metric_indices.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; -import { defaultSourceConfiguration, InfraSource } from '../sources'; -import { createInfraSourcesMock } from '../sources/mocks'; -import { makeGetMetricIndices } from './make_get_metric_indices'; - -describe('getMetricIndices', () => { - it('should return the indices from a resolved configuration', async () => { - const sourceConfiguration: InfraSource = { - id: 'default', - origin: 'stored', - configuration: defaultSourceConfiguration, - }; - const infraSourcesMock = createInfraSourcesMock(); - infraSourcesMock.getSourceConfiguration.mockResolvedValueOnce(sourceConfiguration); - - const getMetricIndices = makeGetMetricIndices(infraSourcesMock); - - const savedObjectsClient = savedObjectsClientMock.create(); - const metricIndices = await getMetricIndices(savedObjectsClient); - - expect(metricIndices).toEqual(defaultSourceConfiguration.metricAlias); - }); -}); diff --git a/x-pack/plugins/infra/server/lib/metrics/make_get_metric_indices.ts b/x-pack/plugins/infra/server/lib/metrics/make_get_metric_indices.ts deleted file mode 100644 index a6ff7e96a55a0..0000000000000 --- a/x-pack/plugins/infra/server/lib/metrics/make_get_metric_indices.ts +++ /dev/null @@ -1,16 +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 { SavedObjectsClientContract } from '@kbn/core/server'; -import type { IInfraSources } from '../sources'; - -export function makeGetMetricIndices(metricSources: IInfraSources) { - return async (savedObjectsClient: SavedObjectsClientContract, sourceId: string = 'default') => { - const source = await metricSources.getSourceConfiguration(savedObjectsClient, sourceId); - return source.configuration.metricAlias; - }; -} diff --git a/x-pack/plugins/infra/server/lib/sources/mocks.ts b/x-pack/plugins/infra/server/lib/sources/mocks.ts index 95ce2619e247a..5184d4a4ef334 100644 --- a/x-pack/plugins/infra/server/lib/sources/mocks.ts +++ b/x-pack/plugins/infra/server/lib/sources/mocks.ts @@ -10,6 +10,7 @@ import type { InfraSources } from './sources'; type IInfraSources = Pick<InfraSources, keyof InfraSources>; export const createInfraSourcesMock = (): jest.Mocked<IInfraSources> => ({ + getInfraSourceConfiguration: jest.fn(), getSourceConfiguration: jest.fn(), createSourceConfiguration: jest.fn(), deleteSourceConfiguration: jest.fn(), diff --git a/x-pack/plugins/infra/server/lib/sources/sources.test.ts b/x-pack/plugins/infra/server/lib/sources/sources.test.ts index 9f7d5e9bd1be1..a8c7cf3231b41 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.test.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.test.ts @@ -6,6 +6,7 @@ */ import { SavedObject } from '@kbn/core/server'; +import { MetricsDataClient } from '@kbn/metrics-data-access-plugin/server'; import { InfraConfig } from '../../types'; import { infraSourceConfigurationSavedObjectName } from './saved_object_type'; import { InfraSources } from './sources'; @@ -15,6 +16,7 @@ describe('the InfraSources lib', () => { test('returns a source configuration if it exists', async () => { const sourcesLib = new InfraSources({ config: createMockStaticConfiguration({}), + metricsClient: createMockMetricsDataClient('METRIC_ALIAS'), }); const request: any = createRequestContext({ @@ -56,6 +58,7 @@ describe('the InfraSources lib', () => { logIndices: { type: 'index_pattern', indexPatternId: 'LOG_ALIAS' }, }, }), + metricsClient: createMockMetricsDataClient('METRIC_ALIAS'), }); const request: any = createRequestContext({ @@ -83,6 +86,7 @@ describe('the InfraSources lib', () => { test('adds missing attributes from the default configuration to a source configuration', async () => { const sourcesLib = new InfraSources({ config: createMockStaticConfiguration({}), + metricsClient: createMockMetricsDataClient(), }); const request: any = createRequestContext({ @@ -128,6 +132,12 @@ const createMockStaticConfiguration = (sources: any): InfraConfig => ({ enabled: true, }); +const createMockMetricsDataClient = (metricAlias: string = 'metrics-*,metricbeat-*') => + ({ + getMetricIndices: jest.fn().mockResolvedValue(metricAlias), + updateMetricIndices: jest.fn(), + } as unknown as MetricsDataClient); + const createRequestContext = (savedObject?: SavedObject<unknown>) => { return { core: { diff --git a/x-pack/plugins/infra/server/lib/sources/sources.ts b/x-pack/plugins/infra/server/lib/sources/sources.ts index 693c4aba20ae1..64f7900d57279 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.ts @@ -15,6 +15,7 @@ import { SavedObjectsClientContract, SavedObjectsErrorHelpers, } from '@kbn/core/server'; +import { MetricsDataClient } from '@kbn/metrics-data-access-plugin/server'; import { InfraSavedSourceConfiguration, InfraSource, @@ -35,6 +36,7 @@ import { infraSourceConfigurationSavedObjectName } from './saved_object_type'; interface Libs { config: InfraConfig; + metricsClient: MetricsDataClient; } // extract public interface @@ -48,7 +50,7 @@ export class InfraSources { this.libs = libs; } - public async getSourceConfiguration( + public async getInfraSourceConfiguration( savedObjectsClient: SavedObjectsClientContract, sourceId: string ): Promise<InfraSource> { @@ -90,6 +92,21 @@ export class InfraSources { return savedSourceConfiguration; } + public async getSourceConfiguration( + savedObjectsClient: SavedObjectsClientContract, + sourceId: string + ): Promise<InfraSource> { + const sourceConfiguration = await this.getInfraSourceConfiguration( + savedObjectsClient, + sourceId + ); + const metricAlias = await this.libs.metricsClient.getMetricIndices({ + savedObjectsClient, + }); + sourceConfiguration.configuration.metricAlias = metricAlias; + return sourceConfiguration; + } + public async getAllSourceConfigurations(savedObjectsClient: SavedObjectsClientContract) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); @@ -129,6 +146,11 @@ export class InfraSources { }) ); + await this.libs.metricsClient.updateMetricIndices({ + savedObjectsClient, + metricIndices: newSourceConfiguration.metricAlias, + }); + return { ...createdSourceConfiguration, configuration: mergeSourceConfiguration( @@ -180,6 +202,11 @@ export class InfraSources { }) ); + await this.libs.metricsClient.updateMetricIndices({ + savedObjectsClient, + metricIndices: updatedSourceConfiguration.configuration.metricAlias!, + }); + return { ...updatedSourceConfiguration, configuration: mergeSourceConfiguration( diff --git a/x-pack/plugins/infra/server/mocks.ts b/x-pack/plugins/infra/server/mocks.ts index a15575572a076..51845ffed003f 100644 --- a/x-pack/plugins/infra/server/mocks.ts +++ b/x-pack/plugins/infra/server/mocks.ts @@ -27,7 +27,6 @@ const createInfraSetupMock = () => { const createInfraStartMock = () => { const infraStartMock: jest.Mocked<InfraPluginStart> = { - getMetricIndices: jest.fn(), inventoryViews: createInventoryViewsServiceStartMock(), metricsExplorerViews: createMetricsExplorerViewsServiceStartMock(), }; diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 8a91d5685daa3..d3898f064135f 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -18,6 +18,7 @@ import { i18n } from '@kbn/i18n'; import { Logger } from '@kbn/logging'; import { alertsLocatorID } from '@kbn/observability-plugin/common'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { GetMetricIndicesOptions } from '@kbn/metrics-data-access-plugin/server'; import { DISCOVER_APP_TARGET, LOGS_APP_TARGET, @@ -41,7 +42,6 @@ import { import { InfraFieldsDomain } from './lib/domains/fields_domain'; import { InfraMetricsDomain } from './lib/domains/metrics_domain'; import { InfraBackendLibs, InfraDomainLibs } from './lib/infra_types'; -import { makeGetMetricIndices } from './lib/metrics/make_get_metric_indices'; import { infraSourceConfigurationSavedObjectType, InfraSources } from './lib/sources'; import { InfraSourceStatus } from './lib/source_status'; import { inventoryViewSavedObjectType, metricsExplorerViewSavedObjectType } from './saved_objects'; @@ -153,8 +153,17 @@ export class InfraServerPlugin setup(core: InfraPluginCoreSetup, plugins: InfraServerPluginSetupDeps) { const framework = new KibanaFramework(core, this.config, plugins); + const metricsClient = plugins.metricsDataAccess.client; + metricsClient.setDefaultMetricIndicesHandler(async (options: GetMetricIndicesOptions) => { + const sourceConfiguration = await sources.getInfraSourceConfiguration( + options.savedObjectsClient, + 'default' + ); + return sourceConfiguration.configuration.metricAlias; + }); const sources = new InfraSources({ config: this.config, + metricsClient, }); const sourceStatus = new InfraSourceStatus( new InfraElasticsearchSourceStatusAdapter(framework), @@ -186,6 +195,7 @@ export class InfraServerPlugin framework, sources, sourceStatus, + metricsClient, ...domainLibs, handleEsError, logsRules: this.logsRules.setup(core, plugins), @@ -202,7 +212,7 @@ export class InfraServerPlugin // Register an handler to retrieve the fallback logView starting from a source configuration plugins.logsShared.logViews.registerLogViewFallbackHandler(async (sourceId, { soClient }) => { - const sourceConfiguration = await sources.getSourceConfiguration(soClient, sourceId); + const sourceConfiguration = await sources.getInfraSourceConfiguration(soClient, sourceId); return mapSourceToLogView(sourceConfiguration); }); plugins.logsShared.logViews.setLogViewsStaticConfig({ @@ -270,7 +280,6 @@ export class InfraServerPlugin return { inventoryViews, metricsExplorerViews, - getMetricIndices: makeGetMetricIndices(this.libs.sources), }; } diff --git a/x-pack/plugins/infra/server/types.ts b/x-pack/plugins/infra/server/types.ts index 0a4ad94c09d43..e9d9faa548bb2 100644 --- a/x-pack/plugins/infra/server/types.ts +++ b/x-pack/plugins/infra/server/types.ts @@ -5,11 +5,7 @@ * 2.0. */ -import type { - CoreSetup, - CustomRequestHandlerContext, - SavedObjectsClientContract, -} from '@kbn/core/server'; +import type { CoreSetup, CustomRequestHandlerContext } from '@kbn/core/server'; import type { SearchRequestHandlerContext } from '@kbn/data-plugin/server'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; import type { InfraStaticSourceConfiguration } from '../common/source_configuration/source_configuration'; @@ -37,10 +33,6 @@ export interface InfraPluginSetup { export interface InfraPluginStart { inventoryViews: InventoryViewsServiceStart; metricsExplorerViews: MetricsExplorerViewsServiceStart; - getMetricIndices: ( - savedObjectsClient: SavedObjectsClientContract, - sourceId?: string - ) => Promise<string>; } export type MlSystem = ReturnType<MlPluginSetup['mlSystemProvider']>; diff --git a/x-pack/plugins/infra/tsconfig.json b/x-pack/plugins/infra/tsconfig.json index 0b4b4038de953..2166ae9c7b4c6 100644 --- a/x-pack/plugins/infra/tsconfig.json +++ b/x-pack/plugins/infra/tsconfig.json @@ -70,6 +70,7 @@ "@kbn/licensing-plugin", "@kbn/aiops-utils", "@kbn/lens-embeddable-utils", + "@kbn/metrics-data-access-plugin", "@kbn/expressions-plugin" ], "exclude": ["target/**/*"] diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx index 51ed27f328838..88f6c67113bce 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx @@ -64,7 +64,7 @@ import { import { getFiltersInLayer, - getShardFailuresWarningMessages, + getSearchWarningMessages, getVisualDefaultsForLayer, isColumnInvalid, cloneLayer, @@ -811,7 +811,7 @@ export function getFormBasedDatasource({ }, getSearchWarningMessages: (state, warning, request, response) => { - return [...getShardFailuresWarningMessages(state, warning, request, response, core.theme)]; + return [...getSearchWarningMessages(state, warning, request, response, core.theme)]; }, checkIntegrity: (state, indexPatterns) => { diff --git a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx index 33c60b89f3ce4..73caafa33fc8e 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { DocLinksStart, ThemeServiceStart } from '@kbn/core/public'; +import { hasUnsupportedDownsampledAggregationFailure } from '@kbn/search-response-warnings'; import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; import { TimeRange } from '@kbn/es-query'; import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; @@ -18,11 +19,7 @@ import { groupBy, escape, uniq, uniqBy } from 'lodash'; import type { Query } from '@kbn/data-plugin/common'; import { SearchRequest } from '@kbn/data-plugin/common'; -import { - SearchResponseWarning, - ShardFailureOpenModalButton, - ShardFailureRequest, -} from '@kbn/data-plugin/public'; +import { SearchResponseWarning, OpenIncompleteResultsModalButton } from '@kbn/data-plugin/public'; import { estypes } from '@elastic/elasticsearch'; import { isQueryValid } from '@kbn/visualization-ui-components'; @@ -260,7 +257,7 @@ const accuracyModeEnabledWarning = ( ), }); -export function getShardFailuresWarningMessages( +export function getSearchWarningMessages( state: FormBasedPersistedState, warning: SearchResponseWarning, request: SearchRequest, @@ -268,10 +265,9 @@ export function getShardFailuresWarningMessages( theme: ThemeServiceStart ): UserMessage[] { if (state) { - if (warning.type === 'shard_failure') { - switch (warning.reason.type) { - case 'unsupported_aggregation_on_downsampled_index': - return Object.values(state.layers).flatMap((layer) => + if (warning.type === 'incomplete') { + return hasUnsupportedDownsampledAggregationFailure(warning) + ? Object.values(state.layers).flatMap((layer) => uniq( Object.values(layer.columns) .filter((col) => @@ -302,40 +298,33 @@ export function getShardFailuresWarningMessages( }), } as UserMessage) ) - ); - default: - return [ + ) + : [ { - uniqueId: `shard_failure`, + uniqueId: `incomplete`, severity: 'warning', fixableInEditor: true, displayLocations: [{ id: 'toolbar' }, { id: 'embeddableBadge' }], shortMessage: '', longMessage: ( <> - <EuiText size="s"> - <strong>{warning.message}</strong> - <p>{warning.text}</p> - </EuiText> + <EuiText size="s">{warning.message}</EuiText> <EuiSpacer size="s" /> - {warning.text ? ( - <ShardFailureOpenModalButton - theme={theme} - title={warning.message} - size="m" - getRequestMeta={() => ({ - request: request as ShardFailureRequest, - response, - })} - color="primary" - isButtonEmpty={true} - /> - ) : null} + <OpenIncompleteResultsModalButton + theme={theme} + warning={warning} + size="m" + getRequestMeta={() => ({ + request, + response, + })} + color="primary" + isButtonEmpty={true} + /> </> ), } as UserMessage, ]; - } } } return []; 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 4e66763b54a94..6af4fe67c0622 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 @@ -729,7 +729,7 @@ export const VisualizationWrapper = ({ to: context.dateRange.toDate, }, filters: context.filters, - disableShardWarnings: true, + disableWarningToasts: true, }), [context] ); diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx index 67dea2f98231c..67764b46f6609 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ b/x-pack/plugins/lens/public/embeddable/embeddable.tsx @@ -1196,7 +1196,7 @@ export class Embeddable this.savedVis.state.filters, this.savedVis.references ), - disableShardWarnings: true, + disableWarningToasts: true, }; if (input.query) { diff --git a/x-pack/plugins/lens/public/state_management/selectors.ts b/x-pack/plugins/lens/public/state_management/selectors.ts index 407aacba9e4a2..6bf40638554f9 100644 --- a/x-pack/plugins/lens/public/state_management/selectors.ts +++ b/x-pack/plugins/lens/public/state_management/selectors.ts @@ -62,7 +62,7 @@ export const selectExecutionContextSearch = createSelector(selectExecutionContex to: res.dateRange.toDate, }, filters: res.filters, - disableShardWarnings: true, + disableWarningToasts: true, })); const selectInjectedDependencies = (_state: LensState, dependencies: unknown) => dependencies; diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index b1deface2cd77..90011c6bad735 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -349,29 +349,26 @@ export const getSearchWarningMessages = ( searchService: ISearchStart; } ): UserMessage[] => { - const warningsMap: Map<string, UserMessage[]> = new Map(); + const userMessages: UserMessage[] = []; deps.searchService.showWarnings(adapter, (warning, meta) => { - const { request, response, requestId } = meta; + const { request, response } = meta; - const warningMessages = datasource.getSearchWarningMessages?.( + const userMessagesFromWarning = datasource.getSearchWarningMessages?.( state, warning, request, response ); - if (warningMessages?.length) { - const key = (requestId ?? '') + warning.type + warning.reason?.type ?? ''; - if (!warningsMap.has(key)) { - warningsMap.set(key, warningMessages); - } + if (userMessagesFromWarning?.length) { + userMessages.push(...userMessagesFromWarning); return true; } return false; }); - return [...warningsMap.values()].flat(); + return userMessages; }; function getSafeLabel(label: string) { diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index 484734f1ae38f..ca536dc187c3f 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -86,6 +86,7 @@ "@kbn/content-management-utils", "@kbn/serverless", "@kbn/ebt-tools", + "@kbn/search-response-warnings", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.test.ts b/x-pack/plugins/maps/public/classes/joins/inner_join.test.ts index 160ced8f46b9d..4797e43e1aac4 100644 --- a/x-pack/plugins/maps/public/classes/joins/inner_join.test.ts +++ b/x-pack/plugins/maps/public/classes/joins/inner_join.test.ts @@ -27,7 +27,7 @@ const rightSource = { } as ESTermSourceDescriptor; const mockSource = { - createField({ fieldName }: { fieldName: string }) { + getFieldByName(fieldName: string) { return { getName() { return fieldName; diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.ts b/x-pack/plugins/maps/public/classes/joins/inner_join.ts index b2c299e977ec9..a80ddd7c26e4f 100644 --- a/x-pack/plugins/maps/public/classes/joins/inner_join.ts +++ b/x-pack/plugins/maps/public/classes/joins/inner_join.ts @@ -56,13 +56,13 @@ export function createJoinSource( export class InnerJoin { private readonly _descriptor: Partial<JoinDescriptor>; private readonly _rightSource?: IJoinSource; - private readonly _leftField?: IField; + private readonly _leftField?: IField | null; constructor(joinDescriptor: Partial<JoinDescriptor>, leftSource: IVectorSource) { this._descriptor = joinDescriptor; this._rightSource = createJoinSource(this._descriptor.right); this._leftField = joinDescriptor.leftField - ? leftSource.createField({ fieldName: joinDescriptor.leftField }) + ? leftSource.getFieldByName(joinDescriptor.leftField) : undefined; } diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts index 631f78df6e856..1f20bb4733d34 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/geojson_vector_layer/perform_inner_joins.test.ts @@ -69,7 +69,7 @@ const mockVectorSource = { getInspectorAdapters: () => { return undefined; }, - createField: () => { + getFieldByName: () => { return { getName: () => { return LEFT_FIELD; diff --git a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx index 40ea053523eea..f46acc54cc7b0 100644 --- a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx @@ -66,18 +66,10 @@ export class EMSFileSource extends AbstractVectorSource implements IEmsFileSourc super(EMSFileSource.createDescriptor(descriptor)); this._descriptor = EMSFileSource.createDescriptor(descriptor); this._tooltipFields = this._descriptor.tooltipProperties.map((propertyKey) => - this.createField({ fieldName: propertyKey }) + this.getFieldByName(propertyKey) ); } - createField({ fieldName }: { fieldName: string }): IField { - return new EMSFileField({ - fieldName, - source: this, - origin: FIELD_ORIGIN.SOURCE, - }); - } - renderSourceSettingsEditor({ onChange }: SourceEditorArgs): ReactElement<any> | null { return ( <UpdateSourceEditor @@ -188,10 +180,22 @@ export class EMSFileSource extends AbstractVectorSource implements IEmsFileSourc }; } - async getLeftJoinFields() { + async getFields(): Promise<IField[]> { const emsFileLayer = await this.getEMSFileLayer(); const fields = emsFileLayer.getFieldsInLanguage(); - return fields.map((f) => this.createField({ fieldName: f.name })); + return fields.map((f) => this.getFieldByName(f.name)); + } + + getFieldByName(fieldName: string): IField { + return new EMSFileField({ + fieldName, + source: this, + origin: FIELD_ORIGIN.SOURCE, + }); + } + + async getLeftJoinFields() { + return this.getFields(); } hasTooltipProperties() { @@ -216,4 +220,38 @@ export class EMSFileSource extends AbstractVectorSource implements IEmsFileSourc const emsSettings = getEMSSettings(); return emsSettings.isEMSUrlSet() ? [LICENSED_FEATURES.ON_PREM_EMS] : []; } + + private async _getFieldValues(fieldName: string): Promise<string[]> { + try { + const emsFileLayer = await this.getEMSFileLayer(); + const targetEmsField = emsFileLayer.getFields().find(({ id }) => id === fieldName); + if (targetEmsField?.values?.length) { + return targetEmsField.values; + } + + // Fallback to pulling values from feature properties when values are not available in file definition + const valuesSet = new Set<string>(); // use set to avoid duplicate values + const featureCollection = await emsFileLayer.getGeoJson(); + featureCollection?.features.forEach((feature) => { + if ( + feature.properties && + fieldName in feature.properties && + feature.properties[fieldName] != null + ) { + valuesSet.add(feature.properties[fieldName].toString()); + } + }); + return Array.from(valuesSet); + } catch (error) { + // ignore errors + return []; + } + } + + getValueSuggestions = async (field: IField, query: string): Promise<string[]> => { + const values = await this._getFieldValues(field.getName()); + return query.length + ? values.filter((value) => value.toLowerCase().includes(query.toLowerCase())) + : values; + }; } diff --git a/x-pack/plugins/maps/public/classes/sources/ems_file_source/update_source_editor.tsx b/x-pack/plugins/maps/public/classes/sources/ems_file_source/update_source_editor.tsx index a35d5c0cc6fa2..743428a2c0586 100644 --- a/x-pack/plugins/maps/public/classes/sources/ems_file_source/update_source_editor.tsx +++ b/x-pack/plugins/maps/public/classes/sources/ems_file_source/update_source_editor.tsx @@ -5,11 +5,10 @@ * 2.0. */ -import React, { Component, Fragment } from 'react'; -import { EuiTitle, EuiPanel, EuiSpacer } from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { EuiTitle, EuiPanel, EuiSkeletonText, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { TooltipSelector } from '../../../components/tooltip_selector'; -import { getEmsFileLayers } from '../../../util'; import { IEmsFileSource } from './ems_file_source'; import { IField } from '../../fields/field'; import { OnSourceChangeArgs } from '../source'; @@ -21,74 +20,62 @@ interface Props { tooltipFields: IField[]; } -interface State { - fields: IField[] | null; -} - -export class UpdateSourceEditor extends Component<Props, State> { - private _isMounted: boolean = false; - - state = { - fields: null, - }; - - componentDidMount() { - this._isMounted = true; - this.loadFields(); - } - - componentWillUnmount() { - this._isMounted = false; - } - - async loadFields() { - let fields: IField[] = []; - try { - const emsFiles = await getEmsFileLayers(); - const targetEmsFile = emsFiles.find((emsFile) => emsFile.getId() === this.props.layerId); - if (targetEmsFile) { - fields = targetEmsFile - .getFieldsInLanguage() - .map((field) => this.props.source.createField({ fieldName: field.name })); - } - } catch (e) { - // When a matching EMS-config cannot be found, the source already will have thrown errors during the data request. - // This will propagate to the vector-layer and be displayed in the UX - } +export function UpdateSourceEditor(props: Props) { + const [isLoading, setIsLoading] = useState(false); + const [fields, setFields] = useState<IField[]>([]); - if (this._isMounted) { - this.setState({ fields }); - } - } + useEffect(() => { + let ignore = false; + setIsLoading(true); + props.source + .getFields() + .then((nextFields) => { + if (!ignore) { + setFields(nextFields); + setIsLoading(false); + } + }) + .catch((err) => { + if (!ignore) { + // When a matching EMS-config cannot be found, the source already will have thrown errors during the data request. + // This will propagate to the vector-layer and be displayed in the UX + setIsLoading(false); + } + }); - _onTooltipPropertiesSelect = (selectedFieldNames: string[]) => { - this.props.onChange({ propName: 'tooltipProperties', value: selectedFieldNames }); - }; + return () => { + ignore = true; + }; + // only run onMount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); - render() { - return ( - <Fragment> - <EuiPanel> - <EuiTitle size="xs"> - <h5> - <FormattedMessage - id="xpack.maps.emsSource.tooltipsTitle" - defaultMessage="Tooltip fields" - /> - </h5> - </EuiTitle> + return ( + <> + <EuiPanel> + <EuiTitle size="xs"> + <h5> + <FormattedMessage + id="xpack.maps.emsSource.tooltipsTitle" + defaultMessage="Tooltip fields" + /> + </h5> + </EuiTitle> - <EuiSpacer size="m" /> + <EuiSpacer size="m" /> + <EuiSkeletonText isLoading={isLoading}> <TooltipSelector - tooltipFields={this.props.tooltipFields} - onChange={this._onTooltipPropertiesSelect} - fields={this.state.fields} + tooltipFields={props.tooltipFields} + onChange={(selectedFieldNames: string[]) => { + props.onChange({ propName: 'tooltipProperties', value: selectedFieldNames }); + }} + fields={fields} /> - </EuiPanel> + </EuiSkeletonText> + </EuiPanel> - <EuiSpacer size="s" /> - </Fragment> - ); - } + <EuiSpacer size="s" /> + </> + ); } diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index 4bb67e8b38099..f56155284232d 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -152,19 +152,11 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource this._descriptor = sourceDescriptor; this._tooltipFields = this._descriptor.tooltipProperties ? this._descriptor.tooltipProperties.map((property) => { - return this.createField({ fieldName: property }); + return this.getFieldByName(property); }) : []; } - createField({ fieldName }: { fieldName: string }): ESDocField { - return new ESDocField({ - fieldName, - source: this, - origin: FIELD_ORIGIN.SOURCE, - }); - } - renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs): ReactElement<any> | null { if (this._isTopHits()) { return ( @@ -213,7 +205,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource }); return fields.map((field): IField => { - return this.createField({ fieldName: field.name }); + return this.getFieldByName(field.name); }); } catch (error) { // failed index-pattern retrieval will show up as error-message in the layer-toc-entry @@ -221,6 +213,14 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } } + getFieldByName(fieldName: string): ESDocField { + return new ESDocField({ + fieldName, + source: this, + origin: FIELD_ORIGIN.SOURCE, + }); + } + isMvt() { return this._descriptor.scalingType === SCALING_TYPES.MVT; } @@ -747,7 +747,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource const indexPattern = await this.getIndexPattern(); // Left fields are retrieved from _source. return getSourceFields(indexPattern.fields).map((field): IField => { - return this.createField({ fieldName: field.name }); + return this.getFieldByName(field.name); }); } diff --git a/x-pack/plugins/maps/public/classes/sources/geojson_file_source/geojson_file_source.ts b/x-pack/plugins/maps/public/classes/sources/geojson_file_source/geojson_file_source.ts index eabeca9190f31..cb112790408ae 100644 --- a/x-pack/plugins/maps/public/classes/sources/geojson_file_source/geojson_file_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/geojson_file_source/geojson_file_source.ts @@ -58,42 +58,31 @@ export class GeoJsonFileSource extends AbstractVectorSource { super(normalizedDescriptor); } - _getFields(): InlineFieldDescriptor[] { + private _getFieldDescriptors(): InlineFieldDescriptor[] { const fields = (this._descriptor as GeojsonFileSourceDescriptor).__fields; return fields ? fields : []; } - createField({ fieldName }: { fieldName: string }): IField { - const fields = this._getFields(); - const descriptor: InlineFieldDescriptor | undefined = fields.find((field) => { - return field.name === fieldName; - }); - - if (!descriptor) { - throw new Error( - `Cannot find corresponding field ${fieldName} in __fields array ${JSON.stringify( - this._getFields() - )} ` - ); - } + private _createField(fieldDescriptor: InlineFieldDescriptor): IField { return new InlineField<GeoJsonFileSource>({ - fieldName: descriptor.name, + fieldName: fieldDescriptor.name, source: this, origin: FIELD_ORIGIN.SOURCE, - dataType: descriptor.type, + dataType: fieldDescriptor.type, }); } async getFields(): Promise<IField[]> { - const fields = this._getFields(); - return fields.map((field: InlineFieldDescriptor) => { - return new InlineField<GeoJsonFileSource>({ - fieldName: field.name, - source: this, - origin: FIELD_ORIGIN.SOURCE, - dataType: field.type, - }); + return this._getFieldDescriptors().map((fieldDescriptor: InlineFieldDescriptor) => { + return this._createField(fieldDescriptor); + }); + } + + getFieldByName(fieldName: string): IField | null { + const fieldDescriptor = this._getFieldDescriptors().find((findFieldDescriptor) => { + return findFieldDescriptor.name === fieldName; }); + return fieldDescriptor ? this._createField(fieldDescriptor) : null; } isBoundsAware(): boolean { diff --git a/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts index bb25a9363bde6..c1321649168a2 100644 --- a/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/join_sources/table_source/table_source.ts @@ -139,14 +139,6 @@ export class TableSource extends AbstractVectorSource implements ITermJoinSource return false; } - createField({ fieldName }: { fieldName: string }): IField { - const field = this.getFieldByName(fieldName); - if (!field) { - throw new Error(`Cannot find field for ${fieldName}`); - } - return field; - } - async getBoundsForFilters( boundsFilters: BoundsRequestMeta, registerCancelCallback: (callback: () => void) => void diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx index 0834b9361eac7..a4debb51e3281 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx @@ -112,26 +112,17 @@ export class MVTSingleLayerVectorSource extends AbstractSource implements IMvtVe } getFieldByName(fieldName: string): MVTField | null { - try { - return this.createField({ fieldName }); - } catch (e) { - return null; - } - } - - createField({ fieldName }: { fieldName: string }): MVTField { const field = this._descriptor.fields.find((f: MVTFieldDescriptor) => { return f.name === fieldName; }); - if (!field) { - throw new Error(`Cannot create field for fieldName ${fieldName}`); - } - return new MVTField({ - fieldName: field.name, - type: field.type, - source: this, - origin: FIELD_ORIGIN.SOURCE, - }); + return field + ? new MVTField({ + fieldName: field.name, + type: field.type, + source: this, + origin: FIELD_ORIGIN.SOURCE, + }) + : null; } getGeoJsonWithMeta(): Promise<GeoJsonWithMeta> { diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx index ba2fbe5892177..c4da68816d262 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx @@ -113,7 +113,6 @@ export interface IVectorSource extends ISource { */ getSyncMeta(dataFilters: DataFilters): object | null; - createField({ fieldName }: { fieldName: string }): IField; hasTooltipProperties(): boolean; getSupportedShapeTypes(): Promise<VECTOR_SHAPE_TYPE[]>; isBoundsAware(): boolean; @@ -143,14 +142,6 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc return false; } - createField({ fieldName }: { fieldName: string }): IField { - throw new Error('Not implemented'); - } - - getFieldByName(fieldName: string): IField | null { - return this.createField({ fieldName }); - } - isFilterByMapBounds() { return false; } @@ -174,6 +165,10 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc return []; } + getFieldByName(fieldName: string): IField | null { + throw new Error('Must implement VectorSource#getFieldByName'); + } + async getLeftJoinFields(): Promise<IField[]> { return []; } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js index 9702d0f44ea39..1bbaad11534b0 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js @@ -26,9 +26,6 @@ class MockSource { getFieldByName(fieldName) { return new MockField({ fieldName }); } - createField({ fieldName }) { - return new MockField({ fieldName }); - } } describe('getDescriptorWithUpdatedStyleProps', () => { diff --git a/x-pack/plugins/maps/public/ems_autosuggest/ems_autosuggest.ts b/x-pack/plugins/maps/public/ems_autosuggest/ems_autosuggest.ts index 4ade37658fd13..f03ea6f1dca47 100644 --- a/x-pack/plugins/maps/public/ems_autosuggest/ems_autosuggest.ts +++ b/x-pack/plugins/maps/public/ems_autosuggest/ems_autosuggest.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { FileLayer } from '@elastic/ems-client'; +import type { FileLayer, FileLayerField } from '@elastic/ems-client'; import { getEmsFileLayers } from '../util'; export interface SampleValuesConfig { @@ -23,12 +23,6 @@ interface UniqueMatch { config: EMSTermJoinConfig; count: number; } -interface FileLayerFieldShim { - id: string; - values?: string[]; - regex?: string; - alias?: string[]; -} export async function suggestEMSTermJoinConfig( sampleValuesConfig: SampleValuesConfig @@ -94,8 +88,8 @@ function suggestByName( ): EMSTermJoinConfig[] { const matches: EMSTermJoinConfig[] = []; fileLayers.forEach((fileLayer) => { - const emsFields: FileLayerFieldShim[] = fileLayer.getFields(); - emsFields.forEach((emsField: FileLayerFieldShim) => { + const emsFields: FileLayerField[] = fileLayer.getFields(); + emsFields.forEach((emsField: FileLayerField) => { if (!emsField.alias || !emsField.alias.length) { return; } @@ -148,8 +142,8 @@ function suggestByIdValues( ): EMSTermJoinConfig[] { const matches: EMSTermJoinConfig[] = []; fileLayers.forEach((fileLayer) => { - const emsFields: FileLayerFieldShim[] = fileLayer.getFields(); - emsFields.forEach((emsField: FileLayerFieldShim) => { + const emsFields: FileLayerField[] = fileLayer.getFields(); + emsFields.forEach((emsField: FileLayerField) => { if (!emsField.values || !emsField.values.length) { return; } diff --git a/x-pack/plugins/metrics_data_access/README.md b/x-pack/plugins/metrics_data_access/README.md new file mode 100755 index 0000000000000..b8a9783e7b883 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/README.md @@ -0,0 +1,3 @@ +# Metrics Data Access + +Exposes utilities to access metrics data. diff --git a/x-pack/plugins/metrics_data_access/jest.config.js b/x-pack/plugins/metrics_data_access/jest.config.js new file mode 100644 index 0000000000000..9c8e01aabd0aa --- /dev/null +++ b/x-pack/plugins/metrics_data_access/jest.config.js @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: ['<rootDir>/x-pack/plugins/metrics_data_access'], + coverageDirectory: '<rootDir>/target/kibana-coverage/jest/x-pack/plugins/metrics_data_access', + coverageReporters: ['text', 'html'], + collectCoverageFrom: ['<rootDir>/x-pack/plugins/metrics_data/{server}/**/*.test.ts'], +}; diff --git a/x-pack/plugins/metrics_data_access/kibana.jsonc b/x-pack/plugins/metrics_data_access/kibana.jsonc new file mode 100644 index 0000000000000..6c721fe1734c1 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/kibana.jsonc @@ -0,0 +1,15 @@ +{ + "type": "plugin", + "id": "@kbn/metrics-data-access-plugin", + "owner": "@elastic/infra-monitoring-ui", + "description": "Exposes utilities for accessing metrics data", + "plugin": { + "id": "metricsDataAccess", + "server": true, + "browser": false, + "configPath": ["xpack", "metrics_data_access"], + "requiredPlugins": [], + "requiredBundles": [], + "extraPublicDirs": [] + } +} diff --git a/x-pack/plugins/metrics_data_access/server/client/client.test.ts b/x-pack/plugins/metrics_data_access/server/client/client.test.ts new file mode 100644 index 0000000000000..72449cf47132b --- /dev/null +++ b/x-pack/plugins/metrics_data_access/server/client/client.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import { MetricsDataClient } from './client'; +import { metricsDataSourceSavedObjectName } from '../saved_objects/metrics_data_source'; + +describe('MetricsDataClient', () => { + const client = new MetricsDataClient(); + + client.setDefaultMetricIndicesHandler(async () => { + return 'fallback-indices*'; + }); + + describe('metric indices', () => { + it('retrieves metrics saved object', async () => { + const savedObjectsClient = { + get: jest.fn().mockResolvedValue({ attributes: { metricIndices: 'foo,bar' } }), + }; + + const indices = await client.getMetricIndices({ + savedObjectsClient: savedObjectsClient as unknown as SavedObjectsClientContract, + }); + + expect(savedObjectsClient.get.mock.calls.length).toEqual(1); + expect(savedObjectsClient.get.mock.calls[0]).toEqual([ + metricsDataSourceSavedObjectName, + 'default', + ]); + expect(indices).toEqual('foo,bar'); + }); + + it('falls back to provided handler when no metrics saved object exists', async () => { + const savedObjectsClient = { + get: jest.fn().mockRejectedValue(SavedObjectsErrorHelpers.createGenericNotFoundError()), + }; + + const indices = await client.getMetricIndices({ + savedObjectsClient: savedObjectsClient as unknown as SavedObjectsClientContract, + }); + + expect(savedObjectsClient.get.mock.calls.length).toEqual(1); + expect(savedObjectsClient.get.mock.calls[0]).toEqual([ + metricsDataSourceSavedObjectName, + 'default', + ]); + expect(indices).toEqual('fallback-indices*'); + }); + }); +}); diff --git a/x-pack/plugins/metrics_data_access/server/client/client.ts b/x-pack/plugins/metrics_data_access/server/client/client.ts new file mode 100644 index 0000000000000..30d367cea0293 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/server/client/client.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsErrorHelpers } from '@kbn/core/server'; +import { + DefaultMetricIndicesHandler, + GetMetricIndicesOptions, + UpdateMetricIndicesOptions, +} from '../types'; +import { + MetricsDataSavedObject, + metricsDataSourceSavedObjectName, +} from '../saved_objects/metrics_data_source'; + +export class MetricsDataClient { + private readonly defaultSavedObjectId = 'default'; + private getDefaultMetricIndices: DefaultMetricIndicesHandler = null; + + async getMetricIndices(options: GetMetricIndicesOptions): Promise<string> { + if (!this.getDefaultMetricIndices) { + throw new Error('Missing getMetricsIndices fallback'); + } + + const metricIndices = await options.savedObjectsClient + .get<MetricsDataSavedObject>(metricsDataSourceSavedObjectName, this.defaultSavedObjectId) + .then(({ attributes }) => attributes.metricIndices) + .catch((err) => { + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + return this.getDefaultMetricIndices!(options); + } + + throw err; + }); + return metricIndices; + } + + async updateMetricIndices(options: UpdateMetricIndicesOptions) { + const object = await options.savedObjectsClient.create( + metricsDataSourceSavedObjectName, + { + metricIndices: options.metricIndices, + }, + { id: this.defaultSavedObjectId, overwrite: true } + ); + return object; + } + + setDefaultMetricIndicesHandler(handler: DefaultMetricIndicesHandler) { + this.getDefaultMetricIndices = handler; + } +} diff --git a/x-pack/plugins/ml/server/lib/sample_data_sets/index.ts b/x-pack/plugins/metrics_data_access/server/client/index.ts similarity index 81% rename from x-pack/plugins/ml/server/lib/sample_data_sets/index.ts rename to x-pack/plugins/metrics_data_access/server/client/index.ts index 1cdc7c76ba0d3..0d5314fb067bd 100644 --- a/x-pack/plugins/ml/server/lib/sample_data_sets/index.ts +++ b/x-pack/plugins/metrics_data_access/server/client/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { initSampleDataSets } from './sample_data_sets'; +export { MetricsDataClient } from './client'; diff --git a/x-pack/plugins/metrics_data_access/server/index.ts b/x-pack/plugins/metrics_data_access/server/index.ts new file mode 100644 index 0000000000000..919f5f357856e --- /dev/null +++ b/x-pack/plugins/metrics_data_access/server/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PluginInitializerContext } from '@kbn/core/server'; +import { MetricsDataPlugin } from './plugin'; + +export type { + MetricsDataPluginSetup, + GetMetricIndicesOptions, + UpdateMetricIndicesOptions, + DefaultMetricIndicesHandler, +} from './types'; + +export { metricsDataSourceSavedObjectName } from './saved_objects/metrics_data_source'; + +export { MetricsDataClient } from './client'; + +export function plugin(context: PluginInitializerContext) { + return new MetricsDataPlugin(context); +} diff --git a/x-pack/plugins/metrics_data_access/server/plugin.ts b/x-pack/plugins/metrics_data_access/server/plugin.ts new file mode 100644 index 0000000000000..0f51a7a33f888 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/server/plugin.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreSetup, PluginInitializerContext, Plugin } from '@kbn/core/server'; +import { MetricsDataPluginSetup } from './types'; +import { MetricsDataClient } from './client'; +import { metricsDataSourceSavedObjectType } from './saved_objects/metrics_data_source'; + +export class MetricsDataPlugin implements Plugin<MetricsDataPluginSetup, {}, {}, {}> { + private metricsClient: MetricsDataClient | null = null; + + constructor(context: PluginInitializerContext) {} + + public setup(core: CoreSetup) { + core.savedObjects.registerType(metricsDataSourceSavedObjectType); + + this.metricsClient = new MetricsDataClient(); + return { + client: this.metricsClient, + }; + } + + public start() { + return {}; + } + + public stop() {} +} diff --git a/x-pack/plugins/metrics_data_access/server/saved_objects/metrics_data_source/index.ts b/x-pack/plugins/metrics_data_access/server/saved_objects/metrics_data_source/index.ts new file mode 100644 index 0000000000000..d478f75658646 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/server/saved_objects/metrics_data_source/index.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObject, SavedObjectsType } from '@kbn/core/server'; + +export const metricsDataSourceSavedObjectName = 'metrics-data-source'; + +export interface MetricsDataSavedObject { + metricIndices: string; +} + +export const metricsDataSourceSavedObjectType: SavedObjectsType = { + name: metricsDataSourceSavedObjectName, + hidden: false, + namespaceType: 'single', + management: { + defaultSearchField: 'name', + displayName: 'metrics data source', + getTitle(savedObject: SavedObject<MetricsDataSavedObject>) { + return `Metrics data source [id=${savedObject.id}]`; + }, + icon: 'metricsApp', + importableAndExportable: true, + }, + mappings: { + dynamic: false, + properties: {}, + }, +}; diff --git a/x-pack/plugins/metrics_data_access/server/types.ts b/x-pack/plugins/metrics_data_access/server/types.ts new file mode 100644 index 0000000000000..3d13926899495 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/server/types.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; + +import { MetricsDataClient } from './client'; + +export interface MetricsDataPluginSetup { + client: MetricsDataClient; +} + +export interface GetMetricIndicesOptions { + savedObjectsClient: SavedObjectsClientContract; +} + +export type UpdateMetricIndicesOptions = GetMetricIndicesOptions & { + metricIndices: string; +}; + +export type DefaultMetricIndicesHandler = + | ((options: GetMetricIndicesOptions) => Promise<string>) + | null; diff --git a/x-pack/plugins/metrics_data_access/tsconfig.json b/x-pack/plugins/metrics_data_access/tsconfig.json new file mode 100644 index 0000000000000..b1dd132f12097 --- /dev/null +++ b/x-pack/plugins/metrics_data_access/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": ["../../../typings/**/*", "server/**/*"], + "exclude": ["target/**/*"], + "kbn_references": [ + "@kbn/core", + "@kbn/core-saved-objects-api-server", + ] +} diff --git a/x-pack/plugins/ml/common/constants/app.ts b/x-pack/plugins/ml/common/constants/app.ts index 970505f485739..00f6fa7a42d05 100644 --- a/x-pack/plugins/ml/common/constants/app.ts +++ b/x-pack/plugins/ml/common/constants/app.ts @@ -13,5 +13,6 @@ export const PLUGIN_ICON_SOLUTION = 'logoKibana'; export const ML_APP_NAME = i18n.translate('xpack.ml.navMenu.mlAppNameText', { defaultMessage: 'Machine Learning', }); +export const ML_APP_ROUTE = '/app/ml'; export const ML_INTERNAL_BASE_PATH = '/internal/ml'; export const ML_EXTERNAL_BASE_PATH = '/api/ml'; diff --git a/x-pack/plugins/ml/common/util/job_utils.test.ts b/x-pack/plugins/ml/common/util/job_utils.test.ts index d003710bb57e4..5b07c1018d701 100644 --- a/x-pack/plugins/ml/common/util/job_utils.test.ts +++ b/x-pack/plugins/ml/common/util/job_utils.test.ts @@ -22,8 +22,9 @@ import { resolveMaxTimeInterval, getFiltersForDSLQuery, isKnownEmptyQuery, + removeNodeInfo, } from './job_utils'; -import { CombinedJob, Job } from '../types/anomaly_detection_jobs'; +import type { CombinedJob, CombinedJobWithStats, Job } from '../types/anomaly_detection_jobs'; import { FilterStateStore } from '@kbn/es-query'; import moment from 'moment'; @@ -778,4 +779,39 @@ describe('getFiltersForDSLQuery', () => { expect(result).toBe(false); }); }); + + test('removes node info and returns a copy of the job', () => { + const job = { + job_id: 'test', + datafeed_config: { + datafeed_id: 'datafeed-test', + job_id: 'test', + indices: ['index1'], + query: { + match_all: {}, + }, + node: { + name: 'node-1', + ephemeral_id: '1234', + transport_address: 'localhost:9200', + attributes: {}, + }, + }, + node: { + name: 'node-1', + ephemeral_id: '1234', + transport_address: 'localhost:9200', + attributes: {}, + }, + } as never as CombinedJobWithStats; + + const result = removeNodeInfo(job); + expect(result.job_id).toBe('test'); + expect(result.node).toBe(undefined); + expect(result.datafeed_config.node).toBe(undefined); + + expect(job.job_id).toBe('test'); + expect(job.node).not.toBe(undefined); + expect(job.datafeed_config.node).not.toBe(undefined); + }); }); diff --git a/x-pack/plugins/ml/common/util/job_utils.ts b/x-pack/plugins/ml/common/util/job_utils.ts index 61420a61e7f09..f52019214f873 100644 --- a/x-pack/plugins/ml/common/util/job_utils.ts +++ b/x-pack/plugins/ml/common/util/job_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { each, isEmpty, isEqual, pick } from 'lodash'; +import { cloneDeep, each, isEmpty, isEqual, pick } from 'lodash'; import semverGte from 'semver/functions/gte'; import moment, { Duration } from 'moment'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -29,6 +29,7 @@ import { maxLengthValidator } from './validators'; import { CREATED_BY_LABEL } from '../constants/new_job'; import type { CombinedJob, + CombinedJobWithStats, CustomSettings, Datafeed, Job, @@ -936,3 +937,14 @@ export function extractInfluencers(jobs: Job | Job[]): string[] { } return Array.from(influencers); } + +export function removeNodeInfo(job: CombinedJobWithStats) { + const newJob = cloneDeep(job); + if (newJob.node !== undefined) { + delete newJob.node; + } + if (newJob.datafeed_config?.node !== undefined) { + delete newJob.datafeed_config.node; + } + return newJob; +} diff --git a/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts b/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts index 86446dfb1012e..3379c145bf364 100644 --- a/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts +++ b/x-pack/plugins/ml/public/alerting/register_ml_alerts.ts @@ -11,7 +11,7 @@ import type { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-action import type { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/public'; import { ML_ALERT_TYPES } from '../../common/constants/alerts'; import type { MlAnomalyDetectionAlertParams } from '../../common/types/alerts'; -import { PLUGIN_ID } from '../../common/constants/app'; +import { ML_APP_ROUTE, PLUGIN_ID } from '../../common/constants/app'; import { formatExplorerUrl } from '../locator/formatters/anomaly_detection'; import { validateLookbackInterval, validateTopNBucket } from './validators'; import { registerJobsHealthAlertingRule } from './jobs_health_rule'; @@ -149,6 +149,6 @@ export function registerNavigation(alerting: AlertingSetup) { ]), ]; - return formatExplorerUrl('/app/ml', { jobIds }); + return formatExplorerUrl(ML_APP_ROUTE, { jobIds }); }); } diff --git a/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx b/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx index 65ec83b2cabbf..e0c1728d893a5 100644 --- a/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx +++ b/x-pack/plugins/ml/public/application/aiops/change_point_detection.tsx @@ -15,7 +15,7 @@ import { ChangePointDetection } from '@kbn/aiops-plugin/public'; import { useDataSource } from '../contexts/ml/data_source_context'; import { useFieldStatsTrigger, FieldStatsFlyoutProvider } from '../components/field_stats_flyout'; -import { useMlKibana } from '../contexts/kibana'; +import { useMlKibana, useIsServerless } from '../contexts/kibana'; import { HelpMenu } from '../components/help_menu'; import { TechnicalPreviewBadge } from '../components/technical_preview_badge'; @@ -23,6 +23,7 @@ import { MlPageHeader } from '../components/page_header'; export const ChangePointDetectionPage: FC = () => { const { services } = useMlKibana(); + const isServerless = useIsServerless(); const { selectedDataView: dataView, selectedSavedSearch: savedSearch } = useDataSource(); @@ -45,6 +46,7 @@ export const ChangePointDetectionPage: FC = () => { <ChangePointDetection dataView={dataView} savedSearch={savedSearch} + isServerless={isServerless} appDependencies={{ ...pick(services, [ 'application', diff --git a/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx b/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx index 81412a726c1fa..eded907acabf2 100644 --- a/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx +++ b/x-pack/plugins/ml/public/application/aiops/log_categorization.tsx @@ -11,13 +11,14 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { LogCategorization } from '@kbn/aiops-plugin/public'; import { useDataSource } from '../contexts/ml/data_source_context'; -import { useMlKibana } from '../contexts/kibana'; +import { useMlKibana, useIsServerless } from '../contexts/kibana'; import { HelpMenu } from '../components/help_menu'; import { TechnicalPreviewBadge } from '../components/technical_preview_badge'; import { MlPageHeader } from '../components/page_header'; export const LogCategorizationPage: FC = () => { const { services } = useMlKibana(); + const isServerless = useIsServerless(); const { selectedDataView: dataView, selectedSavedSearch: savedSearch } = useDataSource(); @@ -40,6 +41,7 @@ export const LogCategorizationPage: FC = () => { <LogCategorization dataView={dataView} savedSearch={savedSearch} + isServerless={isServerless} appDependencies={pick(services, [ 'application', 'data', diff --git a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx index 1d9f4e7d92c4a..a61bf2d26bae1 100644 --- a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx +++ b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx @@ -12,13 +12,14 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { LogRateAnalysis } from '@kbn/aiops-plugin/public'; import { useDataSource } from '../contexts/ml/data_source_context'; -import { useMlKibana } from '../contexts/kibana'; +import { useMlKibana, useIsServerless } from '../contexts/kibana'; import { HelpMenu } from '../components/help_menu'; import { TechnicalPreviewBadge } from '../components/technical_preview_badge'; import { MlPageHeader } from '../components/page_header'; export const LogRateAnalysisPage: FC = () => { const { services } = useMlKibana(); + const isServerless = useIsServerless(); const { selectedDataView: dataView, selectedSavedSearch: savedSearch } = useDataSource(); @@ -43,6 +44,7 @@ export const LogRateAnalysisPage: FC = () => { stickyHistogram={false} dataView={dataView} savedSearch={savedSearch} + isServerless={isServerless} appDependencies={pick(services, [ 'application', 'data', diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index ca1a398de1cbf..a5993f99e4a9c 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -12,7 +12,7 @@ import { pick } from 'lodash'; import type { AppMountParameters, CoreStart, HttpStart } from '@kbn/core/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import { DatePickerContextProvider } from '@kbn/ml-date-picker'; +import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; @@ -41,6 +41,7 @@ interface AppProps { coreStart: CoreStart; deps: MlDependencies; appMountParams: AppMountParameters; + isServerless: boolean; } const localStorage = new Storage(window.localStorage); @@ -48,7 +49,11 @@ const localStorage = new Storage(window.localStorage); /** * Provides global services available across the entire ML app. */ -export function getMlGlobalServices(httpStart: HttpStart, usageCollection?: UsageCollectionSetup) { +export function getMlGlobalServices( + httpStart: HttpStart, + isServerless: boolean, + usageCollection?: UsageCollectionSetup +) { const httpService = new HttpService(httpStart); const mlApiServices = mlApiServicesProvider(httpService); @@ -58,6 +63,7 @@ export function getMlGlobalServices(httpStart: HttpStart, usageCollection?: Usag mlUsageCollection: mlUsageCollectionProvider(usageCollection), mlCapabilities: new MlCapabilitiesService(mlApiServices), mlLicense: new MlLicense(), + isServerless, }; } @@ -67,7 +73,7 @@ export interface MlServicesContext { export type MlGlobalServices = ReturnType<typeof getMlGlobalServices>; -const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => { +const App: FC<AppProps> = ({ coreStart, deps, appMountParams, isServerless }) => { const pageDeps: PageDependencies = { history: appMountParams.history, setHeaderActionMenu: appMountParams.setHeaderActionMenu, @@ -99,9 +105,9 @@ const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => { contentManagement: deps.contentManagement, presentationUtil: deps.presentationUtil, ...coreStart, - mlServices: getMlGlobalServices(coreStart.http, deps.usageCollection), + mlServices: getMlGlobalServices(coreStart.http, isServerless, deps.usageCollection), }; - }, [deps, coreStart]); + }, [deps, coreStart, isServerless]); useLifecycles( function setupLicenseOnMount() { @@ -122,9 +128,10 @@ const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => { if (!licenseReady || !mlCapabilities) return null; - const datePickerDeps = { + const datePickerDeps: DatePickerDependencies = { ...pick(services, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), uiSettingsKeys: UI_SETTINGS, + isServerless, }; const I18nContext = coreStart.i18n.Context; @@ -151,7 +158,8 @@ const App: FC<AppProps> = ({ coreStart, deps, appMountParams }) => { export const renderApp = ( coreStart: CoreStart, deps: MlDependencies, - appMountParams: AppMountParameters + appMountParams: AppMountParameters, + isServerless: boolean ) => { setDependencyCache({ timefilter: deps.data.query.timefilter, @@ -180,7 +188,12 @@ export const renderApp = ( appMountParams.onAppLeave((actions) => actions.default()); ReactDOM.render( - <App coreStart={coreStart} deps={deps} appMountParams={appMountParams} />, + <App + coreStart={coreStart} + deps={deps} + appMountParams={appMountParams} + isServerless={isServerless} + />, appMountParams.element ); diff --git a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts index c5325f4aa7614..ef0bf69c59c50 100644 --- a/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts +++ b/x-pack/plugins/ml/public/application/capabilities/check_capabilities.ts @@ -6,8 +6,15 @@ */ import { i18n } from '@kbn/i18n'; -import { BehaviorSubject, combineLatest, from, type Subscription, timer } from 'rxjs'; -import { distinctUntilChanged, retry, switchMap, tap } from 'rxjs/operators'; +import { + BehaviorSubject, + combineLatest, + from, + type Subscription, + timer, + firstValueFrom, +} from 'rxjs'; +import { distinctUntilChanged, filter, retry, switchMap, tap } from 'rxjs/operators'; import { isEqual } from 'lodash'; import useObservable from 'react-use/lib/useObservable'; import { useMemo, useRef } from 'react'; @@ -16,11 +23,12 @@ import { hasLicenseExpired } from '../license'; import { getDefaultCapabilities, - MlCapabilities, - MlCapabilitiesKey, + type MlCapabilities, + type MlCapabilitiesKey, } from '../../../common/types/capabilities'; import { getCapabilities } from './get_capabilities'; -import { type MlApiServices } from '../services/ml_api_service'; +import type { MlApiServices } from '../services/ml_api_service'; +import type { MlGlobalServices } from '../app'; let _capabilities: MlCapabilities = getDefaultCapabilities(); @@ -36,6 +44,10 @@ export class MlCapabilitiesService { private _updateRequested$ = new BehaviorSubject<number>(Date.now()); private _capabilities$ = new BehaviorSubject<MlCapabilities | null>(null); + private _capabilitiesObs$ = this._capabilities$.asObservable(); + + private _isPlatinumOrTrialLicense$ = new BehaviorSubject<boolean | null>(null); + private _mlFeatureEnabledInSpace$ = new BehaviorSubject<boolean | null>(null); public capabilities$ = this._capabilities$.pipe(distinctUntilChanged(isEqual)); @@ -59,6 +71,8 @@ export class MlCapabilitiesService { ) .subscribe((results) => { this._capabilities$.next(results.capabilities); + this._isPlatinumOrTrialLicense$.next(results.isPlatinumOrTrialLicense); + this._mlFeatureEnabledInSpace$.next(results.mlFeatureEnabledInSpace); this._isLoading$.next(false); /** @@ -72,6 +86,18 @@ export class MlCapabilitiesService { return this._capabilities$.getValue(); } + public isPlatinumOrTrialLicense(): boolean | null { + return this._isPlatinumOrTrialLicense$.getValue(); + } + + public mlFeatureEnabledInSpace(): boolean | null { + return this._mlFeatureEnabledInSpace$.getValue(); + } + + public getCapabilities$() { + return this._capabilitiesObs$; + } + public refreshCapabilities() { this._updateRequested$.next(Date.now()); } @@ -111,23 +137,34 @@ export function usePermissionCheck<T extends MlCapabilitiesKey | MlCapabilitiesK }, [capabilities]); } -export function checkGetManagementMlJobsResolver({ checkMlCapabilities }: MlApiServices) { - return new Promise<{ mlFeatureEnabledInSpace: boolean }>((resolve, reject) => { - checkMlCapabilities() - .then(({ capabilities, isPlatinumOrTrialLicense, mlFeatureEnabledInSpace }) => { - _capabilities = capabilities; - // Loop through all capabilities to ensure they are all set to true. - const isManageML = Object.values(_capabilities).every((p) => p === true); +export function checkGetManagementMlJobsResolver({ mlCapabilities }: MlGlobalServices) { + return new Promise<void>(async (resolve, reject) => { + try { + const capabilities = await firstValueFrom( + mlCapabilities.getCapabilities$().pipe(filter((c) => !!c)) + ); - if (isManageML === true && isPlatinumOrTrialLicense === true) { - return resolve({ mlFeatureEnabledInSpace }); - } else { - return reject({ capabilities, isPlatinumOrTrialLicense, mlFeatureEnabledInSpace }); - } - }) - .catch((e) => { + if (capabilities === null) { return reject(); - }); + } + _capabilities = capabilities; + const isManageML = + (capabilities.isADEnabled && capabilities.canCreateJob) || + (capabilities.isDFAEnabled && capabilities.canCreateDataFrameAnalytics) || + (capabilities.isNLPEnabled && capabilities.canCreateTrainedModels); + if (isManageML === true) { + return resolve(); + } else { + // reject with possible reasons why capabilities are false + return reject({ + capabilities, + isPlatinumOrTrialLicense: mlCapabilities.isPlatinumOrTrialLicense(), + mlFeatureEnabledInSpace: mlCapabilities.mlFeatureEnabledInSpace(), + }); + } + } catch (error) { + reject(error); + } }); } diff --git a/x-pack/plugins/ml/public/application/components/import_export_jobs/export_jobs_flyout/export_jobs_flyout.tsx b/x-pack/plugins/ml/public/application/components/import_export_jobs/export_jobs_flyout/export_jobs_flyout.tsx index 4c53bbd1c4a17..5bf0e73b2cee1 100644 --- a/x-pack/plugins/ml/public/application/components/import_export_jobs/export_jobs_flyout/export_jobs_flyout.tsx +++ b/x-pack/plugins/ml/public/application/components/import_export_jobs/export_jobs_flyout/export_jobs_flyout.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useState, useEffect, useMemo, useCallback } from 'react'; +import React, { FC, useState, useEffect, useMemo, useCallback, useRef } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { @@ -26,12 +26,13 @@ import { EuiConfirmModal, } from '@elastic/eui'; -import { useMlApiContext, useMlKibana } from '../../../contexts/kibana'; +import { useMlKibana } from '../../../contexts/kibana'; import { ExportJobDependenciesWarningCallout } from './export_job_warning_callout'; import { JobsExportService } from './jobs_export_service'; import type { JobDependencies } from './jobs_export_service'; import { toastNotificationServiceProvider } from '../../../services/toast_notification_service'; import type { JobType } from '../../../../../common/types/saved_objects'; +import { usePermissionCheck } from '../../../capabilities/check_capabilities'; interface Props { isDisabled: boolean; @@ -39,21 +40,19 @@ interface Props { } export const ExportJobsFlyout: FC<Props> = ({ isDisabled, currentTab }) => { - const mlApiServices = useMlApiContext(); - const { - getJobs, - dataFrameAnalytics: { getDataFrameAnalytics }, - } = mlApiServices; - const { services: { notifications: { toasts }, - mlServices: { mlUsageCollection }, + mlServices: { mlUsageCollection, mlApiServices }, }, } = useMlKibana(); - // eslint-disable-next-line react-hooks/exhaustive-deps - const jobsExportService = useMemo(() => new JobsExportService(mlApiServices), []); + const { + getJobs, + dataFrameAnalytics: { getDataFrameAnalytics }, + } = mlApiServices; + + const jobsExportService = useMemo(() => new JobsExportService(mlApiServices), [mlApiServices]); const [loadingADJobs, setLoadingADJobs] = useState(true); const [loadingDFAJobs, setLoadingDFAJobs] = useState(true); @@ -69,10 +68,18 @@ export const ExportJobsFlyout: FC<Props> = ({ isDisabled, currentTab }) => { () => toastNotificationServiceProvider(toasts), [toasts] ); + const [isADEnabled, isDFAEnabled] = usePermissionCheck(['isADEnabled', 'isDFAEnabled']); const [jobDependencies, setJobDependencies] = useState<JobDependencies>([]); const [selectedJobDependencies, setSelectedJobDependencies] = useState<JobDependencies>([]); + const isMounted = useRef(true); + useEffect(() => { + return () => { + isMounted.current = false; + }; + }, []); + useEffect( function onFlyoutChange() { setLoadingADJobs(true); @@ -84,49 +91,68 @@ export const ExportJobsFlyout: FC<Props> = ({ isDisabled, currentTab }) => { setSwitchTabConfirmVisible(false); if (showFlyout) { - getJobs() - .then(({ jobs }) => { - setLoadingADJobs(false); - setAdJobIds(jobs.map((j) => j.job_id)); - - jobsExportService - .getJobDependencies(jobs) - .then((jobDeps) => { - setJobDependencies(jobDeps); - setLoadingADJobs(false); - }) - .catch((error) => { - const errorTitle = i18n.translate( - 'xpack.ml.importExport.exportFlyout.calendarsError', - { - defaultMessage: 'Could not load calendars', - } - ); - displayErrorToast(error, errorTitle); + if (isADEnabled) { + getJobs() + .then(({ jobs }) => { + if (isMounted.current === false) return; + setLoadingADJobs(false); + setAdJobIds(jobs.map((j) => j.job_id)); + + jobsExportService + .getJobDependencies(jobs) + .then((jobDeps) => { + if (isMounted.current === false) return; + setJobDependencies(jobDeps); + setLoadingADJobs(false); + }) + .catch((error) => { + if (isMounted.current === false) return; + const errorTitle = i18n.translate( + 'xpack.ml.importExport.exportFlyout.calendarsError', + { + defaultMessage: 'Could not load calendars', + } + ); + displayErrorToast(error, errorTitle); + }); + }) + .catch((error) => { + if (isMounted.current === false) return; + const errorTitle = i18n.translate('xpack.ml.importExport.exportFlyout.adJobsError', { + defaultMessage: 'Could not load anomaly detection jobs', }); - }) - .catch((error) => { - const errorTitle = i18n.translate('xpack.ml.importExport.exportFlyout.adJobsError', { - defaultMessage: 'Could not load anomaly detection jobs', + displayErrorToast(error, errorTitle); }); - displayErrorToast(error, errorTitle); - }); - - getDataFrameAnalytics() - .then(({ data_frame_analytics: dataFrameAnalytics }) => { - setLoadingDFAJobs(false); - setDfaJobIds(dataFrameAnalytics.map((j) => j.id)); - }) - .catch((error) => { - const errorTitle = i18n.translate('xpack.ml.importExport.exportFlyout.dfaJobsError', { - defaultMessage: 'Could not load data frame analytics jobs', + } + + if (isDFAEnabled) { + getDataFrameAnalytics() + .then(({ data_frame_analytics: dataFrameAnalytics }) => { + if (isMounted.current === false) return; + setLoadingDFAJobs(false); + setDfaJobIds(dataFrameAnalytics.map((j) => j.id)); + }) + .catch((error) => { + if (isMounted.current === false) return; + + const errorTitle = i18n.translate('xpack.ml.importExport.exportFlyout.dfaJobsError', { + defaultMessage: 'Could not load data frame analytics jobs', + }); + displayErrorToast(error, errorTitle); }); - displayErrorToast(error, errorTitle); - }); + } } }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [showFlyout] + [ + currentTab, + displayErrorToast, + getDataFrameAnalytics, + getJobs, + isADEnabled, + isDFAEnabled, + jobsExportService, + showFlyout, + ] ); function toggleFlyout() { @@ -188,16 +214,15 @@ export const ExportJobsFlyout: FC<Props> = ({ isDisabled, currentTab }) => { switchTab(jobType); }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [selectedJobIds] + + [selectedJobIds, selectedJobType] ); useEffect(() => { setSelectedJobDependencies( jobDependencies.filter(({ jobId }) => selectedJobIds.includes(jobId)) ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedJobIds]); + }, [jobDependencies, selectedJobIds]); function switchTab(jobType: JobType) { setSwitchTabConfirmVisible(false); @@ -214,6 +239,10 @@ export const ExportJobsFlyout: FC<Props> = ({ isDisabled, currentTab }) => { } } + if (isADEnabled === false && isDFAEnabled === false) { + return null; + } + return ( <> <FlyoutButton onClick={toggleFlyout} isDisabled={isDisabled} /> @@ -239,32 +268,36 @@ export const ExportJobsFlyout: FC<Props> = ({ isDisabled, currentTab }) => { <EuiFlyoutBody> <ExportJobDependenciesWarningCallout jobs={selectedJobDependencies} /> <EuiTabs size="s"> - <EuiTab - isSelected={selectedJobType === 'anomaly-detector'} - onClick={() => attemptTabSwitch('anomaly-detector')} - disabled={exporting} - data-test-subj="mlJobMgmtExportJobsADTab" - > - <FormattedMessage - id="xpack.ml.importExport.exportFlyout.adTab" - defaultMessage="Anomaly detection" - /> - </EuiTab> - <EuiTab - isSelected={selectedJobType === 'data-frame-analytics'} - onClick={() => attemptTabSwitch('data-frame-analytics')} - disabled={exporting} - data-test-subj="mlJobMgmtExportJobsDFATab" - > - <FormattedMessage - id="xpack.ml.importExport.exportFlyout.dfaTab" - defaultMessage="Analytics" - /> - </EuiTab> + {isADEnabled === true ? ( + <EuiTab + isSelected={selectedJobType === 'anomaly-detector'} + onClick={() => attemptTabSwitch('anomaly-detector')} + disabled={exporting} + data-test-subj="mlJobMgmtExportJobsADTab" + > + <FormattedMessage + id="xpack.ml.importExport.exportFlyout.adTab" + defaultMessage="Anomaly detection" + /> + </EuiTab> + ) : null} + {isDFAEnabled === true ? ( + <EuiTab + isSelected={selectedJobType === 'data-frame-analytics'} + onClick={() => attemptTabSwitch('data-frame-analytics')} + disabled={exporting} + data-test-subj="mlJobMgmtExportJobsDFATab" + > + <FormattedMessage + id="xpack.ml.importExport.exportFlyout.dfaTab" + defaultMessage="Analytics" + /> + </EuiTab> + ) : null} </EuiTabs> <EuiSpacer size="s" /> <> - {selectedJobType === 'anomaly-detector' && ( + {isADEnabled === true && selectedJobType === 'anomaly-detector' && ( <> {loadingADJobs === true ? ( <LoadingSpinner /> @@ -308,7 +341,7 @@ export const ExportJobsFlyout: FC<Props> = ({ isDisabled, currentTab }) => { )} </> )} - {selectedJobType === 'data-frame-analytics' && ( + {isDFAEnabled === true && selectedJobType === 'data-frame-analytics' && ( <> {loadingDFAJobs === true ? ( <LoadingSpinner /> diff --git a/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx b/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx index 6c6dc10f085f5..61e6df17676cb 100644 --- a/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx +++ b/x-pack/plugins/ml/public/application/components/import_export_jobs/import_jobs_flyout/import_jobs_flyout.tsx @@ -33,30 +33,33 @@ import { type ErrorType, extractErrorProperties } from '@kbn/ml-error-utils'; import type { DataFrameAnalyticsConfig } from '@kbn/ml-data-frame-analytics-utils'; import type { JobType } from '../../../../../common/types/saved_objects'; -import { useMlApiContext, useMlKibana } from '../../../contexts/kibana'; +import { useMlKibana } from '../../../contexts/kibana'; import { CannotImportJobsCallout } from './cannot_import_jobs_callout'; import { CannotReadFileCallout } from './cannot_read_file_callout'; import { toastNotificationServiceProvider } from '../../../services/toast_notification_service'; import { JobImportService } from './jobs_import_service'; import { useValidateIds } from './validate'; import type { ImportedAdJob, JobIdObject, SkippedJobs } from './jobs_import_service'; +import { usePermissionCheck } from '../../../capabilities/check_capabilities'; interface Props { isDisabled: boolean; } export const ImportJobsFlyout: FC<Props> = ({ isDisabled }) => { - const { - jobs: { bulkCreateJobs }, - dataFrameAnalytics: { createDataFrameAnalytics }, - filters: { filters: getFilters }, - } = useMlApiContext(); const { services: { data: { dataViews: { getTitles: getDataViewTitles }, }, notifications: { toasts }, - mlServices: { mlUsageCollection }, + mlServices: { + mlUsageCollection, + mlApiServices: { + jobs: { bulkCreateJobs }, + dataFrameAnalytics: { createDataFrameAnalytics }, + filters: { filters: getFilters }, + }, + }, }, } = useMlKibana(); @@ -79,6 +82,7 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled }) => { () => toastNotificationServiceProvider(toasts), [toasts] ); + const [isADEnabled, isDFAEnabled] = usePermissionCheck(['isADEnabled', 'isDFAEnabled']); const [validateIds] = useValidateIds( jobType, @@ -123,7 +127,11 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled }) => { try { const loadedFile = await jobImportService.readJobConfigs(files[0]); - if (loadedFile.jobType === null) { + if ( + loadedFile.jobType === null || + (loadedFile.jobType === 'anomaly-detector' && isADEnabled === false) || + (loadedFile.jobType === 'data-frame-analytics' && isDFAEnabled === false) + ) { reset(true); return; } @@ -177,19 +185,19 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled }) => { const onImport = useCallback(async () => { setImporting(true); - if (jobType === 'anomaly-detector') { - const renamedJobs = jobImportService.renameAdJobs(jobIdObjects, adJobs); - try { + try { + if (jobType === 'anomaly-detector' && isADEnabled === true) { + const renamedJobs = jobImportService.renameAdJobs(jobIdObjects, adJobs); await bulkCreateADJobs(renamedJobs); mlUsageCollection.count('imported_anomaly_detector_jobs', renamedJobs.length); - } catch (error) { - // display unexpected error - displayErrorToast(error); + } else if (jobType === 'data-frame-analytics' && isDFAEnabled === true) { + const renamedJobs = jobImportService.renameDfaJobs(jobIdObjects, dfaJobs); + await bulkCreateDfaJobs(renamedJobs); + mlUsageCollection.count('imported_data_frame_analytics_jobs', renamedJobs.length); } - } else if (jobType === 'data-frame-analytics') { - const renamedJobs = jobImportService.renameDfaJobs(jobIdObjects, dfaJobs); - await bulkCreateDfaJobs(renamedJobs); - mlUsageCollection.count('imported_data_frame_analytics_jobs', renamedJobs.length); + } catch (error) { + // display unexpected error + displayErrorToast(error); } setImporting(false); @@ -347,6 +355,10 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled }) => { /> ); + if (isADEnabled === false && isDFAEnabled === false) { + return null; + } + return ( <> <FlyoutButton onClick={toggleFlyout} isDisabled={isDisabled} /> diff --git a/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx b/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx index 16bbf4490e9ad..20faeaf0bdfd2 100644 --- a/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx +++ b/x-pack/plugins/ml/public/application/components/job_messages/job_messages.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { EuiBasicTableColumn, @@ -25,6 +25,7 @@ import { JobMessage } from '../../../../common/types/audit_message'; import { blurButtonOnClick } from '../../util/component_utils'; import { JobIcon } from '../job_message_icon'; +import { useIsServerless } from '../../contexts/kibana'; interface JobMessagesProps { messages: JobMessage[]; @@ -45,54 +46,62 @@ export const JobMessages: FC<JobMessagesProps> = ({ refreshMessage, actionHandler, }) => { - const columns: Array<EuiBasicTableColumn<JobMessage>> = [ - { - name: refreshMessage ? ( - <EuiToolTip - content={i18n.translate('xpack.ml.jobMessages.refreshLabel', { - defaultMessage: 'Refresh', - })} - > - <EuiButtonIcon - onClick={blurButtonOnClick(() => { - refreshMessage(); - })} - iconType="refresh" - aria-label={i18n.translate('xpack.ml.jobMessages.refreshAriaLabel', { + const isServerless = useIsServerless(); + const columns: Array<EuiBasicTableColumn<JobMessage>> = useMemo(() => { + const cols = [ + { + name: refreshMessage ? ( + <EuiToolTip + content={i18n.translate('xpack.ml.jobMessages.refreshLabel', { defaultMessage: 'Refresh', })} - /> - </EuiToolTip> - ) : ( - '' - ), - render: (message: JobMessage) => <JobIcon message={message} />, - width: `${theme.euiSizeL}`, - }, - { - field: 'timestamp', - name: i18n.translate('xpack.ml.jobMessages.timeLabel', { - defaultMessage: 'Time', - }), - render: timeFormatter, - width: '120px', - sortable: true, - }, - { - field: 'node_name', - name: i18n.translate('xpack.ml.jobMessages.nodeLabel', { - defaultMessage: 'Node', - }), - width: '150px', - }, - { - field: 'message', - name: i18n.translate('xpack.ml.jobMessages.messageLabel', { - defaultMessage: 'Message', - }), - width: '50%', - }, - ]; + > + <EuiButtonIcon + onClick={blurButtonOnClick(() => { + refreshMessage(); + })} + iconType="refresh" + aria-label={i18n.translate('xpack.ml.jobMessages.refreshAriaLabel', { + defaultMessage: 'Refresh', + })} + /> + </EuiToolTip> + ) : ( + '' + ), + render: (message: JobMessage) => <JobIcon message={message} />, + width: `${theme.euiSizeL}`, + }, + { + field: 'timestamp', + name: i18n.translate('xpack.ml.jobMessages.timeLabel', { + defaultMessage: 'Time', + }), + render: timeFormatter, + width: '120px', + sortable: true, + }, + { + field: 'message', + name: i18n.translate('xpack.ml.jobMessages.messageLabel', { + defaultMessage: 'Message', + }), + width: '50%', + }, + ]; + + if (isServerless === false) { + cols.splice(2, 0, { + field: 'node_name', + name: i18n.translate('xpack.ml.jobMessages.nodeLabel', { + defaultMessage: 'Node', + }), + width: '150px', + }); + } + + return cols; + }, [isServerless, refreshMessage]); if (typeof actionHandler === 'function') { columns.push({ diff --git a/x-pack/plugins/ml/public/application/components/job_spaces_sync/sync_list.tsx b/x-pack/plugins/ml/public/application/components/job_spaces_sync/sync_list.tsx index 8d724f5b6187e..211dc1aa8c57b 100644 --- a/x-pack/plugins/ml/public/application/components/job_spaces_sync/sync_list.tsx +++ b/x-pack/plugins/ml/public/application/components/job_spaces_sync/sync_list.tsx @@ -18,8 +18,11 @@ import { } from '@elastic/eui'; import type { SyncSavedObjectResponse, SyncResult } from '../../../../common/types/saved_objects'; +import { usePermissionCheck } from '../../capabilities/check_capabilities'; export const SyncList: FC<{ syncItems: SyncSavedObjectResponse | null }> = ({ syncItems }) => { + const [isADEnabled] = usePermissionCheck(['isADEnabled']); + if (syncItems === null) { return null; } @@ -34,13 +37,17 @@ export const SyncList: FC<{ syncItems: SyncSavedObjectResponse | null }> = ({ sy <EuiHorizontalRule margin="l" /> - <DatafeedsAdded syncItems={syncItems} /> + {isADEnabled ? ( + <> + <DatafeedsAdded syncItems={syncItems} /> - <EuiHorizontalRule margin="l" /> + <EuiHorizontalRule margin="l" /> - <DatafeedsRemoved syncItems={syncItems} /> + <DatafeedsRemoved syncItems={syncItems} /> - <EuiHorizontalRule margin="l" /> + <EuiHorizontalRule margin="l" /> + </> + ) : null} </> ); }; diff --git a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx index 07a10b6a36c81..a85776aeacc82 100644 --- a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx +++ b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/jobs_awaiting_node_warning.tsx @@ -10,13 +10,15 @@ import React, { FC } from 'react'; import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { lazyMlNodesAvailable } from '../../ml_nodes_check'; +import { useIsServerless } from '../../contexts/kibana'; interface Props { jobCount: number; } export const JobsAwaitingNodeWarning: FC<Props> = ({ jobCount }) => { - if (lazyMlNodesAvailable() === false || jobCount === 0) { + const isServerless = useIsServerless(); + if (isServerless || lazyMlNodesAvailable() === false || jobCount === 0) { return null; } diff --git a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node.tsx b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node.tsx index 760ebc521d251..5055efad210f0 100644 --- a/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node.tsx +++ b/x-pack/plugins/ml/public/application/components/jobs_awaiting_node_warning/new_job_awaiting_node.tsx @@ -11,17 +11,33 @@ import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { JobType } from '../../../../common/types/saved_objects'; import { lazyMlNodesAvailable } from '../../ml_nodes_check'; +import { useIsServerless } from '../../contexts/kibana'; interface Props { jobType: JobType; } export const NewJobAwaitingNodeWarning: FC<Props> = () => { + const isServerless = useIsServerless(); if (lazyMlNodesAvailable() === false) { return null; } - return ( + return isServerless ? ( + <> + <EuiCallOut + title={ + <FormattedMessage + id="xpack.ml.jobsAwaitingNodeWarning.serverless.title" + defaultMessage="Machine learning is starting..." + /> + } + color="primary" + iconType="iInCircle" + /> + <EuiSpacer size="m" /> + </> + ) : ( <> <EuiCallOut title={ diff --git a/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.test.tsx b/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.test.tsx index 8ae78666f2afb..52f55cf26f0da 100644 --- a/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.test.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.test.tsx @@ -14,6 +14,7 @@ import { useToastNotificationService } from '../../services/toast_notification_s jest.mock('../../contexts/kibana'); jest.mock('../../services/toast_notification_service'); +jest.mock('../../capabilities/check_capabilities'); describe('MlEntitySelector', () => { const getAllJobAndGroupIds = jest.fn(() => { diff --git a/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.tsx b/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.tsx index c31d091fdf67c..22c14ff7d72a9 100644 --- a/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_entity_selector/ml_entity_selector.tsx @@ -17,6 +17,7 @@ import { countBy } from 'lodash'; import useMount from 'react-use/lib/useMount'; import { useMlApiContext } from '../../contexts/kibana'; import { useToastNotificationService } from '../../services/toast_notification_service'; +import { usePermissionCheck } from '../../capabilities/check_capabilities'; type EntityType = 'anomaly_detector' | 'data_frame_analytics' | 'trained_models'; @@ -60,6 +61,11 @@ export const MlEntitySelector: FC<MlEntitySelectorProps> = ({ onSelectionChange, handleDuplicates = false, }) => { + const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ + 'isADEnabled', + 'isDFAEnabled', + 'isNLPEnabled', + ]); const { jobs: jobsApi, trainedModels, dataFrameAnalytics } = useMlApiContext(); const { displayErrorToast } = useToastNotificationService(); const visColorsBehindText = euiPaletteColorBlindBehindText(); @@ -70,7 +76,7 @@ export const MlEntitySelector: FC<MlEntitySelectorProps> = ({ const fetchOptions = useCallback(async () => { try { const newOptions: Array<EuiComboBoxOptionOption<string>> = []; - if (entityTypes?.anomaly_detector) { + if (isADEnabled && entityTypes?.anomaly_detector) { const { jobIds: jobIdOptions } = await jobsApi.getAllJobAndGroupIds(); newOptions.push({ @@ -90,7 +96,7 @@ export const MlEntitySelector: FC<MlEntitySelectorProps> = ({ }); } - if (entityTypes?.data_frame_analytics) { + if (isDFAEnabled && entityTypes?.data_frame_analytics) { const dfa = await dataFrameAnalytics.getDataFrameAnalytics(); if (dfa.count > 0) { newOptions.push({ @@ -110,7 +116,7 @@ export const MlEntitySelector: FC<MlEntitySelectorProps> = ({ } } - if (entityTypes?.trained_models) { + if ((isDFAEnabled || isNLPEnabled) && entityTypes?.trained_models) { const models = await trainedModels.getTrainedModels(); if (models.length > 0) { newOptions.push({ @@ -147,6 +153,9 @@ export const MlEntitySelector: FC<MlEntitySelectorProps> = ({ entityTypes, visColorsBehindText, displayErrorToast, + isADEnabled, + isDFAEnabled, + isNLPEnabled, ]); useMount(function fetchOptionsOnMount() { diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 6c981351d5f63..3eb1deb83e7ae 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -20,7 +20,7 @@ import { DatePickerWrapper } from '@kbn/ml-date-picker'; import * as routes from '../../routing/routes'; import { MlPageWrapper } from '../../routing/ml_page_wrapper'; -import { useMlKibana, useNavigateToPath } from '../../contexts/kibana'; +import { useMlKibana, useNavigateToPath, useIsServerless } from '../../contexts/kibana'; import type { MlRoute, PageDependencies } from '../../routing/router'; import { useActiveRoute } from '../../routing/use_active_route'; import { useDocTitle } from '../../routing/use_doc_title'; @@ -28,7 +28,6 @@ import { useDocTitle } from '../../routing/use_doc_title'; import { MlPageHeaderRenderer } from '../page_header/page_header'; import { useSideNavItems } from './side_nav'; -import { usePermissionCheck } from '../../capabilities/check_capabilities'; const ML_APP_SELECTOR = '[data-test-subj="mlApp"]'; @@ -56,22 +55,12 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps mlServices: { httpService }, }, } = useMlKibana(); + const isServerless = useIsServerless(); const headerPortalNode = useMemo(() => createHtmlPortalNode(), []); const [isHeaderMounted, setIsHeaderMounted] = useState(false); const [isLoading, setIsLoading] = useState(false); - const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ - 'isADEnabled', - 'isDFAEnabled', - 'isNLPEnabled', - ]); - - const navMenuEnabled = useMemo( - () => isADEnabled && isDFAEnabled && isNLPEnabled, - [isADEnabled, isDFAEnabled, isNLPEnabled] - ); - useEffect(() => { const subscriptions = new Subscription(); @@ -138,7 +127,7 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps data-test-subj={'mlApp'} restrictWidth={false} solutionNav={ - navMenuEnabled + isServerless === false ? { name: i18n.translate('xpack.ml.plugin.title', { defaultMessage: 'Machine Learning', diff --git a/x-pack/plugins/ml/public/application/components/saved_objects_warning/saved_objects_warning.tsx b/x-pack/plugins/ml/public/application/components/saved_objects_warning/saved_objects_warning.tsx index 342caa5225883..1e935e657a1e2 100644 --- a/x-pack/plugins/ml/public/application/components/saved_objects_warning/saved_objects_warning.tsx +++ b/x-pack/plugins/ml/public/application/components/saved_objects_warning/saved_objects_warning.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useCallback, useEffect, useRef, useState } from 'react'; +import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import type { MlSavedObjectType } from '../../../../common/types/saved_objects'; @@ -31,7 +31,17 @@ export const SavedObjectsWarning: FC<Props> = ({ const mounted = useRef(false); const [showWarning, setShowWarning] = useState(false); const [showSyncFlyout, setShowSyncFlyout] = useState(false); - const canCreateJob = usePermissionCheck('canCreateJob'); + + const [canCreateJob, canCreateDataFrameAnalytics, canCreateTrainedModels] = usePermissionCheck([ + 'canCreateJob', + 'canCreateDataFrameAnalytics', + 'canCreateTrainedModels', + ]); + + const canSync = useMemo( + () => canCreateJob || canCreateDataFrameAnalytics || canCreateTrainedModels, + [canCreateDataFrameAnalytics, canCreateJob, canCreateTrainedModels] + ); const checkStatus = useCallback(async () => { try { @@ -101,7 +111,7 @@ export const SavedObjectsWarning: FC<Props> = ({ id="xpack.ml.jobsList.missingSavedObjectWarning.description" defaultMessage="Some jobs or trained models are missing or have incomplete saved objects. " /> - {canCreateJob ? ( + {canSync ? ( <FormattedMessage id="xpack.ml.jobsList.missingSavedObjectWarning.link" defaultMessage=" {link}" diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/index.ts b/x-pack/plugins/ml/public/application/contexts/kibana/index.ts index e8696e9b49068..afedbdef15b6c 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/index.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/index.ts @@ -16,3 +16,4 @@ export { useMlApiContext } from './use_ml_api_context'; export { useFieldFormatter } from './use_field_formatter'; export { useCurrentThemeVars } from './use_current_theme'; export { useMlLicenseInfo } from './use_ml_license'; +export { useIsServerless } from './use_is_serverless'; diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/use_is_serverless.ts b/x-pack/plugins/ml/public/application/contexts/kibana/use_is_serverless.ts new file mode 100644 index 0000000000000..ca98dd44c17ce --- /dev/null +++ b/x-pack/plugins/ml/public/application/contexts/kibana/use_is_serverless.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMlKibana } from './kibana_context'; + +export function useIsServerless(): boolean { + return useMlKibana().services.mlServices.isServerless; +} diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/use_navigate_to_path.ts b/x-pack/plugins/ml/public/application/contexts/kibana/use_navigate_to_path.ts index bd2d3303b8fd8..d9217be9b85b5 100644 --- a/x-pack/plugins/ml/public/application/contexts/kibana/use_navigate_to_path.ts +++ b/x-pack/plugins/ml/public/application/contexts/kibana/use_navigate_to_path.ts @@ -7,7 +7,7 @@ import { useCallback } from 'react'; import { useLocation } from 'react-router-dom'; -import { PLUGIN_ID } from '../../../../common/constants/app'; +import { ML_APP_ROUTE, PLUGIN_ID } from '../../../../common/constants/app'; import { useMlKibana } from './kibana_context'; @@ -29,7 +29,7 @@ export const useNavigateToPath = () => { /** * Handle urls generated by MlUrlGenerator where '/app/ml' is automatically prepended */ - const url = modifiedPath.includes('/app/ml') + const url = modifiedPath.includes(ML_APP_ROUTE) ? modifiedPath : getUrlForApp(PLUGIN_ID, { path: modifiedPath, diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx index c86808bd9b255..74356242ae8aa 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/job_map/components/controls.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC, useEffect, useState, useContext, useCallback } from 'react'; +import React, { FC, useEffect, useState, useContext, useCallback, useMemo } from 'react'; import cytoscape from 'cytoscape'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -37,6 +37,7 @@ import { useNotifications, useNavigateToPath, useMlKibana, + useIsServerless, } from '../../../../contexts/kibana'; import { getDataViewIdFromName } from '../../../../util/index_utils'; import { useNavigateToWizardWithClonedJob } from '../../analytics_management/components/action_clone/clone_action_name'; @@ -47,34 +48,40 @@ import { import { DeleteSpaceAwareItemCheckModal } from '../../../../components/delete_space_aware_item_check_modal'; interface Props { - details: any; + details: Record<string, any>; getNodeData: any; modelId?: string; updateElements: (nodeId: string, nodeLabel: string, destIndexNode?: string) => void; refreshJobsCallback: () => void; } -function getListItems(details: object): EuiDescriptionListProps['listItems'] { - return Object.entries(details).map(([key, value]) => { - let description; - if (key === 'create_time') { - description = formatHumanReadableDateTimeSeconds(moment(value).unix() * 1000); - } else { - description = - typeof value === 'object' ? ( - <EuiCodeBlock language="json" fontSize="s" paddingSize="s"> - {JSON.stringify(value, null, 2)} - </EuiCodeBlock> - ) : ( - value - ); +function getListItemsFactory(isServerless: boolean) { + return (details: Record<string, any>): EuiDescriptionListProps['listItems'] => { + if (isServerless) { + delete details.license_level; } - return { - title: key, - description, - }; - }); + return Object.entries(details).map(([key, value]) => { + let description; + if (key === 'create_time') { + description = formatHumanReadableDateTimeSeconds(moment(value).unix() * 1000); + } else { + description = + typeof value === 'object' ? ( + <EuiCodeBlock language="json" fontSize="s" paddingSize="s"> + {JSON.stringify(value, null, 2)} + </EuiCodeBlock> + ) : ( + value + ); + } + + return { + title: key, + description, + }; + }); + }; } export const Controls: FC<Props> = React.memo( @@ -87,6 +94,9 @@ export const Controls: FC<Props> = React.memo( const canCreateDataFrameAnalytics: boolean = usePermissionCheck('canCreateDataFrameAnalytics'); const canDeleteDataFrameAnalytics: boolean = usePermissionCheck('canDeleteDataFrameAnalytics'); const deleteAction = useDeleteAction(canDeleteDataFrameAnalytics); + const isServerless = useIsServerless(); + const getListItems = useMemo(() => getListItemsFactory(isServerless), [isServerless]); + const { closeDeleteJobCheckModal, deleteItem, diff --git a/x-pack/plugins/ml/public/application/datavisualizer/index_based/index_data_visualizer.tsx b/x-pack/plugins/ml/public/application/datavisualizer/index_based/index_data_visualizer.tsx index 10c7003e6e18a..3debbda8021c3 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/index_based/index_data_visualizer.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/index_based/index_data_visualizer.tsx @@ -15,7 +15,7 @@ import type { GetAdditionalLinksParams, } from '@kbn/data-visualizer-plugin/public'; import { useTimefilter } from '@kbn/ml-date-picker'; -import { useMlKibana, useMlLocator } from '../../contexts/kibana'; +import { useMlKibana, useMlLocator, useIsServerless } from '../../contexts/kibana'; import { HelpMenu } from '../../components/help_menu'; import { ML_PAGES } from '../../../../common/constants/locator'; import { isFullLicense } from '../../license'; @@ -37,6 +37,7 @@ export const IndexDataVisualizerPage: FC = () => { }, }, } = useMlKibana(); + const isServerless = useIsServerless(); const mlLocator = useMlLocator()!; const mlFeaturesDisabled = !isFullLicense(); getMlNodeCount(); @@ -188,7 +189,10 @@ export const IndexDataVisualizerPage: FC = () => { defaultMessage="Data Visualizer" /> </MlPageHeader> - <IndexDataVisualizer getAdditionalLinks={getAdditionalLinks} /> + <IndexDataVisualizer + getAdditionalLinks={getAdditionalLinks} + isServerless={isServerless} + /> </> ) : null} <HelpMenu docLink={docLinks.links.ml.guide} /> diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js index 75ada48dbdc4c..dcecda5575d87 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_list_view/jobs_list_view.js @@ -31,6 +31,7 @@ import { JobListMlAnomalyAlertFlyout } from '../../../../../alerting/ml_alerting import { StopDatafeedsConfirmModal } from '../confirm_modals/stop_datafeeds_confirm_modal'; import { CloseJobsConfirmModal } from '../confirm_modals/close_jobs_confirm_modal'; import { AnomalyDetectionEmptyState } from '../anomaly_detection_empty_state'; +import { removeNodeInfo } from '../../../../../../common/util/job_utils'; let blockingJobsRefreshTimeout = null; @@ -136,6 +137,9 @@ export class JobsListView extends Component { loadFullJob(jobId) .then((job) => { const fullJobsList = { ...this.state.fullJobsList }; + if (this.props.isServerless) { + job = removeNodeInfo(job); + } fullJobsList[jobId] = job; this.setState({ fullJobsList }, () => { // take a fresh copy of the itemIdToExpandedRowMap object @@ -314,6 +318,9 @@ export class JobsListView extends Component { const fullJobsList = {}; const jobsSummaryList = jobs.map((job) => { if (job.fullJob !== undefined) { + if (this.props.isServerless) { + job.fullJob = removeNodeInfo(job.fullJob); + } fullJobsList[job.id] = job.fullJob; delete job.fullJob; } @@ -408,7 +415,10 @@ export class JobsListView extends Component { <> <EuiFlexGroup justifyContent="spaceBetween"> <EuiFlexItem grow={false}> - <JobStatsBar jobsSummaryList={jobsSummaryList} /> + <JobStatsBar + jobsSummaryList={jobsSummaryList} + isServerless={this.props.isServerless} + /> </EuiFlexItem> <EuiFlexItem grow={false}> <NewJobButton /> diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_stats_bar/jobs_stats_bar.js b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_stats_bar/jobs_stats_bar.js index 8358c68e473ef..c8b2868267d80 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_stats_bar/jobs_stats_bar.js +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/components/jobs_stats_bar/jobs_stats_bar.js @@ -12,15 +12,21 @@ import PropTypes from 'prop-types'; import React from 'react'; import { i18n } from '@kbn/i18n'; -function createJobStats(jobsSummaryList) { +function createJobStats(jobsSummaryList, isServerless) { + const displayNodeInfo = isServerless === false; + const jobStats = { - activeNodes: { - label: i18n.translate('xpack.ml.jobsList.statsBar.activeMLNodesLabel', { - defaultMessage: 'Active ML nodes', - }), - value: 0, - show: true, - }, + ...(displayNodeInfo + ? { + activeNodes: { + label: i18n.translate('xpack.ml.jobsList.statsBar.activeMLNodesLabel', { + defaultMessage: 'Active ML nodes', + }), + value: 0, + show: true, + }, + } + : {}), total: { label: i18n.translate('xpack.ml.jobsList.statsBar.totalJobsLabel', { defaultMessage: 'Total jobs', @@ -94,17 +100,20 @@ function createJobStats(jobsSummaryList) { jobStats.failed.show = false; } - jobStats.activeNodes.value = Object.keys(mlNodes).length; + if (displayNodeInfo) { + jobStats.activeNodes.value = Object.keys(mlNodes).length; + } return jobStats; } -export const JobStatsBar = ({ jobsSummaryList }) => { - const jobStats = createJobStats(jobsSummaryList); +export const JobStatsBar = ({ jobsSummaryList, isServerless }) => { + const jobStats = createJobStats(jobsSummaryList, isServerless); return <StatsBar stats={jobStats} dataTestSub={'mlJobStatsBar'} />; }; JobStatsBar.propTypes = { jobsSummaryList: PropTypes.array.isRequired, + isServerless: PropTypes.bool.isRequired, }; diff --git a/x-pack/plugins/ml/public/application/jobs/jobs_list/jobs.tsx b/x-pack/plugins/ml/public/application/jobs/jobs_list/jobs.tsx index f93f1642b10f0..f413b97cb3602 100644 --- a/x-pack/plugins/ml/public/application/jobs/jobs_list/jobs.tsx +++ b/x-pack/plugins/ml/public/application/jobs/jobs_list/jobs.tsx @@ -12,7 +12,7 @@ import { JobsListView } from './components/jobs_list_view'; import { ML_PAGES } from '../../../../common/constants/locator'; import { ListingPageUrlState } from '../../../../common/types/common'; import { HelpMenu } from '../../components/help_menu'; -import { useMlKibana } from '../../contexts/kibana'; +import { useIsServerless, useMlKibana } from '../../contexts/kibana'; import { MlPageHeader } from '../../components/page_header'; import { HeaderMenuPortal } from '../../components/header_menu_portal'; import { JobsActionMenu } from '../components/jobs_action_menu'; @@ -42,6 +42,7 @@ export const JobsPage: FC<JobsPageProps> = ({ isMlEnabledInSpace, lastRefresh }) const { services: { docLinks }, } = useMlKibana(); + const isServerless = useIsServerless(); const helpLink = docLinks.links.ml.anomalyDetection; return ( <> @@ -56,6 +57,7 @@ export const JobsPage: FC<JobsPageProps> = ({ isMlEnabledInSpace, lastRefresh }) lastRefresh={lastRefresh} jobsViewState={pageState} onJobsViewStateUpdate={setPageState} + isServerless={isServerless} /> <HelpMenu docLink={helpLink} /> </> diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx index d93eb690c31d9..d9fa9e542c0c5 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/time_range_step/time_range.tsx @@ -22,7 +22,7 @@ import { EventRateChart } from '../charts/event_rate_chart'; import { LineChartPoint } from '../../../common/chart_loader'; import { JOB_TYPE } from '../../../../../../../common/constants/new_job'; import { TimeRangePicker, TimeRange } from '../../../common/components'; -import { useMlKibana } from '../../../../../contexts/kibana'; +import { useMlKibana, useIsServerless } from '../../../../../contexts/kibana'; import { ML_FROZEN_TIER_PREFERENCE, type MlStorageKey, @@ -33,6 +33,7 @@ export const TimeRangeStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) const timefilter = useTimefilter(); const { services } = useMlKibana(); const dataSourceContext = useDataSource(); + const isServerless = useIsServerless(); const { jobCreator, jobCreatorUpdate, jobCreatorUpdated, chartLoader, chartInterval } = useContext(JobCreatorContext); @@ -137,6 +138,7 @@ export const TimeRangeStep: FC<StepProps> = ({ setCurrentStep, isCurrentStep }) callback={fullTimeRangeCallback} timefilter={timefilter} apiPath={`${ML_INTERNAL_BASE_PATH}/fields_service/time_field_range`} + hideFrozenDataTierChoice={isServerless} /> </EuiFlexItem> <EuiFlexItem /> diff --git a/x-pack/plugins/ml/public/application/management/index.ts b/x-pack/plugins/ml/public/application/management/index.ts index f64d7cbb5bb64..dea3ba6cd8afa 100644 --- a/x-pack/plugins/ml/public/application/management/index.ts +++ b/x-pack/plugins/ml/public/application/management/index.ts @@ -16,7 +16,8 @@ import type { MlStartDependencies } from '../../plugin'; export function registerManagementSection( management: ManagementSetup, core: CoreSetup<MlStartDependencies>, - deps: { usageCollection?: UsageCollectionSetup } + deps: { usageCollection?: UsageCollectionSetup }, + isServerless: boolean ) { return management.sections.section.insightsAndAlerting.registerApp({ id: 'jobsListLink', @@ -26,7 +27,7 @@ export function registerManagementSection( order: 4, async mount(params: ManagementAppMountParams) { const { mountApp } = await import('./jobs_list'); - return mountApp(core, params, deps); + return mountApp(core, params, deps, isServerless); }, }); } diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx index 2ce2e9ddd9d56..2cf92278cfa63 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/jobs_list_page.tsx @@ -40,9 +40,7 @@ import { JobSpacesSyncFlyout } from '../../../../components/job_spaces_sync'; import { getMlGlobalServices } from '../../../../app'; import { ExportJobsFlyout, ImportJobsFlyout } from '../../../../components/import_export_jobs'; import type { MlSavedObjectType } from '../../../../../../common/types/saved_objects'; -import { mlApiServicesProvider } from '../../../../services/ml_api_service'; -import { HttpService } from '../../../../services/http_service'; import { SpaceManagement } from './space_management'; import { DocsLink } from './docs_link'; @@ -56,11 +54,17 @@ export const JobsListPage: FC<{ data: DataPublicPluginStart; usageCollection?: UsageCollectionSetup; fieldFormats: FieldFormatsStart; -}> = ({ coreStart, share, history, spacesApi, data, usageCollection, fieldFormats }) => { - const mlApiServices = useMemo( - () => mlApiServicesProvider(new HttpService(coreStart.http)), - [coreStart.http] - ); + isServerless: boolean; +}> = ({ + coreStart, + share, + history, + spacesApi, + data, + usageCollection, + fieldFormats, + isServerless, +}) => { const [initialized, setInitialized] = useState(false); const [accessDenied, setAccessDenied] = useState(false); const [isPlatinumOrTrialLicense, setIsPlatinumOrTrialLicense] = useState(true); @@ -70,13 +74,13 @@ export const JobsListPage: FC<{ const theme$ = coreStart.theme.theme$; const mlServices = useMemo( - () => getMlGlobalServices(coreStart.http, usageCollection), - [coreStart.http, usageCollection] + () => getMlGlobalServices(coreStart.http, isServerless, usageCollection), + [coreStart.http, isServerless, usageCollection] ); const check = async () => { try { - await checkGetManagementMlJobsResolver(mlApiServices); + await checkGetManagementMlJobsResolver(mlServices); } catch (e) { if (e.mlFeatureEnabledInSpace && e.isPlatinumOrTrialLicense === false) { setIsPlatinumOrTrialLicense(false); diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx index 2564f7c55da1e..bb21b971a8c12 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx +++ b/x-pack/plugins/ml/public/application/management/jobs_list/components/jobs_list_page/space_management/space_management.tsx @@ -21,6 +21,7 @@ import { import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import { useTableState } from '@kbn/ml-in-memory-table'; +import { usePermissionCheck } from '../../../../../capabilities/check_capabilities'; import type { JobType, MlSavedObjectType } from '../../../../../../../common/types/saved_objects'; import type { ManagementListResponse, @@ -38,12 +39,19 @@ interface Props { export const SpaceManagement: FC<Props> = ({ spacesApi, setCurrentTab }) => { const { getList } = useManagementApiService(); - const [currentTabId, setCurrentTabId] = useState<MlSavedObjectType>('anomaly-detector'); + + const [currentTabId, setCurrentTabId] = useState<MlSavedObjectType | null>(null); const [items, setItems] = useState<ManagementListResponse>(); const [columns, setColumns] = useState<Array<EuiBasicTableColumn<ManagementItems>>>([]); const [filters, setFilters] = useState<SearchFilterConfig[] | undefined>(); const [isLoading, setIsLoading] = useState(false); + const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ + 'isADEnabled', + 'isDFAEnabled', + 'isNLPEnabled', + ]); + const { onTableChange, pagination, sorting, setPageIndex } = useTableState<ManagementItems>( items ?? [], 'id' @@ -56,9 +64,26 @@ export const SpaceManagement: FC<Props> = ({ spacesApi, setCurrentTab }) => { }; }, []); + useEffect( + function setInitialSelectedTab() { + if (isADEnabled === true) { + setCurrentTabId('anomaly-detector'); + } else if (isDFAEnabled === true) { + setCurrentTabId('data-frame-analytics'); + } else if (isNLPEnabled === true) { + setCurrentTabId('trained-model'); + } + }, + [isADEnabled, isDFAEnabled, isNLPEnabled] + ); + const loadingTab = useRef<MlSavedObjectType | null>(null); const refresh = useCallback( - (tabId: MlSavedObjectType) => { + (tabId: MlSavedObjectType | null) => { + if (tabId === null) { + return; + } + loadingTab.current = tabId; setIsLoading(true); getList(tabId) @@ -83,16 +108,21 @@ export const SpaceManagement: FC<Props> = ({ spacesApi, setCurrentTab }) => { useEffect( function refreshOnTabChange() { setItems(undefined); - setColumns(createColumns()); - setCurrentTab(currentTabId); - refresh(currentTabId); - setPageIndex(0); + if (currentTabId !== null) { + setColumns(createColumns()); + setCurrentTab(currentTabId); + refresh(currentTabId); + setPageIndex(0); + } }, // eslint-disable-next-line react-hooks/exhaustive-deps [currentTabId] ); const createColumns = useCallback(() => { + if (currentTabId === null) { + return []; + } return [ ...getColumns(currentTabId), ...(spacesApi !== undefined @@ -165,35 +195,41 @@ export const SpaceManagement: FC<Props> = ({ spacesApi, setCurrentTab }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [items, columns, isLoading, filters, currentTabId, refresh, onTableChange]); - const tabs = useMemo( - () => [ - { + const tabs = useMemo(() => { + const tempTabs = []; + + if (isADEnabled === true) { + tempTabs.push({ 'data-test-subj': 'mlStackManagementAnomalyDetectionTab', id: 'anomaly-detector', name: i18n.translate('xpack.ml.management.list.anomalyDetectionTab', { defaultMessage: 'Anomaly detection', }), content: getTable(), - }, - { + }); + } + if (isDFAEnabled === true) { + tempTabs.push({ 'data-test-subj': 'mlStackManagementAnalyticsTab', id: 'data-frame-analytics', name: i18n.translate('xpack.ml.management.list.analyticsTab', { defaultMessage: 'Analytics', }), content: getTable(), - }, - { + }); + } + if (isNLPEnabled === true || isDFAEnabled === true) { + tempTabs.push({ 'data-test-subj': 'mlStackManagementTrainedModelsTab', id: 'trained-model', name: i18n.translate('xpack.ml.management.list.trainedModelsTab', { defaultMessage: 'Trained models', }), content: getTable(), - }, - ], - [getTable] - ); + }); + } + return tempTabs; + }, [getTable, isADEnabled, isDFAEnabled, isNLPEnabled]); return ( <EuiTabbedContent diff --git a/x-pack/plugins/ml/public/application/management/jobs_list/index.ts b/x-pack/plugins/ml/public/application/management/jobs_list/index.ts index df79a453a7f7f..2e512e2d708bf 100644 --- a/x-pack/plugins/ml/public/application/management/jobs_list/index.ts +++ b/x-pack/plugins/ml/public/application/management/jobs_list/index.ts @@ -25,6 +25,7 @@ const renderApp = ( share: SharePluginStart, data: DataPublicPluginStart, fieldFormats: FieldFormatsStart, + isServerless: boolean, spacesApi?: SpacesPluginStart, usageCollection?: UsageCollectionSetup ) => { @@ -37,6 +38,7 @@ const renderApp = ( spacesApi, usageCollection, fieldFormats, + isServerless, }), element ); @@ -48,7 +50,8 @@ const renderApp = ( export async function mountApp( core: CoreSetup<MlStartDependencies>, params: ManagementAppMountParams, - deps: { usageCollection?: UsageCollectionSetup } + deps: { usageCollection?: UsageCollectionSetup }, + isServerless: boolean ) { const [coreStart, pluginsStart] = await core.getStartServices(); @@ -60,6 +63,7 @@ export async function mountApp( pluginsStart.share, pluginsStart.data, pluginsStart.fieldFormats, + isServerless, pluginsStart.spaces, deps.usageCollection ); diff --git a/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx b/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx index a90c088b40e26..f134b2e5fbb83 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/memory_tree_map/tree_map.tsx @@ -29,6 +29,7 @@ import { useFieldFormatter, useMlKibana } from '../../contexts/kibana'; import { useRefresh } from '../../routing/use_refresh'; import { getMemoryItemColor } from '../memory_item_colors'; import { useToastNotificationService } from '../../services/toast_notification_service'; +import { usePermissionCheck } from '../../capabilities/check_capabilities'; interface Props { node?: string; @@ -58,13 +59,6 @@ const TYPE_LABELS_INVERTED = Object.entries(TYPE_LABELS).reduce<Record<MlSavedOb {} as Record<MlSavedObjectType, string> ); -const TYPE_OPTIONS: EuiComboBoxOptionOption[] = Object.entries(TYPE_LABELS).map( - ([label, type]) => ({ - label, - color: getMemoryItemColor(type), - }) -); - export const JobMemoryTreeMap: FC<Props> = ({ node, type, height }) => { const { services: { theme: themeService }, @@ -79,6 +73,12 @@ export const JobMemoryTreeMap: FC<Props> = ({ node, type, height }) => { [isDarkTheme] ); + const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ + 'isADEnabled', + 'isDFAEnabled', + 'isNLPEnabled', + ]); + const bytesFormatter = useFieldFormatter(FIELD_FORMAT_IDS.BYTES); const { displayErrorToast } = useToastNotificationService(); const refresh = useRefresh(); @@ -88,10 +88,40 @@ export const JobMemoryTreeMap: FC<Props> = ({ node, type, height }) => { const [allData, setAllData] = useState<MemoryUsageInfo[]>([]); const [data, setData] = useState<MemoryUsageInfo[]>([]); const [loading, setLoading] = useState(false); - const [selectedOptions, setSelectedOptions] = useState(TYPE_OPTIONS); + const [selectedOptions, setSelectedOptions] = useState<EuiComboBoxOptionOption[] | null>(null); + const typeOptions = useMemo(() => { + return Object.entries(TYPE_LABELS) + .filter(([, t]) => { + if ( + (t === 'anomaly-detector' && isADEnabled === false) || + (t === 'data-frame-analytics' && isDFAEnabled === false) || + (t === 'trained-model' && isNLPEnabled === false && isDFAEnabled === false) + ) { + return false; + } + + return true; + }) + .map(([label, t]) => ({ + label, + color: getMemoryItemColor(t), + })); + }, [isADEnabled, isDFAEnabled, isNLPEnabled]); + + useEffect( + function initSelectedOptions() { + if (selectedOptions === null) { + setSelectedOptions(typeOptions); + } + }, + [selectedOptions, typeOptions] + ); const filterData = useCallback( (dataIn: MemoryUsageInfo[]) => { + if (selectedOptions === null) { + return dataIn; + } const types = selectedOptions.map((o) => TYPE_LABELS[o.label]); return dataIn.filter((d) => types.includes(d.type)); }, @@ -137,8 +167,8 @@ export const JobMemoryTreeMap: FC<Props> = ({ node, type, height }) => { <LoadingWrapper height={chartHeight} hasData={data.length > 0} loading={loading}> <EuiComboBox fullWidth - options={TYPE_OPTIONS} - selectedOptions={selectedOptions} + options={typeOptions} + selectedOptions={selectedOptions ?? []} onChange={setSelectedOptions} isClearable={false} /> diff --git a/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx b/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx index fd0c2f4157a58..249d9c959809d 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx @@ -13,7 +13,7 @@ import { NodesList } from './nodes_overview'; import { MlPageHeader } from '../components/page_header'; import { MemoryPage, JobMemoryTreeMap } from './memory_tree_map'; import { SavedObjectsWarning } from '../components/saved_objects_warning'; -import { usePermissionCheck } from '../capabilities/check_capabilities'; +import { useIsServerless } from '../contexts/kibana'; enum TAB { NODES, @@ -23,11 +23,8 @@ enum TAB { export const MemoryUsagePage: FC = () => { const [selectedTab, setSelectedTab] = useState<TAB>(TAB.NODES); useTimefilter({ timeRangeSelector: false, autoRefreshSelector: true }); - const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ - 'isADEnabled', - 'isDFAEnabled', - 'isNLPEnabled', - ]); + + const isServerless = useIsServerless(); const refresh = useCallback(() => { mlTimefilterRefresh$.next({ @@ -50,7 +47,7 @@ export const MemoryUsagePage: FC = () => { <SavedObjectsWarning onCloseFlyout={refresh} /> - {isADEnabled && isDFAEnabled && isNLPEnabled ? ( + {isServerless === false ? ( <> <EuiTabs> <EuiTab diff --git a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx index c367f990b5321..c50b575f84c52 100644 --- a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx +++ b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx @@ -33,6 +33,7 @@ import { ModelPipelines } from './pipelines'; import { AllocatedModels } from '../memory_usage/nodes_overview/allocated_models'; import type { AllocatedModel, TrainedModelStat } from '../../../common/types/trained_models'; import { useFieldFormatter } from '../contexts/kibana/use_field_formatter'; +import { useIsServerless } from '../contexts/kibana'; interface ExpandedRowProps { item: ModelItemFull; @@ -113,6 +114,7 @@ export function useListItemsFormatter() { export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { const formatToListItems = useListItemsFormatter(); + const isServerless = useIsServerless(); const { inference_config: inferenceConfig, @@ -149,7 +151,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { estimated_operations, estimated_heap_memory_usage_bytes, default_field_map, - license_level, + ...(isServerless ? {} : { license_level }), }; }, [ default_field_map, @@ -159,6 +161,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { license_level, tags, version, + isServerless, ]); const deploymentStatItems: AllocatedModel[] = useMemo<AllocatedModel[]>(() => { @@ -196,6 +199,10 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { return items; }, [stats]); + const hideColumns = useMemo(() => { + return isServerless ? ['model_id', 'node_name'] : ['model_id']; + }, [isServerless]); + const tabs = useMemo<EuiTabbedContentTab[]>(() => { return [ { @@ -341,7 +348,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { </h5> </EuiTitle> <EuiSpacer size={'m'} /> - <AllocatedModels models={deploymentStatItems} hideColumns={['model_id']} /> + <AllocatedModels models={deploymentStatItems} hideColumns={hideColumns} /> </EuiPanel> <EuiSpacer size={'s'} /> </> @@ -455,6 +462,7 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { restMetaData, stats, item.model_id, + hideColumns, ]); const initialSelectedTab = diff --git a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx index 2dc8e3f3ff5d5..80eb6e91843f8 100644 --- a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx +++ b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx @@ -534,7 +534,9 @@ export function useModelActions({ isPrimary: true, available: isTestable, onClick: (item) => onTestAction(item), - enabled: (item) => canTestTrainedModels && isTestable(item, true) && !isLoading, + enabled: (item) => { + return canTestTrainedModels && isTestable(item, true) && !isLoading; + }, }, ], [ diff --git a/x-pack/plugins/ml/public/application/model_management/models_list.tsx b/x-pack/plugins/ml/public/application/model_management/models_list.tsx index c90142da28eeb..5ddcc2096b914 100644 --- a/x-pack/plugins/ml/public/application/model_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/model_management/models_list.tsx @@ -63,6 +63,7 @@ import { useRefresh } from '../routing/use_refresh'; import { SavedObjectsWarning } from '../components/saved_objects_warning'; import { TestTrainedModelFlyout } from './test_models'; import { AddInferencePipelineFlyout } from '../components/ml_inference'; +import { usePermissionCheck } from '../capabilities/check_capabilities'; type Stats = Omit<TrainedModelStat, 'model_id' | 'deployment_stats'>; @@ -104,6 +105,8 @@ export const ModelsList: FC<Props> = ({ }, } = useMlKibana(); + const [isNLPEnabled] = usePermissionCheck(['isNLPEnabled']); + useTimefilter({ timeRangeSelector: false, autoRefreshSelector: true }); const dateFormatter = useFieldFormatter(FIELD_FORMAT_IDS.DATE); @@ -582,6 +585,11 @@ export const ModelsList: FC<Props> = ({ }; const resultItems = useMemo<ModelItem[]>(() => { + if (isNLPEnabled === false) { + // don't add any of the built in models (e.g. elser) if NLP is disabled + return items; + } + const idSet = new Set(items.map((i) => i.model_id)); const notDownloaded: ModelItem[] = Object.entries(ELASTIC_MODEL_DEFINITIONS) .filter(([modelId]) => !idSet.has(modelId)) @@ -594,8 +602,10 @@ export const ModelsList: FC<Props> = ({ description: modelDefinition.description, } as ModelItem; }); - return [...items, ...notDownloaded]; - }, [items]); + const result = [...items, ...notDownloaded]; + + return result; + }, [isNLPEnabled, items]); if (!isInitialized) return null; diff --git a/x-pack/plugins/ml/public/application/notifications/components/notifications_list.test.tsx b/x-pack/plugins/ml/public/application/notifications/components/notifications_list.test.tsx index f9f7478be6e3e..91e6650a544f7 100644 --- a/x-pack/plugins/ml/public/application/notifications/components/notifications_list.test.tsx +++ b/x-pack/plugins/ml/public/application/notifications/components/notifications_list.test.tsx @@ -17,6 +17,7 @@ jest.mock('../../services/toast_notification_service'); jest.mock('../../contexts/ml/ml_notifications_context'); jest.mock('../../contexts/kibana/use_field_formatter'); jest.mock('../../components/saved_objects_warning'); +jest.mock('../../capabilities/check_capabilities'); const getMockedTimefilter = () => { // eslint-disable-next-line @typescript-eslint/no-var-requires diff --git a/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx b/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx index 4c04333b71e61..5edd19f4d8119 100644 --- a/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx +++ b/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx @@ -40,6 +40,7 @@ import type { NotificationItem, } from '../../../../common/types/notifications'; import { useMlKibana } from '../../contexts/kibana'; +import { usePermissionCheck } from '../../capabilities/check_capabilities'; const levelBadgeMap: Record<MlNotificationMessageLevel, IconColor> = { [ML_NOTIFICATIONS_MESSAGE_LEVEL.ERROR]: 'danger', @@ -65,6 +66,13 @@ export const NotificationsList: FC = () => { mlServices: { mlApiServices }, }, } = useMlKibana(); + + const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ + 'isADEnabled', + 'isDFAEnabled', + 'isNLPEnabled', + ]); + const { displayErrorToast } = useToastNotificationService(); const { lastCheckedAt, setLastCheckedAt, notificationsCounts, latestRequestedAt } = @@ -221,6 +229,39 @@ export const NotificationsList: FC = () => { }, [dateFormatter]); const filters: SearchFilterConfig[] = useMemo<SearchFilterConfig[]>(() => { + const jobTypeOptions = []; + if (isADEnabled === true) { + jobTypeOptions.push({ + value: 'anomaly_detector', + name: i18n.translate('xpack.ml.notifications.filters.type.anomalyDetector', { + defaultMessage: 'Anomaly Detection', + }), + }); + } + if (isDFAEnabled === true) { + jobTypeOptions.push({ + value: 'data_frame_analytics', + name: i18n.translate('xpack.ml.notifications.filters.type.dfa', { + defaultMessage: 'Data Frame Analytics', + }), + }); + } + if (isNLPEnabled === true || isDFAEnabled === true) { + jobTypeOptions.push({ + value: 'inference', + name: i18n.translate('xpack.ml.notifications.filters.type.inference', { + defaultMessage: 'Inference', + }), + }); + } + + jobTypeOptions.push({ + value: 'system', + name: i18n.translate('xpack.ml.notifications.filters.type.system', { + defaultMessage: 'System', + }), + }); + return [ { type: 'field_value_selection', @@ -260,39 +301,14 @@ export const NotificationsList: FC = () => { defaultMessage: 'Type', }), multiSelect: 'or', - options: [ - { - value: 'anomaly_detector', - name: i18n.translate('xpack.ml.notifications.filters.type.anomalyDetector', { - defaultMessage: 'Anomaly Detection', - }), - }, - { - value: 'data_frame_analytics', - name: i18n.translate('xpack.ml.notifications.filters.type.dfa', { - defaultMessage: 'Data Frame Analytics', - }), - }, - { - value: 'inference', - name: i18n.translate('xpack.ml.notifications.filters.type.inference', { - defaultMessage: 'Inference', - }), - }, - { - value: 'system', - name: i18n.translate('xpack.ml.notifications.filters.type.system', { - defaultMessage: 'System', - }), - }, - ], + options: jobTypeOptions, }, { type: 'custom_component', component: EntityFilter, }, ]; - }, []); + }, [isADEnabled, isDFAEnabled, isNLPEnabled]); const newNotificationsCount = Object.values(notificationsCounts).reduce((a, b) => a + b); diff --git a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx index 30aa0f6d22dfb..9707515deb800 100644 --- a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx @@ -19,7 +19,7 @@ import { import { ML_PAGES } from '../../../../../common/constants/locator'; import { OverviewStatsBar } from '../../../components/collapsible_panel/collapsible_panel'; import { CollapsiblePanel } from '../../../components/collapsible_panel'; -import { useMlKibana, useMlLink } from '../../../contexts/kibana'; +import { useMlKibana, useMlLink, useIsServerless } from '../../../contexts/kibana'; import { AnomalyDetectionTable } from './table'; import { ml } from '../../../services/ml_api_service'; import { getGroupsFromJobs, getStatsBarData } from './utils'; @@ -57,6 +57,7 @@ export const AnomalyDetectionPanel: FC<Props> = ({ anomalyTimelineService, setLa } = useMlKibana(); const { displayErrorToast } = useToastNotificationService(); + const isServerless = useIsServerless(); const refresh = useRefresh(); @@ -91,7 +92,7 @@ export const AnomalyDetectionPanel: FC<Props> = ({ anomalyTimelineService, setLa return job; }); const { groups: jobsGroups, count } = getGroupsFromJobs(jobsSummaryList); - const stats = getStatsBarData(jobsSummaryList); + const stats = getStatsBarData(jobsSummaryList, isServerless); const statGroups = groupBy( Object.entries(stats) diff --git a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/utils.ts b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/utils.ts index a5a864e139eae..3e46b258c3a05 100644 --- a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/utils.ts +++ b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/utils.ts @@ -74,7 +74,7 @@ export function getGroupsFromJobs(jobs: MlSummaryJobs): { return { groups, count }; } -export function getStatsBarData(jobsList: any) { +export function getStatsBarData(jobsList: MlSummaryJob[] | undefined, isServerless: boolean) { const jobStats = { total: { label: i18n.translate('xpack.ml.overviewJobsList.statsBar.totalJobsLabel', { @@ -108,14 +108,18 @@ export function getStatsBarData(jobsList: any) { show: false, group: 0, }, - activeNodes: { - label: i18n.translate('xpack.ml.overviewJobsList.statsBar.activeMLNodesLabel', { - defaultMessage: 'Active ML nodes', - }), - value: 0, - show: true, - group: 1, - }, + ...(isServerless + ? {} + : { + activeNodes: { + label: i18n.translate('xpack.ml.overviewJobsList.statsBar.activeMLNodesLabel', { + defaultMessage: 'Active ML nodes', + }), + value: 0, + show: true, + group: 1, + }, + }), activeDatafeeds: { label: i18n.translate('xpack.ml.jobsList.statsBar.activeDatafeedsLabel', { defaultMessage: 'Active datafeeds', @@ -162,7 +166,9 @@ export function getStatsBarData(jobsList: any) { jobStats.failed.show = false; } - jobStats.activeNodes.value = Object.keys(mlNodes).length; + if (isServerless === false) { + jobStats.activeNodes!.value = Object.keys(mlNodes).length; + } if (jobStats.total.value === 0) { for (const [statKey, val] of Object.entries(jobStats)) { diff --git a/x-pack/plugins/ml/public/application/routing/routes/memory_usage.tsx b/x-pack/plugins/ml/public/application/routing/routes/memory_usage.tsx index 9f78410615586..dce72c080e94f 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/memory_usage.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/memory_usage.tsx @@ -38,7 +38,12 @@ export const nodesListRouteFactory = ( const PageWrapper: FC = () => { const { context } = useRouteResolver( 'full', - ['canGetJobs', 'canGetDataFrameAnalytics', 'canGetTrainedModels'], + // only enabled in non-serverless mode + // if a serverless project ever contains all three features + // this check will have to be changed to an + // explicit isServerless check which will probably + // require a change in useRouteResolver + ['isADEnabled', 'isDFAEnabled', 'isNLPEnabled'], basicResolvers() ); diff --git a/x-pack/plugins/ml/public/application/services/job_service.js b/x-pack/plugins/ml/public/application/services/job_service.js index e2b183a7855a2..5f2be59156762 100644 --- a/x-pack/plugins/ml/public/application/services/job_service.js +++ b/x-pack/plugins/ml/public/application/services/job_service.js @@ -8,7 +8,6 @@ import { cloneDeep, each, find, get, isNumber } from 'lodash'; import moment from 'moment'; -import { i18n } from '@kbn/i18n'; import { validateTimeRange, TIME_FORMAT } from '@kbn/ml-date-utils'; import { parseInterval } from '../../../common/util/parse_interval'; @@ -47,50 +46,6 @@ class JobService { this.jobDescriptions = {}; this.detectorsByJob = {}; this.customUrlsByJob = {}; - this.jobStats = { - activeNodes: { - label: i18n.translate('xpack.ml.jobService.activeMLNodesLabel', { - defaultMessage: 'Active ML nodes', - }), - value: 0, - show: true, - }, - total: { - label: i18n.translate('xpack.ml.jobService.totalJobsLabel', { - defaultMessage: 'Total jobs', - }), - value: 0, - show: true, - }, - open: { - label: i18n.translate('xpack.ml.jobService.openJobsLabel', { - defaultMessage: 'Open jobs', - }), - value: 0, - show: true, - }, - closed: { - label: i18n.translate('xpack.ml.jobService.closedJobsLabel', { - defaultMessage: 'Closed jobs', - }), - value: 0, - show: true, - }, - failed: { - label: i18n.translate('xpack.ml.jobService.failedJobsLabel', { - defaultMessage: 'Failed jobs', - }), - value: 0, - show: false, - }, - activeDatafeeds: { - label: i18n.translate('xpack.ml.jobService.activeDatafeedsLabel', { - defaultMessage: 'Active datafeeds', - }), - value: 0, - show: true, - }, - }; } loadJobs() { diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.test.ts b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.test.ts index dd7408287cbf4..4e1771c25d0ef 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.test.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.test.ts @@ -27,7 +27,7 @@ describe('AnomalyChartsEmbeddableFactory', () => { const [coreStart, pluginsStart] = await getStartServices(); // act - const factory = new AnomalyChartsEmbeddableFactory(getStartServices); + const factory = new AnomalyChartsEmbeddableFactory(getStartServices, false); await factory.create({ jobIds: ['test-job'], diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.ts b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.ts index e502d03bcd964..a6056e84a87be 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.ts @@ -35,7 +35,8 @@ export class AnomalyChartsEmbeddableFactory ]; constructor( - private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart> + private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart>, + private isServerless: boolean ) {} public async isEditable() { @@ -61,7 +62,7 @@ export class AnomalyChartsEmbeddableFactory const { resolveEmbeddableAnomalyChartsUserInput } = await import( './anomaly_charts_setup_flyout' ); - return await resolveEmbeddableAnomalyChartsUserInput(coreStart); + return await resolveEmbeddableAnomalyChartsUserInput(coreStart, this.isServerless); } catch (e) { return Promise.reject(); } diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx index 92aea068c5b15..13849c8e6064c 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_setup_flyout.tsx @@ -19,6 +19,7 @@ import { mlApiServicesProvider } from '../../application/services/ml_api_service export async function resolveEmbeddableAnomalyChartsUserInput( coreStart: CoreStart, + isServerless: boolean, input?: AnomalyChartsEmbeddableInput ): Promise<Partial<AnomalyChartsEmbeddableInput>> { const { http, overlays, theme, i18n } = coreStart; @@ -27,7 +28,7 @@ export async function resolveEmbeddableAnomalyChartsUserInput( return new Promise(async (resolve, reject) => { try { - const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds); + const { jobIds } = await resolveJobSelection(coreStart, isServerless, input?.jobIds); const title = input?.title ?? getDefaultExplorerChartsPanelTitle(jobIds); const { jobs } = await getJobs({ jobId: jobIds.join(',') }); const influencers = extractInfluencers(jobs); diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx index cb759f6783b46..2b75202095e3f 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx @@ -27,7 +27,7 @@ describe('AnomalySwimlaneEmbeddableFactory', () => { const [coreStart, pluginsStart] = await getStartServices(); // act - const factory = new AnomalySwimlaneEmbeddableFactory(getStartServices); + const factory = new AnomalySwimlaneEmbeddableFactory(getStartServices, false); await factory.create({ jobIds: ['test-job'], diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.ts b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.ts index 3e7f958ea778e..421d12193e56f 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.ts +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.ts @@ -35,7 +35,8 @@ export class AnomalySwimlaneEmbeddableFactory ]; constructor( - private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart> + private getStartServices: StartServicesAccessor<MlStartDependencies, MlPluginStart>, + private isServerless: boolean ) {} public async isEditable() { @@ -59,7 +60,7 @@ export class AnomalySwimlaneEmbeddableFactory try { const { resolveAnomalySwimlaneUserInput } = await import('./anomaly_swimlane_setup_flyout'); - return await resolveAnomalySwimlaneUserInput(coreStart); + return await resolveAnomalySwimlaneUserInput(coreStart, this.isServerless); } catch (e) { return Promise.reject(); } diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx index dc2ca931cc805..2c0e6c5e2d963 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout.tsx @@ -19,6 +19,7 @@ import { mlApiServicesProvider } from '../../application/services/ml_api_service export async function resolveAnomalySwimlaneUserInput( coreStart: CoreStart, + isServerless: boolean, input?: AnomalySwimlaneEmbeddableInput ): Promise<Partial<AnomalySwimlaneEmbeddableInput>> { const { http, overlays, theme, i18n } = coreStart; @@ -27,7 +28,7 @@ export async function resolveAnomalySwimlaneUserInput( return new Promise(async (resolve, reject) => { try { - const { jobIds } = await resolveJobSelection(coreStart, input?.jobIds); + const { jobIds } = await resolveJobSelection(coreStart, isServerless, input?.jobIds); const title = input?.title ?? getDefaultSwimlanePanelTitle(jobIds); const { jobs } = await getJobs({ jobId: jobIds.join(',') }); const influencers = extractInfluencers(jobs); diff --git a/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx b/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx index 00c4a02d4e929..3cd49afd8c361 100644 --- a/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx +++ b/x-pack/plugins/ml/public/embeddables/common/resolve_job_selection.tsx @@ -26,6 +26,7 @@ import { JobSelectorFlyout } from './components/job_selector_flyout'; */ export async function resolveJobSelection( coreStart: CoreStart, + isServerless: boolean, selectedJobIds?: JobId[] ): Promise<{ jobIds: string[]; groups: Array<{ groupId: string; jobIds: string[] }> }> { const { @@ -69,7 +70,9 @@ export async function resolveJobSelection( const flyoutSession = coreStart.overlays.openFlyout( toMountPoint( - <KibanaContextProvider services={{ ...coreStart, mlServices: getMlGlobalServices(http) }}> + <KibanaContextProvider + services={{ ...coreStart, mlServices: getMlGlobalServices(http, isServerless) }} + > <JobSelectorFlyout selectedIds={selectedJobIds} withTimeRangeSelector={false} diff --git a/x-pack/plugins/ml/public/embeddables/index.ts b/x-pack/plugins/ml/public/embeddables/index.ts index 0a505fe04ea85..e480a17997751 100644 --- a/x-pack/plugins/ml/public/embeddables/index.ts +++ b/x-pack/plugins/ml/public/embeddables/index.ts @@ -15,16 +15,24 @@ export * from './types'; export { getEmbeddableComponent } from './get_embeddable_component'; -export function registerEmbeddables(embeddable: EmbeddableSetup, core: MlCoreSetup) { +export function registerEmbeddables( + embeddable: EmbeddableSetup, + core: MlCoreSetup, + isServerless: boolean +) { const anomalySwimlaneEmbeddableFactory = new AnomalySwimlaneEmbeddableFactory( - core.getStartServices + core.getStartServices, + isServerless ); embeddable.registerEmbeddableFactory( anomalySwimlaneEmbeddableFactory.type, anomalySwimlaneEmbeddableFactory ); - const anomalyChartsFactory = new AnomalyChartsEmbeddableFactory(core.getStartServices); + const anomalyChartsFactory = new AnomalyChartsEmbeddableFactory( + core.getStartServices, + isServerless + ); embeddable.registerEmbeddableFactory(anomalyChartsFactory.type, anomalyChartsFactory); } diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx index 7fd5f9e86fca8..1cbf56427ec3c 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/common/create_flyout.tsx @@ -27,6 +27,7 @@ export function createFlyout( share: SharePluginStart, data: DataPublicPluginStart, dashboardService: DashboardStart, + isServerless: boolean, lens?: LensPublicStart ): Promise<void> { const { @@ -53,7 +54,7 @@ export function createFlyout( data, lens, dashboardService, - mlServices: getMlGlobalServices(http), + mlServices: getMlGlobalServices(http, isServerless), }} > <FlyoutComponent diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx index 91e6f6f001861..0d563c453edbf 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/lens/show_flyout.tsx @@ -20,7 +20,8 @@ export async function showLensVisToADJobFlyout( share: SharePluginStart, data: DataPublicPluginStart, lens: LensPublicStart, - dashboardService: DashboardStart + dashboardService: DashboardStart, + isServerless: boolean ): Promise<void> { return createFlyout( LensLayerSelectionFlyout, @@ -29,6 +30,7 @@ export async function showLensVisToADJobFlyout( share, data, dashboardService, + isServerless, lens ); } diff --git a/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx b/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx index 5380513f1dc97..da2d8bb2e0d4c 100644 --- a/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx +++ b/x-pack/plugins/ml/public/embeddables/job_creation/map/show_flyout.tsx @@ -19,7 +19,16 @@ export async function showMapVisToADJobFlyout( coreStart: CoreStart, share: SharePluginStart, data: DataPublicPluginStart, - dashboardService: DashboardStart + dashboardService: DashboardStart, + isServerless: boolean ): Promise<void> { - return createFlyout(GeoJobFlyout, embeddable, coreStart, share, data, dashboardService); + return createFlyout( + GeoJobFlyout, + embeddable, + coreStart, + share, + data, + dashboardService, + isServerless + ); } diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index c66d4c6ec8d33..3a32f8b25ae89 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -51,9 +51,9 @@ import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/ import { registerManagementSection } from './application/management'; import { MlLocatorDefinition, type MlLocator } from './locator'; import { setDependencyCache } from './application/util/dependency_cache'; -import { registerFeature } from './register_feature'; +import { registerHomeFeature } from './register_home_feature'; import { isFullLicense, isMlEnabled } from '../common/license'; -import { PLUGIN_ICON_SOLUTION, PLUGIN_ID } from '../common/constants/app'; +import { ML_APP_ROUTE, PLUGIN_ICON_SOLUTION, PLUGIN_ID } from '../common/constants/app'; import type { MlCapabilities } from './shared'; export interface MlStartDependencies { @@ -103,8 +103,11 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> { private appUpdater$ = new BehaviorSubject<AppUpdater>(() => ({})); private locator: undefined | MlLocator; + private isServerless: boolean = false; - constructor(private initializerContext: PluginInitializerContext) {} + constructor(private initializerContext: PluginInitializerContext) { + this.isServerless = initializerContext.env.packageInfo.buildFlavor === 'serverless'; + } setup(core: MlCoreSetup, pluginsSetup: MlSetupDependencies) { core.application.register({ @@ -114,12 +117,11 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> { }), order: 5000, euiIconType: PLUGIN_ICON_SOLUTION, - appRoute: '/app/ml', + appRoute: ML_APP_ROUTE, category: DEFAULT_APP_CATEGORIES.kibana, updater$: this.appUpdater$, mount: async (params: AppMountParameters) => { const [coreStart, pluginsStart] = await core.getStartServices(); - const kibanaVersion = this.initializerContext.env.packageInfo.version; const { renderApp } = await import('./application/app'); return renderApp( coreStart, @@ -137,7 +139,7 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> { embeddable: { ...pluginsSetup.embeddable, ...pluginsStart.embeddable }, maps: pluginsStart.maps, uiActions: pluginsStart.uiActions, - kibanaVersion, + kibanaVersion: this.initializerContext.env.packageInfo.version, triggersActionsUi: pluginsStart.triggersActionsUi, dataVisualizer: pluginsStart.dataVisualizer, usageCollection: pluginsSetup.usageCollection, @@ -149,7 +151,8 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> { contentManagement: pluginsStart.contentManagement, presentationUtil: pluginsStart.presentationUtil, }, - params + params, + this.isServerless ); }, }); @@ -159,9 +162,14 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> { } if (pluginsSetup.management) { - registerManagementSection(pluginsSetup.management, core, { - usageCollection: pluginsSetup.usageCollection, - }).enable(); + registerManagementSection( + pluginsSetup.management, + core, + { + usageCollection: pluginsSetup.usageCollection, + }, + this.isServerless + ).enable(); } const licensing = pluginsSetup.licensing.license$.pipe(take(1)); @@ -170,53 +178,58 @@ export class MlPlugin implements Plugin<MlPluginSetup, MlPluginStart> { const fullLicense = isFullLicense(license); const [coreStart, pluginStart] = await core.getStartServices(); const { capabilities } = coreStart.application; + const mlCapabilities = capabilities.ml as MlCapabilities; + // register various ML plugin features which require a full license + // note including registerHomeFeature in register_helper would cause the page bundle size to increase significantly if (mlEnabled) { // add ML to home page if (pluginsSetup.home) { - registerFeature(pluginsSetup.home); + registerHomeFeature(pluginsSetup.home); } - } else { - // if ml is disabled in elasticsearch, disable ML in kibana - this.appUpdater$.next(() => ({ - status: AppStatus.inaccessible, - })); - } - - // register various ML plugin features which require a full license - // note including registerFeature in register_helper would cause the page bundle size to increase significantly - const { - registerEmbeddables, - registerMlUiActions, - registerSearchLinks, - registerMlAlerts, - registerMapExtension, - registerCasesAttachments, - } = await import('./register_helper'); - - if (pluginsSetup.maps) { - // Pass capabilites.ml.canGetJobs as minimum permission to show anomalies card in maps layers - const canGetJobs = capabilities.ml?.canGetJobs === true; - const canCreateJobs = capabilities.ml?.canCreateJob === true; - await registerMapExtension(pluginsSetup.maps, core, { canGetJobs, canCreateJobs }); - } - if (mlEnabled) { - registerSearchLinks(this.appUpdater$, fullLicense, capabilities.ml as MlCapabilities); + const { + registerEmbeddables, + registerMlUiActions, + registerSearchLinks, + registerMlAlerts, + registerMapExtension, + registerCasesAttachments, + } = await import('./register_helper'); + registerSearchLinks(this.appUpdater$, fullLicense, mlCapabilities, this.isServerless); if (fullLicense) { - registerEmbeddables(pluginsSetup.embeddable, core); - registerMlUiActions(pluginsSetup.uiActions, core); + registerMlUiActions(pluginsSetup.uiActions, core, this.isServerless); - if (pluginsSetup.cases) { - registerCasesAttachments(pluginsSetup.cases, coreStart, pluginStart); - } + if (mlCapabilities.isADEnabled) { + registerEmbeddables(pluginsSetup.embeddable, core, this.isServerless); + + if (pluginsSetup.cases) { + registerCasesAttachments(pluginsSetup.cases, coreStart, pluginStart); + } + + if ( + pluginsSetup.triggersActionsUi && + mlCapabilities.canUseMlAlerts && + mlCapabilities.canGetJobs + ) { + registerMlAlerts(pluginsSetup.triggersActionsUi, pluginsSetup.alerting); + } - const canUseMlAlerts = capabilities.ml?.canUseMlAlerts; - if (pluginsSetup.triggersActionsUi && canUseMlAlerts) { - registerMlAlerts(pluginsSetup.triggersActionsUi, pluginsSetup.alerting); + if (pluginsSetup.maps) { + // Pass canGetJobs as minimum permission to show anomalies card in maps layers + await registerMapExtension(pluginsSetup.maps, core, { + canGetJobs: mlCapabilities.canGetJobs, + canCreateJobs: mlCapabilities.canCreateJob, + }); + } } } + } else { + // if ml is disabled in elasticsearch, disable ML in kibana + this.appUpdater$.next(() => ({ + status: AppStatus.inaccessible, + })); } }); diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts index 35c37c56ecdff..6b7f10103b440 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts @@ -15,7 +15,8 @@ import type { MlCapabilities } from '../../shared'; export function registerSearchLinks( appUpdater: BehaviorSubject<AppUpdater>, isFullLicense: boolean, - mlCapabilities: MlCapabilities + mlCapabilities: MlCapabilities, + isServerless: boolean ) { appUpdater.next(() => ({ keywords: [ @@ -23,6 +24,6 @@ export function registerSearchLinks( defaultMessage: 'ML', }), ], - deepLinks: getDeepLinks(isFullLicense, mlCapabilities), + deepLinks: getDeepLinks(isFullLicense, mlCapabilities, isServerless), })); } diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index dfe2b4bbaf200..f9bdd2b50e4a4 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -12,276 +12,275 @@ import { type AppDeepLink, AppNavLinkStatus } from '@kbn/core/public'; import { ML_PAGES } from '../../../common/constants/locator'; import type { MlCapabilities } from '../../shared'; -function getNavStatus( +function createDeepLinks( mlCapabilities: MlCapabilities, - statusIfServerless: boolean -): AppNavLinkStatus | undefined { - if (mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled) { - // if all features are enabled we can assume that we are not running in serverless mode. - // returning default will not add the link to the nav menu, but the link will be registered for searching - return AppNavLinkStatus.default; - } - - return statusIfServerless ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden; -} + isFullLicense: boolean, + isServerless: boolean +) { + function getNavStatus( + visible: boolean, + showInServerless: boolean = true + ): AppNavLinkStatus | undefined { + if (isServerless) { + // in serverless the status needs to be "visible" rather than "default" + // for the links to appear in the nav menu. + return showInServerless && visible ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden; + } -function getOverviewLinkDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - return { - id: 'overview', - title: i18n.translate('xpack.ml.deepLink.overview', { - defaultMessage: 'Overview', - }), - path: `/${ML_PAGES.OVERVIEW}`, - navLinkStatus: getNavStatus(mlCapabilities, false), - }; -} + return visible ? AppNavLinkStatus.default : AppNavLinkStatus.hidden; + } -function getAnomalyDetectionDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isADEnabled); return { - id: 'anomalyDetection', - title: i18n.translate('xpack.ml.deepLink.anomalyDetection', { - defaultMessage: 'Anomaly Detection', - }), - path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, - navLinkStatus, - deepLinks: [ - { - id: 'anomalyExplorer', - title: i18n.translate('xpack.ml.deepLink.anomalyExplorer', { - defaultMessage: 'Anomaly explorer', - }), - path: `/${ML_PAGES.ANOMALY_EXPLORER}`, - navLinkStatus, - }, - { - id: 'singleMetricViewer', - title: i18n.translate('xpack.ml.deepLink.singleMetricViewer', { - defaultMessage: 'Single metric viewer', + getOverviewLinkDeepLink: (): AppDeepLink<LinkId> => { + const navLinkStatus = getNavStatus(mlCapabilities.isADEnabled || mlCapabilities.isDFAEnabled); + return { + id: 'overview', + title: i18n.translate('xpack.ml.deepLink.overview', { + defaultMessage: 'Overview', }), - path: `/${ML_PAGES.SINGLE_METRIC_VIEWER}`, + path: `/${ML_PAGES.OVERVIEW}`, navLinkStatus, - }, - ], - }; -} + }; + }, -function getDataFrameAnalyticsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isDFAEnabled); - return { - id: 'dataFrameAnalytics', - title: i18n.translate('xpack.ml.deepLink.dataFrameAnalytics', { - defaultMessage: 'Data Frame Analytics', - }), - path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, - navLinkStatus, - deepLinks: [ - { - id: 'resultExplorer', - title: i18n.translate('xpack.ml.deepLink.resultExplorer', { - defaultMessage: 'Results explorer', + getAnomalyDetectionDeepLink: (): AppDeepLink<LinkId> => { + const navLinkStatus = getNavStatus(mlCapabilities.isADEnabled); + return { + id: 'anomalyDetection', + title: i18n.translate('xpack.ml.deepLink.anomalyDetection', { + defaultMessage: 'Anomaly Detection', }), - path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_EXPLORATION}`, + path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, navLinkStatus, - }, - { - id: 'analyticsMap', - title: i18n.translate('xpack.ml.deepLink.analyticsMap', { - defaultMessage: 'Analytics map', + deepLinks: [ + { + id: 'anomalyExplorer', + title: i18n.translate('xpack.ml.deepLink.anomalyExplorer', { + defaultMessage: 'Anomaly explorer', + }), + path: `/${ML_PAGES.ANOMALY_EXPLORER}`, + navLinkStatus, + }, + { + id: 'singleMetricViewer', + title: i18n.translate('xpack.ml.deepLink.singleMetricViewer', { + defaultMessage: 'Single metric viewer', + }), + path: `/${ML_PAGES.SINGLE_METRIC_VIEWER}`, + navLinkStatus, + }, + ], + }; + }, + + getDataFrameAnalyticsDeepLink: (): AppDeepLink<LinkId> => { + const navLinkStatus = getNavStatus(mlCapabilities.isDFAEnabled); + return { + id: 'dataFrameAnalytics', + title: i18n.translate('xpack.ml.deepLink.dataFrameAnalytics', { + defaultMessage: 'Data Frame Analytics', }), - path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MAP}`, + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, navLinkStatus, - }, - ], - }; -} + deepLinks: [ + { + id: 'resultExplorer', + title: i18n.translate('xpack.ml.deepLink.resultExplorer', { + defaultMessage: 'Results explorer', + }), + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_EXPLORATION}`, + navLinkStatus, + }, + { + id: 'analyticsMap', + title: i18n.translate('xpack.ml.deepLink.analyticsMap', { + defaultMessage: 'Analytics map', + }), + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MAP}`, + navLinkStatus, + }, + ], + }; + }, -function getAiopsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.canUseAiops); - return { - id: 'aiOps', - title: i18n.translate('xpack.ml.deepLink.aiOps', { - defaultMessage: 'AIOps', - }), - // Default to the index select page for log rate analysis since we don't have an AIops overview page - path: `/${ML_PAGES.AIOPS_LOG_RATE_ANALYSIS_INDEX_SELECT}`, - navLinkStatus, - deepLinks: [ - { - id: 'logRateAnalysis', - title: i18n.translate('xpack.ml.deepLink.logRateAnalysis', { - defaultMessage: 'Log Rate Analysis', + getModelManagementDeepLink: (): AppDeepLink<LinkId> => { + const navLinkStatus = getNavStatus( + mlCapabilities.isDFAEnabled || mlCapabilities.isNLPEnabled + ); + return { + id: 'modelManagement', + title: i18n.translate('xpack.ml.deepLink.modelManagement', { + defaultMessage: 'Model Management', }), - path: `/${ML_PAGES.AIOPS_LOG_RATE_ANALYSIS_INDEX_SELECT}`, + path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, navLinkStatus, - }, - { - id: 'logPatternAnalysis', - title: i18n.translate('xpack.ml.deepLink.logPatternAnalysis', { - defaultMessage: 'Log Pattern Analysis', + deepLinks: [ + { + id: 'nodesOverview', + title: i18n.translate('xpack.ml.deepLink.trainedModels', { + defaultMessage: 'Trained Models', + }), + path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, + navLinkStatus, + }, + { + id: 'nodes', + title: i18n.translate('xpack.ml.deepLink.nodes', { + defaultMessage: 'Nodes', + }), + path: `/${ML_PAGES.NODES}`, + navLinkStatus: getNavStatus( + mlCapabilities.isDFAEnabled || mlCapabilities.isNLPEnabled, + false + ), + }, + ], + }; + }, + + getMemoryUsageDeepLink: (): AppDeepLink<LinkId> => { + return { + id: 'memoryUsage', + title: i18n.translate('xpack.ml.deepLink.memoryUsage', { + defaultMessage: 'Memory Usage', }), - path: `/${ML_PAGES.AIOPS_LOG_CATEGORIZATION_INDEX_SELECT}`, - navLinkStatus, - }, - { - id: 'changePointDetections', - title: i18n.translate('xpack.ml.deepLink.changePointDetection', { - defaultMessage: 'Change Point Detection', + path: `/${ML_PAGES.MEMORY_USAGE}`, + navLinkStatus: getNavStatus(isFullLicense, false), + }; + }, + + getSettingsDeepLink: (): AppDeepLink<LinkId> => { + const navLinkStatus = getNavStatus(mlCapabilities.isADEnabled); + return { + id: 'settings', + title: i18n.translate('xpack.ml.deepLink.settings', { + defaultMessage: 'Settings', }), - path: `/${ML_PAGES.AIOPS_CHANGE_POINT_DETECTION_INDEX_SELECT}`, + path: `/${ML_PAGES.SETTINGS}`, navLinkStatus, - }, - ], - }; -} + deepLinks: [ + { + id: 'calendarSettings', + title: i18n.translate('xpack.ml.deepLink.calendarSettings', { + defaultMessage: 'Calendars', + }), + path: `/${ML_PAGES.CALENDARS_MANAGE}`, + navLinkStatus, + }, + { + id: 'filterListsSettings', + title: i18n.translate('xpack.ml.deepLink.filterListsSettings', { + defaultMessage: 'Filter Lists', + }), + path: `/${ML_PAGES.SETTINGS}`, // Link to settings page as read only users cannot view filter lists. + navLinkStatus, + }, + ], + }; + }, -function getModelManagementDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isNLPEnabled); - return { - id: 'modelManagement', - title: i18n.translate('xpack.ml.deepLink.modelManagement', { - defaultMessage: 'Model Management', - }), - path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, - navLinkStatus, - deepLinks: [ - { - id: 'nodesOverview', - title: i18n.translate('xpack.ml.deepLink.trainedModels', { - defaultMessage: 'Trained Models', + getAiopsDeepLink: (): AppDeepLink<LinkId> => { + const navLinkStatus = getNavStatus(mlCapabilities.canUseAiops); + return { + id: 'aiOps', + title: i18n.translate('xpack.ml.deepLink.aiOps', { + defaultMessage: 'AIOps', }), - path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, + // Default to the index select page for log rate analysis since we don't have an AIops overview page + path: `/${ML_PAGES.AIOPS_LOG_RATE_ANALYSIS_INDEX_SELECT}`, navLinkStatus, - }, - { - id: 'nodes', - title: i18n.translate('xpack.ml.deepLink.nodes', { - defaultMessage: 'Nodes', - }), - path: `/${ML_PAGES.NODES}`, - navLinkStatus: getNavStatus(mlCapabilities, false), - }, - ], - }; -} + deepLinks: [ + { + id: 'logRateAnalysis', + title: i18n.translate('xpack.ml.deepLink.logRateAnalysis', { + defaultMessage: 'Log Rate Analysis', + }), + path: `/${ML_PAGES.AIOPS_LOG_RATE_ANALYSIS_INDEX_SELECT}`, + navLinkStatus, + }, + { + id: 'logPatternAnalysis', + title: i18n.translate('xpack.ml.deepLink.logPatternAnalysis', { + defaultMessage: 'Log Pattern Analysis', + }), + path: `/${ML_PAGES.AIOPS_LOG_CATEGORIZATION_INDEX_SELECT}`, + navLinkStatus, + }, + { + id: 'changePointDetections', + title: i18n.translate('xpack.ml.deepLink.changePointDetection', { + defaultMessage: 'Change Point Detection', + }), + path: `/${ML_PAGES.AIOPS_CHANGE_POINT_DETECTION_INDEX_SELECT}`, + navLinkStatus, + }, + ], + }; + }, -function getMemoryUsageDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - return { - id: 'memoryUsage', - title: i18n.translate('xpack.ml.deepLink.memoryUsage', { - defaultMessage: 'Memory Usage', - }), - path: `/${ML_PAGES.MEMORY_USAGE}`, - navLinkStatus: getNavStatus(mlCapabilities, false), - }; -} - -function getDataVisualizerDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - return { - id: 'dataVisualizer', - title: i18n.translate('xpack.ml.deepLink.dataVisualizer', { - defaultMessage: 'Data Visualizer', - }), - path: `/${ML_PAGES.DATA_VISUALIZER}`, - navLinkStatus: getNavStatus(mlCapabilities, false), - }; -} - -function getFileUploadDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - return { - id: 'fileUpload', - title: i18n.translate('xpack.ml.deepLink.fileUpload', { - defaultMessage: 'File Upload', - }), - keywords: ['CSV', 'JSON'], - path: `/${ML_PAGES.DATA_VISUALIZER_FILE}`, - navLinkStatus: getNavStatus(mlCapabilities, false), - }; -} - -function getIndexDataVisualizerDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - return { - id: 'indexDataVisualizer', - title: i18n.translate('xpack.ml.deepLink.indexDataVisualizer', { - defaultMessage: 'Index Data Visualizer', - }), - path: `/${ML_PAGES.DATA_VISUALIZER_INDEX_SELECT}`, - navLinkStatus: getNavStatus(mlCapabilities, false), - }; -} + getNotificationsDeepLink: (): AppDeepLink<LinkId> => { + return { + id: 'notifications', + title: i18n.translate('xpack.ml.deepLink.notifications', { + defaultMessage: 'Notifications', + }), + path: `/${ML_PAGES.NOTIFICATIONS}`, + navLinkStatus: getNavStatus(isFullLicense), + }; + }, -function getDataComparisonDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - return { - id: 'dataComparison', - title: i18n.translate('xpack.ml.deepLink.dataComparison', { - defaultMessage: 'Data Comparison', - }), - path: `/${ML_PAGES.DATA_COMPARISON_INDEX_SELECT}`, - navLinkStatus: getNavStatus(mlCapabilities, false), - }; -} + getDataVisualizerDeepLink: (): AppDeepLink<LinkId> => { + return { + id: 'dataVisualizer', + title: i18n.translate('xpack.ml.deepLink.dataVisualizer', { + defaultMessage: 'Data Visualizer', + }), + path: `/${ML_PAGES.DATA_VISUALIZER}`, + navLinkStatus: getNavStatus(true), + }; + }, -function getSettingsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isADEnabled); - return { - id: 'settings', - title: i18n.translate('xpack.ml.deepLink.settings', { - defaultMessage: 'Settings', - }), - path: `/${ML_PAGES.SETTINGS}`, - navLinkStatus, - deepLinks: [ - { - id: 'calendarSettings', - title: i18n.translate('xpack.ml.deepLink.calendarSettings', { - defaultMessage: 'Calendars', + getFileUploadDeepLink: (): AppDeepLink<LinkId> => { + return { + id: 'fileUpload', + title: i18n.translate('xpack.ml.deepLink.fileUpload', { + defaultMessage: 'File Upload', }), - path: `/${ML_PAGES.CALENDARS_MANAGE}`, - navLinkStatus, - }, - { - id: 'filterListsSettings', - title: i18n.translate('xpack.ml.deepLink.filterListsSettings', { - defaultMessage: 'Filter Lists', + keywords: ['CSV', 'JSON'], + path: `/${ML_PAGES.DATA_VISUALIZER_FILE}`, + navLinkStatus: getNavStatus(true), + }; + }, + + getIndexDataVisualizerDeepLink: (): AppDeepLink<LinkId> => { + return { + id: 'indexDataVisualizer', + title: i18n.translate('xpack.ml.deepLink.indexDataVisualizer', { + defaultMessage: 'Index Data Visualizer', }), - path: `/${ML_PAGES.SETTINGS}`, // Link to settings page as read only users cannot view filter lists. - navLinkStatus, - }, - ], - }; -} + path: `/${ML_PAGES.DATA_VISUALIZER_INDEX_SELECT}`, + navLinkStatus: getNavStatus(true), + }; + }, -function getNotificationsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink<LinkId> { - return { - id: 'notifications', - title: i18n.translate('xpack.ml.deepLink.notifications', { - defaultMessage: 'Notifications', - }), - path: `/${ML_PAGES.NOTIFICATIONS}`, - navLinkStatus: getNavStatus(mlCapabilities, true), + getDataComparisonDeepLink: (): AppDeepLink<LinkId> => { + return { + id: 'dataComparison', + title: i18n.translate('xpack.ml.deepLink.dataComparison', { + defaultMessage: 'Data Comparison', + }), + path: `/${ML_PAGES.DATA_COMPARISON_INDEX_SELECT}`, + navLinkStatus: getNavStatus(true), + }; + }, }; } -export function getDeepLinks(isFullLicense: boolean, mlCapabilities: MlCapabilities) { - const deepLinks: Array<AppDeepLink<LinkId>> = [ - getDataVisualizerDeepLink(mlCapabilities), - getFileUploadDeepLink(mlCapabilities), - getIndexDataVisualizerDeepLink(mlCapabilities), - getDataComparisonDeepLink(mlCapabilities), - ]; - - if (isFullLicense === true) { - deepLinks.push( - getOverviewLinkDeepLink(mlCapabilities), - getAnomalyDetectionDeepLink(mlCapabilities), - getDataFrameAnalyticsDeepLink(mlCapabilities), - getModelManagementDeepLink(mlCapabilities), - getMemoryUsageDeepLink(mlCapabilities), - getSettingsDeepLink(mlCapabilities), - getAiopsDeepLink(mlCapabilities), - getNotificationsDeepLink(mlCapabilities) - ); - } - - return deepLinks; +export function getDeepLinks( + isFullLicense: boolean, + mlCapabilities: MlCapabilities, + isServerless: boolean +) { + const links = createDeepLinks(mlCapabilities, isFullLicense, isServerless); + return Object.values(links).map((link) => link()); } diff --git a/x-pack/plugins/ml/public/register_feature.ts b/x-pack/plugins/ml/public/register_home_feature.ts similarity index 86% rename from x-pack/plugins/ml/public/register_feature.ts rename to x-pack/plugins/ml/public/register_home_feature.ts index bc0f6f751351e..baae66f72eea5 100644 --- a/x-pack/plugins/ml/public/register_feature.ts +++ b/x-pack/plugins/ml/public/register_home_feature.ts @@ -7,9 +7,9 @@ import { i18n } from '@kbn/i18n'; import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; -import { PLUGIN_ID } from '../common/constants/app'; +import { ML_APP_ROUTE, PLUGIN_ID } from '../common/constants/app'; -export const registerFeature = (home: HomePublicPluginSetup) => { +export const registerHomeFeature = (home: HomePublicPluginSetup) => { // register ML so it appears on the Kibana home page home.featureCatalogue.register({ id: PLUGIN_ID, @@ -24,7 +24,7 @@ export const registerFeature = (home: HomePublicPluginSetup) => { 'Automatically model the normal behavior of your time series data to detect anomalies.', }), icon: 'machineLearningApp', - path: '/app/ml', + path: ML_APP_ROUTE, showOnHomePage: false, category: 'data', solutionId: 'kibana', diff --git a/x-pack/plugins/ml/public/ui_actions/edit_anomaly_charts_panel_action.tsx b/x-pack/plugins/ml/public/ui_actions/edit_anomaly_charts_panel_action.tsx index d79c897958554..e4f765f87c598 100644 --- a/x-pack/plugins/ml/public/ui_actions/edit_anomaly_charts_panel_action.tsx +++ b/x-pack/plugins/ml/public/ui_actions/edit_anomaly_charts_panel_action.tsx @@ -17,7 +17,8 @@ import { export const EDIT_ANOMALY_CHARTS_PANEL_ACTION = 'editAnomalyChartsPanelAction'; export function createEditAnomalyChartsPanelAction( - getStartServices: MlCoreSetup['getStartServices'] + getStartServices: MlCoreSetup['getStartServices'], + isServerless: boolean ): UiActionsActionDefinition<EditAnomalyChartsPanelContext> { return { id: 'edit-anomaly-charts', @@ -43,6 +44,7 @@ export function createEditAnomalyChartsPanelAction( const result = await resolveEmbeddableAnomalyChartsUserInput( coreStart, + isServerless, embeddable.getInput() ); embeddable.updateInput(result); diff --git a/x-pack/plugins/ml/public/ui_actions/edit_swimlane_panel_action.tsx b/x-pack/plugins/ml/public/ui_actions/edit_swimlane_panel_action.tsx index 4352dc2df89bf..5070862023598 100644 --- a/x-pack/plugins/ml/public/ui_actions/edit_swimlane_panel_action.tsx +++ b/x-pack/plugins/ml/public/ui_actions/edit_swimlane_panel_action.tsx @@ -14,7 +14,8 @@ import { ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, EditSwimlanePanelContext } from '../e export const EDIT_SWIMLANE_PANEL_ACTION = 'editSwimlanePanelAction'; export function createEditSwimlanePanelAction( - getStartServices: MlCoreSetup['getStartServices'] + getStartServices: MlCoreSetup['getStartServices'], + isServerless: boolean ): UiActionsActionDefinition<EditSwimlanePanelContext> { return { id: 'edit-anomaly-swimlane', @@ -38,7 +39,11 @@ export function createEditSwimlanePanelAction( '../embeddables/anomaly_swimlane/anomaly_swimlane_setup_flyout' ); - const result = await resolveAnomalySwimlaneUserInput(coreStart, embeddable.getInput()); + const result = await resolveAnomalySwimlaneUserInput( + coreStart, + isServerless, + embeddable.getInput() + ); embeddable.updateInput(result); } catch (e) { return Promise.reject(); diff --git a/x-pack/plugins/ml/public/ui_actions/index.ts b/x-pack/plugins/ml/public/ui_actions/index.ts index 4067547e08956..f08f5bcd886bc 100644 --- a/x-pack/plugins/ml/public/ui_actions/index.ts +++ b/x-pack/plugins/ml/public/ui_actions/index.ts @@ -34,17 +34,24 @@ export { SWIM_LANE_SELECTION_TRIGGER }; */ export function registerMlUiActions( uiActions: UiActionsSetup, - core: CoreSetup<MlStartDependencies, MlPluginStart> + core: CoreSetup<MlStartDependencies, MlPluginStart>, + isServerless: boolean ) { // Initialize actions - const editSwimlanePanelAction = createEditSwimlanePanelAction(core.getStartServices); + const editSwimlanePanelAction = createEditSwimlanePanelAction( + core.getStartServices, + isServerless + ); const openInExplorerAction = createOpenInExplorerAction(core.getStartServices); const applyInfluencerFiltersAction = createApplyInfluencerFiltersAction(core.getStartServices); const applyEntityFieldFilterAction = createApplyEntityFieldFiltersAction(core.getStartServices); const applyTimeRangeSelectionAction = createApplyTimeRangeSelectionAction(core.getStartServices); const clearSelectionAction = createClearSelectionAction(core.getStartServices); - const editExplorerPanelAction = createEditAnomalyChartsPanelAction(core.getStartServices); - const visToAdJobAction = createVisToADJobAction(core.getStartServices); + const editExplorerPanelAction = createEditAnomalyChartsPanelAction( + core.getStartServices, + isServerless + ); + const visToAdJobAction = createVisToADJobAction(core.getStartServices, isServerless); // Register actions uiActions.registerAction(editSwimlanePanelAction); diff --git a/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx b/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx index fb0aa38e44d90..3e06b6175d61e 100644 --- a/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx +++ b/x-pack/plugins/ml/public/ui_actions/open_vis_in_ml_action.tsx @@ -15,7 +15,8 @@ import { isLensEmbeddable, isMapEmbeddable } from '../application/jobs/new_job/j export const CREATE_LENS_VIS_TO_ML_AD_JOB_ACTION = 'createMLADJobAction'; export function createVisToADJobAction( - getStartServices: MlCoreSetup['getStartServices'] + getStartServices: MlCoreSetup['getStartServices'], + isServerless: boolean ): UiActionsActionDefinition<{ embeddable: Embeddable | MapEmbeddable }> { return { id: 'create-ml-ad-job-action', @@ -39,11 +40,26 @@ export function createVisToADJobAction( if (lens === undefined) { return; } - await showLensVisToADJobFlyout(embeddable, coreStart, share, data, lens, dashboard); + await showLensVisToADJobFlyout( + embeddable, + coreStart, + share, + data, + lens, + dashboard, + isServerless + ); } else if (isMapEmbeddable(embeddable)) { const [{ showMapVisToADJobFlyout }, [coreStart, { share, data, dashboard }]] = await Promise.all([import('../embeddables/job_creation/map'), getStartServices()]); - await showMapVisToADJobFlyout(embeddable, coreStart, share, data, dashboard); + await showMapVisToADJobFlyout( + embeddable, + coreStart, + share, + data, + dashboard, + isServerless + ); } } catch (e) { return Promise.reject(); diff --git a/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts b/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts index ab1136b5d1edc..1095280ebdae9 100644 --- a/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts +++ b/x-pack/plugins/ml/server/lib/alerts/register_ml_alerts.ts @@ -19,7 +19,7 @@ export interface RegisterAlertParams { mlServicesProviders: MlServicesProviders; } -export function registerMlAlerts(params: RegisterAlertParams) { - registerAnomalyDetectionAlertType(params); - registerJobsMonitoringRuleType(params); +export function registerMlAlerts(alertParams: RegisterAlertParams) { + registerAnomalyDetectionAlertType(alertParams); + registerJobsMonitoringRuleType(alertParams); } diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts index 2be5bd877552a..dadb15b8a46b8 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts @@ -59,7 +59,7 @@ function getSwitcher( basicLicenseMlCapabilities.forEach((c) => (mlCaps[c] = originalCapabilities[c])); } - return { ml: applyEnabledFeatures(mlCaps, enabledFeatures) }; + return { ml: mlCaps }; } catch (e) { logger.debug(`Error updating capabilities for ML based on licensing: ${e}`); return {}; @@ -67,22 +67,26 @@ function getSwitcher( }; } -function applyEnabledFeatures(mlCaps: MlCapabilities, enabledFeatures: MlFeatures) { - mlCaps.isADEnabled = enabledFeatures.ad; - mlCaps.isDFAEnabled = enabledFeatures.dfa; - mlCaps.isNLPEnabled = enabledFeatures.nlp; +function applyEnabledFeatures(mlCaps: MlCapabilities, { ad, dfa, nlp }: MlFeatures) { + mlCaps.isADEnabled = ad; + mlCaps.isDFAEnabled = dfa; + mlCaps.isNLPEnabled = nlp; + mlCaps.canViewMlNodes = mlCaps.canViewMlNodes && ad && dfa && nlp; - mlCaps.canViewMlNodes = - mlCaps.canViewMlNodes && mlCaps.isADEnabled && mlCaps.isDFAEnabled && mlCaps.isNLPEnabled; - - if (enabledFeatures.ad === false) { - featureCapabilities.ad.forEach((c) => (mlCaps[c] = false)); + if (ad === false) { + for (const c of featureCapabilities.ad) { + mlCaps[c] = false; + } } - if (enabledFeatures.dfa === false) { - featureCapabilities.dfa.forEach((c) => (mlCaps[c] = false)); + if (dfa === false) { + for (const c of featureCapabilities.dfa) { + mlCaps[c] = false; + } } - if (enabledFeatures.nlp === false) { - featureCapabilities.nlp.forEach((c) => (mlCaps[c] = false)); + if (nlp === false && dfa === false) { + for (const c of featureCapabilities.nlp) { + mlCaps[c] = false; + } } return mlCaps; diff --git a/x-pack/plugins/ml/server/lib/register_cases.ts b/x-pack/plugins/ml/server/lib/register_cases.ts new file mode 100644 index 0000000000000..f916176a4d3f4 --- /dev/null +++ b/x-pack/plugins/ml/server/lib/register_cases.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CasesSetup } from '@kbn/cases-plugin/server'; +import { + CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS, + CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE, +} from '../../common/constants/cases'; + +export function registerCasesPersistableState(cases: CasesSetup) { + cases.attachmentFramework.registerPersistableState({ + id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE, + }); + + cases.attachmentFramework.registerPersistableState({ + id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS, + }); +} diff --git a/x-pack/plugins/ml/server/lib/sample_data_sets/sample_data_sets.ts b/x-pack/plugins/ml/server/lib/register_sameple_data_set_links.ts similarity index 87% rename from x-pack/plugins/ml/server/lib/sample_data_sets/sample_data_sets.ts rename to x-pack/plugins/ml/server/lib/register_sameple_data_set_links.ts index 393490793004a..6e7a0946d0369 100644 --- a/x-pack/plugins/ml/server/lib/sample_data_sets/sample_data_sets.ts +++ b/x-pack/plugins/ml/server/lib/register_sameple_data_set_links.ts @@ -7,10 +7,13 @@ import { i18n } from '@kbn/i18n'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; -import { MlLicense } from '../../../common/license'; +import type { MlFeatures } from '../types'; -export function initSampleDataSets(mlLicense: MlLicense, home: HomeServerPluginSetup) { - if (mlLicense.isMlEnabled() && mlLicense.isFullLicense()) { +export function registerSampleDataSetLinks( + enabledFeatures: MlFeatures, + home: HomeServerPluginSetup +) { + if (enabledFeatures.ad === true) { const sampleDataLinkLabel = i18n.translate('xpack.ml.sampleDataLinkLabel', { defaultMessage: 'ML jobs', }); diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts index 05c2764297d2d..4f1796782a6ae 100644 --- a/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/analytics_manager.ts @@ -7,7 +7,7 @@ import Boom from '@hapi/boom'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { IScopedClusterClient } from '@kbn/core/server'; +import type { IScopedClusterClient } from '@kbn/core/server'; import { getAnalysisType, INDEX_CREATED_BY, @@ -23,20 +23,21 @@ import { flatten } from 'lodash'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { modelsProvider } from '../model_management'; import { - ExtendAnalyticsMapArgs, - GetAnalyticsMapArgs, - InitialElementsReturnType, + type ExtendAnalyticsMapArgs, + type GetAnalyticsMapArgs, + type InitialElementsReturnType, + type NextLinkReturnType, + type GetAnalyticsJobIdArg, + type GetAnalyticsModelIdArg, isCompleteInitialReturnType, isAnalyticsMapEdgeElement, isAnalyticsMapNodeElement, isIndexPatternLinkReturnType, isJobDataLinkReturnType, isTransformLinkReturnType, - NextLinkReturnType, - GetAnalyticsJobIdArg, - GetAnalyticsModelIdArg, } from './types'; import type { MlClient } from '../../lib/ml_client'; +import type { MlFeatures } from '../../types'; import { DEFAULT_TRAINED_MODELS_PAGE_SIZE } from '../../routes/trained_models'; export class AnalyticsManager { @@ -44,12 +45,20 @@ export class AnalyticsManager { private _jobs: estypes.MlDataframeAnalyticsSummary[] = []; private _transforms?: TransformGetTransformTransformSummary[]; - constructor(private _mlClient: MlClient, private _client: IScopedClusterClient) {} + constructor( + private readonly _mlClient: MlClient, + private readonly _client: IScopedClusterClient, + private readonly _enabledFeatures: MlFeatures + ) {} private async initData() { const [models, jobs] = await Promise.all([ - this._mlClient.getTrainedModels({ size: DEFAULT_TRAINED_MODELS_PAGE_SIZE }), - this._mlClient.getDataFrameAnalytics({ size: 1000 }), + this._enabledFeatures.nlp || this._enabledFeatures.dfa + ? this._mlClient.getTrainedModels({ size: DEFAULT_TRAINED_MODELS_PAGE_SIZE }) + : { trained_model_configs: [] }, + this._enabledFeatures.dfa + ? this._mlClient.getDataFrameAnalytics({ size: 1000 }) + : { data_frame_analytics: [] }, ]); this._trainedModels = models.trained_model_configs; this._jobs = jobs.data_frame_analytics; diff --git a/x-pack/plugins/ml/server/models/model_management/memory_usage.test.ts b/x-pack/plugins/ml/server/models/model_management/memory_usage.test.ts index 3f85487a4cbf3..31857da674d52 100644 --- a/x-pack/plugins/ml/server/models/model_management/memory_usage.test.ts +++ b/x-pack/plugins/ml/server/models/model_management/memory_usage.test.ts @@ -133,10 +133,16 @@ describe('Model service', () => { }), } as unknown as jest.Mocked<MlClient>; + const mlFeatures = { + ad: true, + dfa: true, + nlp: true, + }; + let service: MemoryUsageService; beforeEach(() => { - service = new MemoryUsageService(mlClient); + service = new MemoryUsageService(mlClient, mlFeatures); }); afterEach(() => {}); diff --git a/x-pack/plugins/ml/server/models/model_management/memory_usage.ts b/x-pack/plugins/ml/server/models/model_management/memory_usage.ts index 541b396b0a6e5..cd665c387302f 100644 --- a/x-pack/plugins/ml/server/models/model_management/memory_usage.ts +++ b/x-pack/plugins/ml/server/models/model_management/memory_usage.ts @@ -22,6 +22,7 @@ import type { NodeDeploymentStatsResponse, NodesOverviewResponse, } from '../../../common/types/trained_models'; +import type { MlFeatures } from '../../types'; // @ts-expect-error numeral missing value const AD_EXTRA_MEMORY = numeral('10MB').value(); @@ -33,7 +34,7 @@ const NODE_FIELDS = ['attributes', 'name', 'roles'] as const; export type RequiredNodeFields = Pick<estypes.NodesInfoNodeInfo, typeof NODE_FIELDS[number]>; export class MemoryUsageService { - constructor(private readonly mlClient: MlClient) {} + constructor(private readonly mlClient: MlClient, private readonly mlFeatures: MlFeatures) {} public async getMemorySizes(itemType?: MlSavedObjectType, node?: string, showClosedJobs = false) { let memories: MemoryUsageInfo[] = []; @@ -60,11 +61,19 @@ export class MemoryUsageService { } private async getADJobsSizes() { + if (this.mlFeatures.ad === false) { + return []; + } + const jobs = await this.mlClient.getJobStats(); return jobs.jobs.map(this.getADJobMemorySize); } private async getTrainedModelsSizes() { + if (this.mlFeatures.nlp === false) { + return []; + } + const [models, stats] = await Promise.all([ this.mlClient.getTrainedModels(), this.mlClient.getTrainedModelsStats(), @@ -83,6 +92,10 @@ export class MemoryUsageService { } private async getDFAJobsSizes() { + if (this.mlFeatures.dfa === false) { + return []; + } + const [jobs, jobsStats] = await Promise.all([ this.mlClient.getDataFrameAnalytics(), this.mlClient.getDataFrameAnalyticsStats(), diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index b3f829faf170b..0a0d3dfcaf7ee 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -29,10 +29,7 @@ import { notificationsRoutes } from './routes/notifications'; import type { MlFeatures, PluginsSetup, PluginsStart, RouteInitialization } from './types'; import { PLUGIN_ID } from '../common/constants/app'; import type { MlCapabilities } from '../common/types/capabilities'; - import { initMlServerLog } from './lib/log'; -import { initSampleDataSets } from './lib/sample_data_sets'; - import { annotationRoutes } from './routes/annotations'; import { calendars } from './routes/calendars'; import { dataFeedRoutes } from './routes/datafeeds'; @@ -68,10 +65,8 @@ import { ML_ALERT_TYPES } from '../common/constants/alerts'; import { alertingRoutes } from './routes/alerting'; import { registerCollector } from './usage'; import { SavedObjectsSyncService } from './saved_objects/sync_task'; -import { - CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE, - CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS, -} from '../common/constants/cases'; +import { registerCasesPersistableState } from './lib/register_cases'; +import { registerSampleDataSetLinks } from './lib/register_sameple_data_set_links'; type SetFeaturesEnabled = (features: MlFeatures) => void; @@ -104,12 +99,16 @@ export class MlServerPlugin dfa: true, nlp: true, }; + private isServerless: boolean = false; + private registerCases: () => void = () => {}; + private registerSampleDatasetsIntegration: () => void = () => {}; constructor(ctx: PluginInitializerContext) { this.log = ctx.logger.get(); this.mlLicense = new MlLicense(); this.isMlReady = new Promise((resolve) => (this.setMlReady = resolve)); this.savedObjectsSyncService = new SavedObjectsSyncService(this.log); + this.isServerless = ctx.env.packageInfo.buildFlavor === 'serverless'; } public setup(coreSetup: CoreSetup<PluginsStart>, plugins: PluginsSetup): MlPluginSetup { @@ -157,8 +156,6 @@ export class MlServerPlugin }, }); - registerKibanaSettings(coreSetup); - // initialize capabilities switcher to add license filter to ml capabilities setupCapabilitiesSwitcher( coreSetup, @@ -224,7 +221,8 @@ export class MlServerPlugin coreSetup.getStartServices ), mlLicense: this.mlLicense, - enabledFeatures: this.enabledFeatures, + getEnabledFeatures: () => Object.assign({}, this.enabledFeatures), + isServerless: this.isServerless, }; annotationRoutes(routeInit, plugins.security); @@ -268,6 +266,21 @@ export class MlServerPlugin }); } + this.registerCases = () => { + if (plugins.cases) { + registerCasesPersistableState(plugins.cases); + } + }; + + this.registerSampleDatasetsIntegration = () => { + // called in start once enabledFeatures is available + if (this.home) { + registerSampleDataSetLinks(this.enabledFeatures, this.home); + } + }; + + registerKibanaSettings(coreSetup); + if (plugins.usageCollection) { const getIndexForType = (type: string) => coreSetup @@ -276,16 +289,6 @@ export class MlServerPlugin registerCollector(plugins.usageCollection, getIndexForType); } - if (plugins.cases) { - plugins.cases.attachmentFramework.registerPersistableState({ - id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_SWIMLANE, - }); - - plugins.cases.attachmentFramework.registerPersistableState({ - id: CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS, - }); - } - const setFeaturesEnabled = (features: MlFeatures) => { if (features.ad !== undefined) { this.enabledFeatures.ad = features.ad; @@ -319,10 +322,10 @@ export class MlServerPlugin return; } - if (this.home) { - initSampleDataSets(mlLicense, this.home); + if (mlLicense.isMlEnabled() && mlLicense.isFullLicense()) { + this.registerCases(); + this.registerSampleDatasetsIntegration(); } - // check whether the job saved objects exist // and create them if needed. const { initializeJobs } = jobSavedObjectsInitializationFactory( diff --git a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts index 56e4e4ee4f625..fb5eca48d8fa1 100644 --- a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts @@ -15,7 +15,7 @@ import { import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app'; import { wrapError } from '../client/error_wrapper'; import { analyticsAuditMessagesProvider } from '../models/data_frame_analytics/analytics_audit_messages'; -import type { RouteInitialization } from '../types'; +import type { MlFeatures, RouteInitialization } from '../types'; import { dataAnalyticsJobConfigSchema, dataAnalyticsJobUpdateSchema, @@ -51,9 +51,10 @@ function deleteDestDataViewById(dataViewsService: DataViewsService, dataViewId: function getExtendedMap( mlClient: MlClient, client: IScopedClusterClient, - idOptions: ExtendAnalyticsMapArgs + idOptions: ExtendAnalyticsMapArgs, + enabledFeatures: MlFeatures ) { - const analytics = new AnalyticsManager(mlClient, client); + const analytics = new AnalyticsManager(mlClient, client, enabledFeatures); return analytics.extendAnalyticsMapForAnalyticsJob(idOptions); } @@ -63,17 +64,13 @@ function getExtendedModelsMap( idOptions: { analyticsId?: string; modelId?: string; - } + }, + enabledFeatures: MlFeatures ) { - const analytics = new AnalyticsManager(mlClient, client); + const analytics = new AnalyticsManager(mlClient, client, enabledFeatures); return analytics.extendModelsMap(idOptions); } -export function getAnalyticsManager(mlClient: MlClient, client: IScopedClusterClient) { - const analytics = new AnalyticsManager(mlClient, client); - return analytics; -} - // replace the recursive field and agg references with a // map of ids to allow it to be stringified for transportation // over the network. @@ -95,7 +92,12 @@ function convertForStringify(aggs: Aggregation[], fields: Field[]): void { /** * Routes for the data frame analytics */ -export function dataFrameAnalyticsRoutes({ router, mlLicense, routeGuard }: RouteInitialization) { +export function dataFrameAnalyticsRoutes({ + router, + mlLicense, + routeGuard, + getEnabledFeatures, +}: RouteInitialization) { async function userCanDeleteIndex( client: IScopedClusterClient, destinationIndex: string @@ -795,16 +797,26 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense, routeGuard }: Rout let results; if (treatAsRoot === 'true' || treatAsRoot === true) { - // @ts-expect-error never used as analyticsId - results = await getExtendedMap(mlClient, client, { - analyticsId: type !== JOB_MAP_NODE_TYPES.INDEX ? analyticsId : undefined, - index: type === JOB_MAP_NODE_TYPES.INDEX ? analyticsId : undefined, - }); + results = await getExtendedMap( + mlClient, + client, + // @ts-expect-error never used as analyticsId + { + analyticsId: type !== JOB_MAP_NODE_TYPES.INDEX ? analyticsId : undefined, + index: type === JOB_MAP_NODE_TYPES.INDEX ? analyticsId : undefined, + }, + getEnabledFeatures() + ); } else { - results = await getExtendedModelsMap(mlClient, client, { - analyticsId: type !== JOB_MAP_NODE_TYPES.TRAINED_MODEL ? analyticsId : undefined, - modelId: type === JOB_MAP_NODE_TYPES.TRAINED_MODEL ? analyticsId : undefined, - }); + results = await getExtendedModelsMap( + mlClient, + client, + { + analyticsId: type !== JOB_MAP_NODE_TYPES.TRAINED_MODEL ? analyticsId : undefined, + modelId: type === JOB_MAP_NODE_TYPES.TRAINED_MODEL ? analyticsId : undefined, + }, + getEnabledFeatures() + ); } return response.ok({ diff --git a/x-pack/plugins/ml/server/routes/management.ts b/x-pack/plugins/ml/server/routes/management.ts index 9c68c8fcef261..7a74bac8d5128 100644 --- a/x-pack/plugins/ml/server/routes/management.ts +++ b/x-pack/plugins/ml/server/routes/management.ts @@ -19,11 +19,12 @@ import type { AnalyticsManagementItems, TrainedModelsManagementItems, } from '../../common/types/management'; +import { filterForEnabledFeatureModels } from './trained_models'; /** * Routes for management service */ -export function managementRoutes({ router, routeGuard }: RouteInitialization) { +export function managementRoutes({ router, routeGuard, getEnabledFeatures }: RouteInitialization) { /** * @apiGroup Management * @@ -126,12 +127,14 @@ export function managementRoutes({ router, routeGuard }: RouteInitialization) { trainedModelsSpaces(), ]); + const filteredModels = filterForEnabledFeatureModels(models, getEnabledFeatures()); + const modelStatsMapped = modelsStats.reduce((acc, cur) => { acc[cur.model_id] = cur; return acc; }, {} as Record<string, estypes.MlTrainedModelStats>); - const modelsWithSpaces: TrainedModelsManagementItems[] = models.map((m) => { + const modelsWithSpaces: TrainedModelsManagementItems[] = filteredModels.map((m) => { const id = m.model_id; return { id, diff --git a/x-pack/plugins/ml/server/routes/model_management.ts b/x-pack/plugins/ml/server/routes/model_management.ts index 853ee6582a7f7..31709dd4c32d0 100644 --- a/x-pack/plugins/ml/server/routes/model_management.ts +++ b/x-pack/plugins/ml/server/routes/model_management.ts @@ -20,7 +20,11 @@ import { wrapError } from '../client/error_wrapper'; import { MemoryUsageService } from '../models/model_management'; import { itemTypeLiterals } from './schemas/saved_objects'; -export function modelManagementRoutes({ router, routeGuard }: RouteInitialization) { +export function modelManagementRoutes({ + router, + routeGuard, + getEnabledFeatures, +}: RouteInitialization) { /** * @apiGroup ModelManagement * @@ -48,7 +52,7 @@ export function modelManagementRoutes({ router, routeGuard }: RouteInitializatio }, routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, response }) => { try { - const memoryUsageService = new MemoryUsageService(mlClient); + const memoryUsageService = new MemoryUsageService(mlClient, getEnabledFeatures()); const result = await memoryUsageService.getNodesOverview(); return response.ok({ body: result, @@ -95,7 +99,7 @@ export function modelManagementRoutes({ router, routeGuard }: RouteInitializatio routeGuard.fullLicenseAPIGuard(async ({ mlClient, response, request }) => { try { - const memoryUsageService = new MemoryUsageService(mlClient); + const memoryUsageService = new MemoryUsageService(mlClient, getEnabledFeatures()); return response.ok({ body: await memoryUsageService.getMemorySizes( request.query.type, diff --git a/x-pack/plugins/ml/server/routes/notifications.ts b/x-pack/plugins/ml/server/routes/notifications.ts index f9c64543dd042..c248399ff001a 100644 --- a/x-pack/plugins/ml/server/routes/notifications.ts +++ b/x-pack/plugins/ml/server/routes/notifications.ts @@ -14,7 +14,11 @@ import { import { wrapError } from '../client/error_wrapper'; import type { RouteInitialization } from '../types'; -export function notificationsRoutes({ router, routeGuard, enabledFeatures }: RouteInitialization) { +export function notificationsRoutes({ + router, + routeGuard, + getEnabledFeatures, +}: RouteInitialization) { /** * @apiGroup Notifications * @@ -49,7 +53,7 @@ export function notificationsRoutes({ router, routeGuard, enabledFeatures }: Rou const notificationsService = new NotificationsService( client, mlSavedObjectService, - enabledFeatures + getEnabledFeatures() ); const results = await notificationsService.searchMessages(request.query); @@ -98,7 +102,7 @@ export function notificationsRoutes({ router, routeGuard, enabledFeatures }: Rou const notificationsService = new NotificationsService( client, mlSavedObjectService, - enabledFeatures + getEnabledFeatures() ); const results = await notificationsService.countMessages(request.query); diff --git a/x-pack/plugins/ml/server/routes/trained_models.ts b/x-pack/plugins/ml/server/routes/trained_models.ts index 065b5878da9b2..ab5d3a87e8f46 100644 --- a/x-pack/plugins/ml/server/routes/trained_models.ts +++ b/x-pack/plugins/ml/server/routes/trained_models.ts @@ -5,11 +5,12 @@ * 2.0. */ +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { schema } from '@kbn/config-schema'; -import { ErrorType } from '@kbn/ml-error-utils'; -import { type MlGetTrainedModelsRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { ErrorType } from '@kbn/ml-error-utils'; +import type { MlGetTrainedModelsRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ML_INTERNAL_BASE_PATH } from '../../common/constants/app'; -import { RouteInitialization } from '../types'; +import type { MlFeatures, RouteInitialization } from '../types'; import { wrapError } from '../client/error_wrapper'; import { deleteTrainedModelQuerySchema, @@ -25,14 +26,34 @@ import { updateDeploymentParamsSchema, createIngestPipelineSchema, } from './schemas/inference_schema'; -import { TrainedModelConfigResponse } from '../../common/types/trained_models'; +import type { TrainedModelConfigResponse } from '../../common/types/trained_models'; import { mlLog } from '../lib/log'; import { forceQuerySchema } from './schemas/anomaly_detectors_schema'; import { modelsProvider } from '../models/model_management'; export const DEFAULT_TRAINED_MODELS_PAGE_SIZE = 10000; -export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) { +export function filterForEnabledFeatureModels( + models: TrainedModelConfigResponse[] | estypes.MlTrainedModelConfig[], + enabledFeatures: MlFeatures +) { + let filteredModels = models; + if (enabledFeatures.nlp === false) { + filteredModels = filteredModels.filter((m) => m.model_type === 'tree_ensemble'); + } + + if (enabledFeatures.dfa === false) { + filteredModels = filteredModels.filter((m) => m.model_type !== 'tree_ensemble'); + } + + return filteredModels; +} + +export function trainedModelsRoutes({ + router, + routeGuard, + getEnabledFeatures, +}: RouteInitialization) { /** * @apiGroup TrainedModels * @@ -62,14 +83,14 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) try { const { modelId } = request.params; const { with_pipelines: withPipelines, ...query } = request.query; - const body = await mlClient.getTrainedModels({ + const resp = await mlClient.getTrainedModels({ ...query, ...(modelId ? { model_id: modelId } : {}), size: DEFAULT_TRAINED_MODELS_PAGE_SIZE, } as MlGetTrainedModelsRequest); // model_type is missing // @ts-ignore - const result = body.trained_model_configs as TrainedModelConfigResponse[]; + const result = resp.trained_model_configs as TrainedModelConfigResponse[]; try { if (withPipelines) { // Also need to retrieve the list of deployment IDs from stats @@ -123,8 +144,10 @@ export function trainedModelsRoutes({ router, routeGuard }: RouteInitialization) mlLog.debug(e); } + const body = filterForEnabledFeatureModels(result, getEnabledFeatures()); + return response.ok({ - body: result, + body, }); } catch (e) { return response.customError(wrapError(e)); diff --git a/x-pack/plugins/ml/server/types.ts b/x-pack/plugins/ml/server/types.ts index 4bca1336ae0b9..4024e13420e7c 100644 --- a/x-pack/plugins/ml/server/types.ts +++ b/x-pack/plugins/ml/server/types.ts @@ -80,7 +80,8 @@ export interface RouteInitialization { router: IRouter; mlLicense: MlLicense; routeGuard: RouteGuard; - enabledFeatures: MlFeatures; + getEnabledFeatures: () => MlFeatures; + isServerless: boolean; } export type MlFeatures = Record<'ad' | 'dfa' | 'nlp', boolean>; diff --git a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx index 1a665924b5227..455d6d9d24ed3 100644 --- a/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx +++ b/x-pack/plugins/observability/public/components/slo/slo_status_badge/slo_group_by_badge.tsx @@ -25,10 +25,10 @@ export function SloGroupByBadge({ slo }: Props) { <EuiBadge color={euiLightVars.euiColorDisabled}> <EuiToolTip position="top" - content={i18n.translate('xpack.observability.slo.groupByBadge', { - defaultMessage: 'Group by {groupBy}', + content={i18n.translate('xpack.observability.slo.partitionByBadge', { + defaultMessage: 'Partition by {partitionKey}', values: { - groupBy: slo.groupBy, + partitionKey: slo.groupBy, }, })} display="block" diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/burn_rate.test.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/burn_rate.test.tsx new file mode 100644 index 0000000000000..5185fa73758d1 --- /dev/null +++ b/x-pack/plugins/observability/public/pages/slo_details/components/burn_rate.test.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { screen } from '@testing-library/react'; +import React from 'react'; + +import { buildSlo } from '../../../data/slo/slo'; +import { render } from '../../../utils/test_helper'; +import { BurnRate } from './burn_rate'; + +describe('BurnRate', () => { + it("displays '--' when burn rate is 'undefined'", async () => { + const slo = buildSlo(); + render(<BurnRate slo={slo} threshold={14.4} burnRate={undefined} isLoading={false} />); + + expect(screen.queryByTestId('sloDetailsBurnRateStat')).toHaveTextContent('--'); + }); + + it("displays the burn rate value when not 'undefined'", async () => { + const slo = buildSlo(); + render(<BurnRate slo={slo} threshold={14.4} burnRate={3.4} isLoading={false} />); + + expect(screen.queryByTestId('sloDetailsBurnRateStat')).toHaveTextContent('3.4x'); + }); + + it("displays the burn rate value when '0'", async () => { + const slo = buildSlo(); + render(<BurnRate slo={slo} threshold={14.4} burnRate={0} isLoading={false} />); + + expect(screen.queryByTestId('sloDetailsBurnRateStat')).toHaveTextContent('0x'); + }); +}); diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/burn_rate.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/burn_rate.tsx index 1fd2014dee4c7..46c35436359cf 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/components/burn_rate.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/components/burn_rate.tsx @@ -64,7 +64,8 @@ function getSubtitleFromStatus( } export function BurnRate({ threshold, burnRate, slo, isLoading }: BurnRateParams) { - const status: Status = !burnRate ? 'NO_DATA' : burnRate > threshold ? 'BREACHED' : 'OK'; + const status: Status = + burnRate === undefined ? 'NO_DATA' : burnRate > threshold ? 'BREACHED' : 'OK'; const color = status === 'NO_DATA' ? 'subdued' : status === 'BREACHED' ? 'danger' : 'success'; return ( @@ -86,11 +87,12 @@ export function BurnRate({ threshold, burnRate, slo, isLoading }: BurnRateParams <EuiFlexGroup direction="row" justifyContent="flexEnd" alignItems="flexEnd"> <EuiFlexItem grow={false}> <EuiStat - title={burnRate ? `${numeral(burnRate).format('0.[00]')}x` : '--'} + title={burnRate !== undefined ? `${numeral(burnRate).format('0.[00]')}x` : '--'} titleColor="default" titleSize="s" textAlign="right" isLoading={isLoading} + data-test-subj="sloDetailsBurnRateStat" description={ <EuiTextColor color="default"> <span> diff --git a/x-pack/plugins/observability/server/services/slo/slo_installer.ts b/x-pack/plugins/observability/server/services/slo/slo_installer.ts index d6e8b8295348f..44c2a7752e315 100644 --- a/x-pack/plugins/observability/server/services/slo/slo_installer.ts +++ b/x-pack/plugins/observability/server/services/slo/slo_installer.ts @@ -34,9 +34,7 @@ export class DefaultSLOInstaller implements SLOInstaller { await this.sloResourceInstaller.ensureCommonResourcesInstalled(); await this.sloSummaryInstaller.installAndStart(); } catch (error) { - this.logger.error('Failed to install SLO common resources and summary transforms', { - error, - }); + this.logger.error('Failed to install SLO common resources and summary transforms'); } finally { this.isInstalling = false; clearTimeout(installTimeout); diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap index 97850346b4d60..ee4001303fec5 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/histogram.test.ts.snap @@ -47,11 +47,24 @@ Object { exports[`Histogram Transform Generator filters the source using the kql query 1`] = ` Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ Object { - "match": Object { - "labels.groupId": "group-4", + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-4", + }, + }, + ], }, }, ], @@ -215,11 +228,24 @@ Object { ], "query": Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ Object { - "match": Object { - "labels.groupId": "group-3", + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-3", + }, + }, + ], }, }, ], @@ -458,11 +484,24 @@ Object { ], "query": Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ Object { - "match": Object { - "labels.groupId": "group-3", + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-3", + }, + }, + ], }, }, ], diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap index 20c3a00ea9b28..126437173f84a 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/kql_custom.test.ts.snap @@ -88,11 +88,24 @@ Object { exports[`KQL Custom Transform Generator filters the source using the kql query 1`] = ` Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ Object { - "match": Object { - "labels.groupId": "group-4", + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-4", + }, + }, + ], }, }, ], @@ -230,11 +243,24 @@ Object { ], "query": Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ + Object { + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, Object { - "match": Object { - "labels.groupId": "group-3", + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-3", + }, + }, + ], }, }, ], @@ -447,11 +473,24 @@ Object { ], "query": Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ Object { - "match": Object { - "labels.groupId": "group-3", + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-3", + }, + }, + ], }, }, ], diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap index fdd731df983cb..ced0801d859d4 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/__snapshots__/metric_custom.test.ts.snap @@ -59,11 +59,24 @@ Object { exports[`Metric Custom Transform Generator filters the source using the kql query 1`] = ` Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ Object { - "match": Object { - "labels.groupId": "group-4", + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-4", + }, + }, + ], }, }, ], @@ -239,11 +252,24 @@ Object { ], "query": Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ Object { - "match": Object { - "labels.groupId": "group-3", + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-3", + }, + }, + ], }, }, ], @@ -494,11 +520,24 @@ Object { ], "query": Object { "bool": Object { - "minimum_should_match": 1, - "should": Array [ + "filter": Array [ + Object { + "range": Object { + "log_timestamp": Object { + "gte": "now-7d", + }, + }, + }, Object { - "match": Object { - "labels.groupId": "group-3", + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "labels.groupId": "group-3", + }, + }, + ], }, }, ], diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts index aef873ed7e973..654f8d67a3673 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/histogram.ts @@ -45,11 +45,23 @@ export class HistogramTransformGenerator extends TransformGenerator { } private buildSource(slo: SLO, indicator: HistogramIndicator) { - const filter = getElastichsearchQueryOrThrow(indicator.params.filter); return { index: parseIndex(indicator.params.index), runtime_mappings: this.buildCommonRuntimeMappings(slo), - query: filter, + query: { + bool: { + filter: [ + { + range: { + [indicator.params.timestampField]: { + gte: `now-${slo.timeWindow.duration.format()}`, + }, + }, + }, + getElastichsearchQueryOrThrow(indicator.params.filter), + ], + }, + }, }; } diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts index 1dd162d688eb4..8321a0cb7172e 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/kql_custom.ts @@ -40,11 +40,23 @@ export class KQLCustomTransformGenerator extends TransformGenerator { } private buildSource(slo: SLO, indicator: KQLCustomIndicator) { - const filter = getElastichsearchQueryOrThrow(indicator.params.filter); return { index: parseIndex(indicator.params.index), runtime_mappings: this.buildCommonRuntimeMappings(slo), - query: filter, + query: { + bool: { + filter: [ + { + range: { + [indicator.params.timestampField]: { + gte: `now-${slo.timeWindow.duration.format()}`, + }, + }, + }, + getElastichsearchQueryOrThrow(indicator.params.filter), + ], + }, + }, }; } diff --git a/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts b/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts index 024f4403d9479..52209533f828c 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_generators/metric_custom.ts @@ -43,11 +43,23 @@ export class MetricCustomTransformGenerator extends TransformGenerator { } private buildSource(slo: SLO, indicator: MetricCustomIndicator) { - const filter = getElastichsearchQueryOrThrow(indicator.params.filter); return { index: parseIndex(indicator.params.index), runtime_mappings: this.buildCommonRuntimeMappings(slo), - query: filter, + query: { + bool: { + filter: [ + { + range: { + [indicator.params.timestampField]: { + gte: `now-${slo.timeWindow.duration.format()}`, + }, + }, + }, + getElastichsearchQueryOrThrow(indicator.params.filter), + ], + }, + }, }; } diff --git a/x-pack/plugins/observability_log_explorer/common/translations.ts b/x-pack/plugins/observability_log_explorer/common/translations.ts index 2abf660538260..8974c8a3f449e 100644 --- a/x-pack/plugins/observability_log_explorer/common/translations.ts +++ b/x-pack/plugins/observability_log_explorer/common/translations.ts @@ -28,3 +28,10 @@ export const discoverLinkTitle = i18n.translate( defaultMessage: 'Discover', } ); + +export const onboardingLinkTitle = i18n.translate( + 'xpack.observabilityLogExplorer.onboardingLinkTitle', + { + defaultMessage: 'Add data', + } +); diff --git a/x-pack/plugins/observability_log_explorer/kibana.jsonc b/x-pack/plugins/observability_log_explorer/kibana.jsonc index 529f879a56386..15beb1ed3c8d2 100644 --- a/x-pack/plugins/observability_log_explorer/kibana.jsonc +++ b/x-pack/plugins/observability_log_explorer/kibana.jsonc @@ -15,11 +15,12 @@ "data", "discover", "logExplorer", - "observabilityShared" + "observabilityShared", + "share" ], "optionalPlugins": [ "serverless" ], - "requiredBundles": ["kibanaReact"] + "requiredBundles": ["kibanaReact", "observabilityOnboarding"] } } diff --git a/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx b/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx index 999ebdd3095bf..562ff3ba9d109 100644 --- a/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx +++ b/x-pack/plugins/observability_log_explorer/public/applications/observability_log_explorer.tsx @@ -52,7 +52,6 @@ export const ObservabilityLogExplorerApp = ({ plugins, pluginStart, }: ObservabilityLogExplorerAppProps) => { - const { logExplorer, observabilityShared, serverless } = plugins; const KibanaContextProviderForPlugin = useKibanaContextForPluginProvider( core, plugins, @@ -67,15 +66,7 @@ export const ObservabilityLogExplorerApp = ({ <Route path="/" exact={true} - render={() => ( - <ObservablityLogExplorerMainRoute - appParams={appParams} - core={core} - logExplorer={logExplorer} - observabilityShared={observabilityShared} - serverless={serverless} - /> - )} + render={() => <ObservablityLogExplorerMainRoute appParams={appParams} core={core} />} /> </Routes> </Router> diff --git a/x-pack/plugins/observability_log_explorer/public/components/log_explorer_top_nav_menu.tsx b/x-pack/plugins/observability_log_explorer/public/components/log_explorer_top_nav_menu.tsx index 0e8ec200da871..dab2ddb772010 100644 --- a/x-pack/plugins/observability_log_explorer/public/components/log_explorer_top_nav_menu.tsx +++ b/x-pack/plugins/observability_log_explorer/public/components/log_explorer_top_nav_menu.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useEffect } from 'react'; import deepEqual from 'fast-deep-equal'; import useObservable from 'react-use/lib/useObservable'; import { type BehaviorSubject, distinctUntilChanged } from 'rxjs'; @@ -13,59 +13,148 @@ import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public'; import { AppMountParameters } from '@kbn/core-application-browser'; import { EuiBetaBadge, + EuiButton, + EuiHeader, EuiHeaderLink, EuiHeaderLinks, EuiHeaderSection, EuiHeaderSectionItem, useEuiTheme, } from '@elastic/eui'; -import { css } from '@emotion/react'; import { LogExplorerStateContainer } from '@kbn/log-explorer-plugin/public'; -import { useKibanaContextForPlugin } from '../utils/use_kibana'; -import { betaBadgeDescription, betaBadgeTitle, discoverLinkTitle } from '../../common/translations'; +import { + OBSERVABILITY_ONBOARDING_LOCATOR, + ObservabilityOnboardingLocatorParams, +} from '@kbn/observability-onboarding-plugin/public'; +import { KibanaReactContextValue } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import { css } from '@emotion/react'; +import { PluginKibanaContextValue } from '../utils/use_kibana'; +import { + betaBadgeDescription, + betaBadgeTitle, + discoverLinkTitle, + onboardingLinkTitle, +} from '../../common/translations'; +import { getRouterLinkProps } from '../utils/get_router_link_props'; interface LogExplorerTopNavMenuProps { setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; + services: KibanaReactContextValue<PluginKibanaContextValue>['services']; state$: BehaviorSubject<LogExplorerStateContainer>; theme$: AppMountParameters['theme$']; } export const LogExplorerTopNavMenu = ({ setHeaderActionMenu, + services, state$, theme$, }: LogExplorerTopNavMenuProps) => { + const { serverless } = services; + + return Boolean(serverless) ? ( + <ServerlessTopNav services={services} state$={state$} /> + ) : ( + <StatefulTopNav + services={services} + setHeaderActionMenu={setHeaderActionMenu} + state$={state$} + theme$={theme$} + /> + ); +}; + +const ServerlessTopNav = ({ + services, + state$, +}: Pick<LogExplorerTopNavMenuProps, 'services' | 'state$'>) => { const { euiTheme } = useEuiTheme(); return ( - <HeaderMenuPortal setHeaderActionMenu={setHeaderActionMenu} theme$={theme$}> + <EuiHeader data-test-subj="logExplorerHeaderMenu"> + <EuiHeaderSection> + <EuiHeaderSectionItem> + <EuiHeaderLinks gutterSize="xs"> + <DiscoverLink services={services} state$={state$} /> + </EuiHeaderLinks> + </EuiHeaderSectionItem> + </EuiHeaderSection> <EuiHeaderSection - data-test-subj="logExplorerHeaderMenu" + side="right" css={css` gap: ${euiTheme.size.m}; `} > <EuiHeaderSectionItem> <EuiBetaBadge + size="s" + iconType="beta" label={betaBadgeTitle} tooltipContent={betaBadgeDescription} alignment="middle" /> </EuiHeaderSectionItem> - <EuiHeaderLinks gutterSize="xs"> - <DiscoverLink state$={state$} /> - </EuiHeaderLinks> + <EuiHeaderSectionItem> + <OnboardingLink services={services} /> + </EuiHeaderSectionItem> + </EuiHeaderSection> + </EuiHeader> + ); +}; + +const StatefulTopNav = ({ + setHeaderActionMenu, + services, + state$, + theme$, +}: LogExplorerTopNavMenuProps) => { + const { euiTheme } = useEuiTheme(); + + useEffect(() => { + const { chrome, i18n, theme } = services; + + if (chrome) { + chrome.setBreadcrumbsAppendExtension({ + content: toMountPoint( + <EuiHeaderSection + data-test-subj="logExplorerHeaderMenu" + css={css` + margin-left: ${euiTheme.size.m}; + `} + > + <EuiHeaderSectionItem> + <EuiBetaBadge + size="s" + iconType="beta" + label={betaBadgeTitle} + tooltipContent={betaBadgeDescription} + alignment="middle" + /> + </EuiHeaderSectionItem> + </EuiHeaderSection>, + { theme, i18n } + ), + }); + } + }, [euiTheme, services]); + + return ( + <HeaderMenuPortal setHeaderActionMenu={setHeaderActionMenu} theme$={theme$}> + <EuiHeaderSection data-test-subj="logExplorerHeaderMenu"> + <EuiHeaderSectionItem> + <EuiHeaderLinks gutterSize="xs"> + <DiscoverLink services={services} state$={state$} /> + <OnboardingLink services={services} /> + </EuiHeaderLinks> + </EuiHeaderSectionItem> </EuiHeaderSection> </HeaderMenuPortal> ); }; const DiscoverLink = React.memo( - ({ state$ }: { state$: BehaviorSubject<LogExplorerStateContainer> }) => { - const { - services: { discover }, - } = useKibanaContextForPlugin(); - + ({ services, state$ }: Pick<LogExplorerTopNavMenuProps, 'services' | 'state$'>) => { const { appState, logExplorerState } = useObservable<LogExplorerStateContainer>( state$.pipe( distinctUntilChanged<LogExplorerStateContainer>((prev, curr) => { @@ -91,9 +180,20 @@ const DiscoverLink = React.memo( dataViewSpec: logExplorerState?.datasetSelection?.selection.dataset.toDataviewSpec(), }; + const discoverUrl = services.discover.locator?.getRedirectUrl(discoverLinkParams); + + const navigateToDiscover = () => { + services.discover.locator?.navigate(discoverLinkParams); + }; + + const discoverLinkProps = getRouterLinkProps({ + href: discoverUrl, + onClick: navigateToDiscover, + }); + return ( <EuiHeaderLink - onClick={() => discover.locator?.navigate(discoverLinkParams)} + {...discoverLinkProps} color="primary" iconType="discoverApp" data-test-subj="logExplorerDiscoverFallbackLink" @@ -103,3 +203,32 @@ const DiscoverLink = React.memo( ); } ); + +const OnboardingLink = React.memo(({ services }: Pick<LogExplorerTopNavMenuProps, 'services'>) => { + const locator = services.share.url.locators.get<ObservabilityOnboardingLocatorParams>( + OBSERVABILITY_ONBOARDING_LOCATOR + ); + + const onboardingUrl = locator?.useUrl({}); + + const navigateToOnboarding = () => { + locator?.navigate({}); + }; + + const onboardingLinkProps = getRouterLinkProps({ + href: onboardingUrl, + onClick: navigateToOnboarding, + }); + + return ( + <EuiButton + {...onboardingLinkProps} + fill + size="s" + iconType="indexOpen" + data-test-subj="logExplorerOnboardingLink" + > + {onboardingLinkTitle} + </EuiButton> + ); +}); diff --git a/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx b/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx index 7b224da830433..b4eb120ba3cae 100644 --- a/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx +++ b/x-pack/plugins/observability_log_explorer/public/routes/main/main_route.tsx @@ -6,38 +6,35 @@ */ import { AppMountParameters, CoreStart } from '@kbn/core/public'; -import { LogExplorerPluginStart } from '@kbn/log-explorer-plugin/public'; -import { ObservabilitySharedPluginStart } from '@kbn/observability-shared-plugin/public'; -import { ServerlessPluginStart } from '@kbn/serverless/public'; import React, { useState } from 'react'; import { BehaviorSubject } from 'rxjs'; import { LogExplorerTopNavMenu } from '../../components/log_explorer_top_nav_menu'; import { ObservabilityLogExplorerPageTemplate } from '../../components/page_template'; import { noBreadcrumbs, useBreadcrumbs } from '../../utils/breadcrumbs'; +import { useKibanaContextForPlugin } from '../../utils/use_kibana'; export interface ObservablityLogExplorerMainRouteProps { appParams: AppMountParameters; core: CoreStart; - logExplorer: LogExplorerPluginStart; - observabilityShared: ObservabilitySharedPluginStart; - serverless?: ServerlessPluginStart; } export const ObservablityLogExplorerMainRoute = ({ - appParams: { history, setHeaderActionMenu, theme$ }, + appParams, core, - logExplorer, - observabilityShared, - serverless, }: ObservablityLogExplorerMainRouteProps) => { + const { services } = useKibanaContextForPlugin(); + const { logExplorer, observabilityShared, serverless } = services; useBreadcrumbs(noBreadcrumbs, core.chrome, serverless); + const { history, setHeaderActionMenu, theme$ } = appParams; + const [state$] = useState(() => new BehaviorSubject({})); return ( <> <LogExplorerTopNavMenu setHeaderActionMenu={setHeaderActionMenu} + services={services} state$={state$} theme$={theme$} /> diff --git a/x-pack/plugins/observability_log_explorer/public/types.ts b/x-pack/plugins/observability_log_explorer/public/types.ts index e52ece9ca1624..48b2ad624796a 100644 --- a/x-pack/plugins/observability_log_explorer/public/types.ts +++ b/x-pack/plugins/observability_log_explorer/public/types.ts @@ -10,6 +10,7 @@ import { DiscoverStart } from '@kbn/discover-plugin/public'; import { LogExplorerPluginStart } from '@kbn/log-explorer-plugin/public'; import { ObservabilitySharedPluginStart } from '@kbn/observability-shared-plugin/public'; import { ServerlessPluginStart } from '@kbn/serverless/public'; +import { SharePluginStart } from '@kbn/share-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ObservabilityLogExplorerPluginSetup {} @@ -27,4 +28,5 @@ export interface ObservabilityLogExplorerStartDeps { logExplorer: LogExplorerPluginStart; observabilityShared: ObservabilitySharedPluginStart; serverless?: ServerlessPluginStart; + share: SharePluginStart; } diff --git a/x-pack/plugins/observability_log_explorer/public/utils/get_router_link_props.ts b/x-pack/plugins/observability_log_explorer/public/utils/get_router_link_props.ts new file mode 100644 index 0000000000000..a325df1a7e86f --- /dev/null +++ b/x-pack/plugins/observability_log_explorer/public/utils/get_router_link_props.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +interface GetRouterLinkPropsDeps { + href?: string; + onClick(): void; +} + +const isModifiedEvent = (event: React.MouseEvent<HTMLAnchorElement>) => + !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); + +const isLeftClickEvent = (event: React.MouseEvent<HTMLAnchorElement>) => event.button === 0; + +export const getRouterLinkProps = ({ href, onClick }: GetRouterLinkPropsDeps) => { + const guardedClickHandler = (event: React.MouseEvent<HTMLAnchorElement>) => { + if (event.defaultPrevented) { + return; + } + + if (isModifiedEvent(event) || !isLeftClickEvent(event)) { + return; + } + + // Prevent regular link behavior, which causes a browser refresh. + event.preventDefault(); + + onClick(); + }; + + return { href, onClick: guardedClickHandler }; +}; diff --git a/x-pack/plugins/observability_log_explorer/tsconfig.json b/x-pack/plugins/observability_log_explorer/tsconfig.json index ae9660b421359..0100aa5abb37a 100644 --- a/x-pack/plugins/observability_log_explorer/tsconfig.json +++ b/x-pack/plugins/observability_log_explorer/tsconfig.json @@ -24,6 +24,9 @@ "@kbn/config-schema", "@kbn/core-application-browser", "@kbn/discover-plugin", + "@kbn/observability-onboarding-plugin", + "@kbn/react-kibana-mount", + "@kbn/share-plugin", ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_onboarding/public/application/app.tsx b/x-pack/plugins/observability_onboarding/public/application/app.tsx index 0646e0d800924..93a62f5f378e3 100644 --- a/x-pack/plugins/observability_onboarding/public/application/app.tsx +++ b/x-pack/plugins/observability_onboarding/public/application/app.tsx @@ -26,7 +26,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { RouteComponentProps, RouteProps } from 'react-router-dom'; import { ConfigSchema } from '..'; -import { customLogsRoutes } from '../components/app/custom_logs/wizard'; +import { customLogsRoutes } from '../components/app/custom_logs'; import { systemLogsRoutes } from '../components/app/system_logs'; import { ObservabilityOnboardingHeaderActionMenu } from '../components/app/header_action_menu'; import { diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/api_key_banner.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/api_key_banner.tsx similarity index 98% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/api_key_banner.tsx rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/api_key_banner.tsx index b0d6b5f9e6c26..46d39cd70c31c 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/api_key_banner.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/api_key_banner.tsx @@ -18,7 +18,7 @@ import { IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser'; import { i18n } from '@kbn/i18n'; import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; import React from 'react'; -import { APIReturnType } from '../../../../services/rest/create_call_api'; +import { APIReturnType } from '../../../services/rest/create_call_api'; type ApiKeyPayload = APIReturnType<'POST /internal/observability_onboarding/logs/flow'>; diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/back_button.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/back_button.tsx similarity index 100% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/back_button.tsx rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/back_button.tsx diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/configure_logs.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/configure_logs.tsx similarity index 99% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/configure_logs.tsx rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/configure_logs.tsx index 9a6d83a3c84b3..1e438e1dd0e66 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/configure_logs.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/configure_logs.tsx @@ -35,12 +35,12 @@ import { } from '@kbn/custom-integrations'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useWizard } from '.'; -import { OptionalFormRow } from '../../../shared/optional_form_row'; +import { OptionalFormRow } from '../../shared/optional_form_row'; import { StepPanel, StepPanelContent, StepPanelFooter, -} from '../../../shared/step_panel'; +} from '../../shared/step_panel'; import { BackButton } from './back_button'; import { getFilename } from './get_filename'; diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/get_filename.ts b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/get_filename.ts similarity index 100% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/get_filename.ts rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/get_filename.ts diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/index.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/index.tsx similarity index 97% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/index.tsx rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/index.tsx index 9fb2f2ecf9536..81d7faf448a48 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/index.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/index.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { createWizardContext, Step, -} from '../../../../context/create_wizard_context'; +} from '../../../context/create_wizard_context'; import { ConfigureLogs } from './configure_logs'; import { Inspect } from './inspect'; import { InstallElasticAgent } from './install_elastic_agent'; diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/inspect.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/inspect.tsx similarity index 97% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/inspect.tsx rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/inspect.tsx index 2a9074e6976e1..b632fd6e84ffc 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/inspect.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/inspect.tsx @@ -11,7 +11,7 @@ import { StepPanel, StepPanelContent, StepPanelFooter, -} from '../../../shared/step_panel'; +} from '../../shared/step_panel'; import { useWizard } from '.'; import { BackButton } from './back_button'; diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/install_elastic_agent.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/install_elastic_agent.tsx similarity index 86% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/install_elastic_agent.tsx rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/install_elastic_agent.tsx index 2457d75d4f543..fc8e36626c4cd 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/install_elastic_agent.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/install_elastic_agent.tsx @@ -7,10 +7,7 @@ import { EuiButton, - EuiButtonEmpty, EuiCallOut, - EuiFlexGroup, - EuiFlexItem, EuiHorizontalRule, EuiSpacer, EuiText, @@ -18,28 +15,28 @@ import { import { i18n } from '@kbn/i18n'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { default as React, useCallback, useEffect, useState } from 'react'; -import { ObservabilityOnboardingPluginSetupDeps } from '../../../../plugin'; +import { ObservabilityOnboardingPluginSetupDeps } from '../../../plugin'; import { useWizard } from '.'; -import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/use_fetcher'; import { ElasticAgentPlatform, getElasticAgentSetupCommand, -} from '../../../shared/get_elastic_agent_setup_command'; +} from '../../shared/get_elastic_agent_setup_command'; import { InstallElasticAgentSteps, ProgressStepId, EuiStepStatus, -} from '../../../shared/install_elastic_agent_steps'; +} from '../../shared/install_elastic_agent_steps'; import { StepPanel, StepPanelContent, StepPanelFooter, -} from '../../../shared/step_panel'; +} from '../../shared/step_panel'; import { ApiKeyBanner } from './api_key_banner'; import { BackButton } from './back_button'; -import { getDiscoverNavigationParams } from '../../utils'; -import { WindowsInstallStep } from '../../../shared/windows_install_step'; -import { TroubleshootingLink } from '../../../shared/troubleshooting_link'; +import { getDiscoverNavigationParams } from '../utils'; +import { WindowsInstallStep } from '../../shared/windows_install_step'; +import { TroubleshootingLink } from '../../shared/troubleshooting_link'; export function InstallElasticAgent() { const { @@ -47,14 +44,11 @@ export function InstallElasticAgent() { discover: { locator }, }, } = useKibana<ObservabilityOnboardingPluginSetupDeps>(); - const { goBack, goToStep, getState, setState } = useWizard(); + const { goBack, getState, setState } = useWizard(); const wizardState = getState(); const [elasticAgentPlatform, setElasticAgentPlatform] = useState<ElasticAgentPlatform>('linux-tar'); - function onInspect() { - goToStep('inspect'); - } async function onContinue() { await locator?.navigate( getDiscoverNavigationParams([wizardState.datasetName]) @@ -235,33 +229,18 @@ export function InstallElasticAgent() { <StepPanelFooter items={[ <BackButton onBack={goBack} />, - <EuiFlexGroup justifyContent="flexEnd" alignItems="center"> - <EuiFlexItem grow={false}> - <EuiButtonEmpty - data-test-subj="observabilityOnboardingInstallElasticAgentInspectButton" - onClick={onInspect} - > - {i18n.translate( - 'xpack.observability_onboarding.steps.inspect', - { defaultMessage: 'Inspect' } - )} - </EuiButtonEmpty> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiButton - data-test-subj="obltOnboardingExploreLogs" - color="success" - fill - iconType="magnifyWithPlus" - onClick={onContinue} - > - {i18n.translate( - 'xpack.observability_onboarding.steps.exploreLogs', - { defaultMessage: 'Explore logs' } - )} - </EuiButton> - </EuiFlexItem> - </EuiFlexGroup>, + <EuiButton + data-test-subj="obltOnboardingExploreLogs" + color="success" + fill + iconType="magnifyWithPlus" + onClick={onContinue} + > + {i18n.translate( + 'xpack.observability_onboarding.steps.exploreLogs', + { defaultMessage: 'Explore logs' } + )} + </EuiButton>, ]} /> } diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/select_logs.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/select_logs.tsx similarity index 98% rename from x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/select_logs.tsx rename to x-pack/plugins/observability_onboarding/public/components/app/custom_logs/select_logs.tsx index d0712346c1b61..7bed69c1c8f9b 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/select_logs.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/select_logs.tsx @@ -25,9 +25,9 @@ import { StepPanel, StepPanelContent, StepPanelFooter, -} from '../../../shared/step_panel'; +} from '../../shared/step_panel'; import { useWizard } from '.'; -import { useKibanaNavigation } from '../../../../hooks/use_kibana_navigation'; +import { useKibanaNavigation } from '../../../hooks/use_kibana_navigation'; export function SelectLogs() { const { navigateToKibanaUrl, navigateToAppUrl } = useKibanaNavigation(); diff --git a/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx b/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx index 13aec2ff31c06..9ea11e6fe0a5d 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx @@ -139,11 +139,12 @@ export function Home() { paddingSize="l" display="plain" hasBorder + onClick={handleClickSystemLogs} > <EuiSpacer size="s" /> <EuiBadge color="hollow">{elasticAgentLabel}</EuiBadge> <EuiSpacer size="m" /> - <EuiText color="subdued" size="s" textAlign="left"> + <EuiText color="subdued" size="s" textAlign="center"> <p> {i18n.translate( 'xpack.observability_onboarding.card.systemLogs.description1', @@ -177,11 +178,12 @@ export function Home() { paddingSize="l" display="plain" hasBorder + onClick={handleClickCustomLogs} > <EuiSpacer size="s" /> <EuiBadge color="hollow">{elasticAgentLabel}</EuiBadge> <EuiSpacer size="m" /> - <EuiText color="subdued" size="s" textAlign="left"> + <EuiText color="subdued" size="s" textAlign="center"> <p> {i18n.translate( 'xpack.observability_onboarding.card.customLogs.description.text', @@ -263,6 +265,7 @@ export function Home() { paddingSize="m" display="plain" hasBorder + onClick={handleClickKubernetesSetupGuide} /> </EuiFlexItem> </EuiFlexGroup> diff --git a/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx b/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx index 4a753161d39b0..9b07c56f84a33 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx @@ -35,7 +35,7 @@ import { StepPanelContent, StepPanelFooter, } from '../../shared/step_panel'; -import { ApiKeyBanner } from '../custom_logs/wizard/api_key_banner'; +import { ApiKeyBanner } from '../custom_logs/api_key_banner'; import { getDiscoverNavigationParams } from '../utils'; import { WindowsInstallStep } from '../../shared/windows_install_step'; import { SystemIntegrationBanner } from './system_integration_banner'; diff --git a/x-pack/plugins/observability_onboarding/public/index.ts b/x-pack/plugins/observability_onboarding/public/index.ts index d4a667b9e7269..b83c5b6d5cad0 100644 --- a/x-pack/plugins/observability_onboarding/public/index.ts +++ b/x-pack/plugins/observability_onboarding/public/index.ts @@ -18,6 +18,7 @@ import { } from './plugin'; export { OBSERVABILITY_ONBOARDING_LOCATOR } from './locators/onboarding_locator/locator_definition'; +export type { ObservabilityOnboardingLocatorParams } from './locators/onboarding_locator/types'; export interface ConfigSchema { ui: { diff --git a/x-pack/plugins/observability_onboarding/public/routes/index.tsx b/x-pack/plugins/observability_onboarding/public/routes/index.tsx index 66a99343be2b2..35044a98df050 100644 --- a/x-pack/plugins/observability_onboarding/public/routes/index.tsx +++ b/x-pack/plugins/observability_onboarding/public/routes/index.tsx @@ -8,7 +8,7 @@ import * as t from 'io-ts'; import React from 'react'; import { Redirect } from 'react-router-dom'; -import { customLogsRoutes } from '../components/app/custom_logs/wizard'; +import { customLogsRoutes } from '../components/app/custom_logs'; import { systemLogsRoutes } from '../components/app/system_logs'; import { Home } from '../components/app/home'; diff --git a/x-pack/plugins/observability_onboarding/public/routes/templates/custom_logs.tsx b/x-pack/plugins/observability_onboarding/public/routes/templates/custom_logs.tsx index da30df8a11eac..bd31340edbf21 100644 --- a/x-pack/plugins/observability_onboarding/public/routes/templates/custom_logs.tsx +++ b/x-pack/plugins/observability_onboarding/public/routes/templates/custom_logs.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public'; import React, { ComponentType, useRef, useState } from 'react'; import { breadcrumbsApp } from '../../application/app'; -import { Provider as WizardProvider } from '../../components/app/custom_logs/wizard'; +import { Provider as WizardProvider } from '../../components/app/custom_logs'; import { FilmstripFrame, FilmstripTransition, diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts index c100f4c0b7de1..9a9448fc790b0 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_liked_apps.cy.ts @@ -16,10 +16,11 @@ import { } from '../../tasks/live_query'; import { closeModalIfVisible, closeToastIfVisible } from '../../tasks/integrations'; import { RESULTS_TABLE, RESULTS_TABLE_BUTTON } from '../../screens/live_query'; +import { ServerlessRoleName } from '../../support/roles'; const UUID_REGEX = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}'; -describe('Alert Event Details', { tags: ['@ess', '@serverless'] }, () => { +describe('Alert Event Details', { browser: 'electron', tags: ['@ess', '@serverless'] }, () => { let ruleId: string; let ruleName: string; @@ -36,7 +37,7 @@ describe('Alert Event Details', { tags: ['@ess', '@serverless'] }, () => { }); beforeEach(() => { - cy.login('elastic'); + cy.login(ServerlessRoleName.SOC_MANAGER); cy.visit('/app/security/rules'); clickRuleName(ruleName); }); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts index 0d83358ca76b1..cac1e827721da 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts @@ -26,167 +26,172 @@ import { typeInECSFieldInput, } from '../../tasks/live_query'; import { closeDateTabIfVisible, closeToastIfVisible } from '../../tasks/integrations'; +import { ServerlessRoleName } from '../../support/roles'; -describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serverless'] }, () => { - let multiQueryPackId: string; - let multiQueryPackName: string; - let ruleId: string; - let ruleName: string; - let packId: string; - let packName: string; - const packData = packFixture(); - const multiQueryPackData = multiQueryPackFixture(); +describe( + 'Alert Event Details - Response Actions Form', + { browser: 'electron', tags: ['@ess', '@serverless'] }, + () => { + let multiQueryPackId: string; + let multiQueryPackName: string; + let ruleId: string; + let ruleName: string; + let packId: string; + let packName: string; + const packData = packFixture(); + const multiQueryPackData = multiQueryPackFixture(); - beforeEach(() => { - loadPack(packData).then((data) => { - packId = data.saved_object_id; - packName = data.name; - }); - loadPack(multiQueryPackData).then((data) => { - multiQueryPackId = data.saved_object_id; - multiQueryPackName = data.name; + beforeEach(() => { + loadPack(packData).then((data) => { + packId = data.saved_object_id; + packName = data.name; + }); + loadPack(multiQueryPackData).then((data) => { + multiQueryPackId = data.saved_object_id; + multiQueryPackName = data.name; + }); + loadRule().then((data) => { + ruleId = data.id; + ruleName = data.name; + }); + cy.login(ServerlessRoleName.SOC_MANAGER); }); - loadRule().then((data) => { - ruleId = data.id; - ruleName = data.name; + afterEach(() => { + cleanupPack(packId); + cleanupPack(multiQueryPackId); + cleanupRule(ruleId); }); - cy.login('elastic'); - }); - afterEach(() => { - cleanupPack(packId); - cleanupPack(multiQueryPackId); - cleanupRule(ruleId); - }); - it('adds response actions with osquery with proper validation and form values', () => { - cy.visit('/app/security/rules'); - clickRuleName(ruleName); - cy.getBySel('editRuleSettingsLink').click(); - cy.getBySel('globalLoadingIndicator').should('not.exist'); - closeDateTabIfVisible(); - cy.getBySel('edit-rule-actions-tab').click(); - cy.contains('Response actions are run on each rule execution.'); - cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); - cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { - cy.contains('Query is a required field'); - inputQuery('select * from uptime1'); - }); - cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); - cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { - cy.contains('Run a set of queries in a pack').click(); - }); - cy.contains('Save changes').click(); - cy.getBySel('response-actions-error') - .within(() => { + it('adds response actions with osquery with proper validation and form values', () => { + cy.visit('/app/security/rules'); + clickRuleName(ruleName); + cy.getBySel('editRuleSettingsLink').click(); + cy.getBySel('globalLoadingIndicator').should('not.exist'); + closeDateTabIfVisible(); + cy.getBySel('edit-rule-actions-tab').click(); + cy.contains('Response actions are run on each rule execution.'); + cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.contains('Query is a required field'); + inputQuery('select * from uptime1'); + }); + cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); + cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { + cy.contains('Run a set of queries in a pack').click(); + }); + cy.contains('Save changes').click(); + cy.getBySel('response-actions-error') + .within(() => { + cy.contains('Pack is a required field'); + }) + .should('exist'); + cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { cy.contains('Pack is a required field'); - }) - .should('exist'); - cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { - cy.contains('Pack is a required field'); - cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`); - }); + cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`); + }); - cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); + cy.getBySel(OSQUERY_RESPONSE_ACTION_ADD_BUTTON).click(); - cy.getBySel(RESPONSE_ACTIONS_ITEM_2).within(() => { - cy.contains('Query is a required field'); - inputQuery('select * from uptime'); - cy.contains('Advanced').click(); - typeInECSFieldInput('message{downArrow}{enter}'); - cy.getBySel('osqueryColumnValueSelect').type('days{downArrow}{enter}'); - cy.wait(1000); // wait for the validation to trigger - cypress is way faster than users ;) - }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_2).within(() => { + cy.contains('Query is a required field'); + inputQuery('select * from uptime'); + cy.contains('Advanced').click(); + typeInECSFieldInput('message{downArrow}{enter}'); + cy.getBySel('osqueryColumnValueSelect').type('days{downArrow}{enter}'); + cy.wait(1000); // wait for the validation to trigger - cypress is way faster than users ;) + }); - cy.getBySel('ruleEditSubmitButton').click(); - cy.contains(`${ruleName} was saved`).should('exist'); - closeToastIfVisible(); + cy.getBySel('ruleEditSubmitButton').click(); + cy.contains(`${ruleName} was saved`).should('exist'); + closeToastIfVisible(); - cy.getBySel('editRuleSettingsLink').click(); - cy.getBySel('globalLoadingIndicator').should('not.exist'); - cy.getBySel('edit-rule-actions-tab').click(); - cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { - cy.contains('select * from uptime1'); - }); - cy.getBySel(RESPONSE_ACTIONS_ITEM_2).within(() => { - cy.contains('select * from uptime'); - cy.contains('Log message optimized for viewing in a log viewer'); - cy.contains('Days of uptime'); - }); - cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { - cy.contains(packName); - cy.getBySel('comboBoxInput').type('{backspace}{enter}'); - }); - cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { - cy.contains('select * from uptime1'); - cy.getBySel('remove-response-action').click(); - }); - cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { - cy.contains('Search for a pack to run'); - cy.contains('Pack is a required field'); - cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`); - }); - cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { - cy.contains('select * from uptime'); - cy.contains('Log message optimized for viewing in a log viewer'); - cy.contains('Days of uptime'); - }); - cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleSingleQuery'); - cy.getBySel('ruleEditSubmitButton').click(); - cy.wait('@saveRuleSingleQuery').should(({ request }) => { - const oneQuery = [ - { - interval: 3600, - query: 'select * from uptime;', - id: Object.keys(packData.queries)[0], - }, - ]; - expect(request.body.response_actions[0].params.queries).to.deep.equal(oneQuery); - }); + cy.getBySel('editRuleSettingsLink').click(); + cy.getBySel('globalLoadingIndicator').should('not.exist'); + cy.getBySel('edit-rule-actions-tab').click(); + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.contains('select * from uptime1'); + }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_2).within(() => { + cy.contains('select * from uptime'); + cy.contains('Log message optimized for viewing in a log viewer'); + cy.contains('Days of uptime'); + }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { + cy.contains(packName); + cy.getBySel('comboBoxInput').type('{backspace}{enter}'); + }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.contains('select * from uptime1'); + cy.getBySel('remove-response-action').click(); + }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.contains('Search for a pack to run'); + cy.contains('Pack is a required field'); + cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`); + }); + cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { + cy.contains('select * from uptime'); + cy.contains('Log message optimized for viewing in a log viewer'); + cy.contains('Days of uptime'); + }); + cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleSingleQuery'); + cy.getBySel('ruleEditSubmitButton').click(); + cy.wait('@saveRuleSingleQuery').should(({ request }) => { + const oneQuery = [ + { + interval: 3600, + query: 'select * from uptime;', + id: Object.keys(packData.queries)[0], + }, + ]; + expect(request.body.response_actions[0].params.queries).to.deep.equal(oneQuery); + }); - cy.contains(`${ruleName} was saved`).should('exist'); - closeToastIfVisible(); + cy.contains(`${ruleName} was saved`).should('exist'); + closeToastIfVisible(); - cy.getBySel('editRuleSettingsLink').click(); - cy.getBySel('globalLoadingIndicator').should('not.exist'); - cy.getBySel('edit-rule-actions-tab').click(); - cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { - cy.contains(packName); - cy.getBySel('comboBoxInput').type(`${multiQueryPackName}{downArrow}{enter}`); - checkActionItemsInResults({ - cases: false, - lens: false, - discover: false, - timeline: false, + cy.getBySel('editRuleSettingsLink').click(); + cy.getBySel('globalLoadingIndicator').should('not.exist'); + cy.getBySel('edit-rule-actions-tab').click(); + cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { + cy.contains(packName); + cy.getBySel('comboBoxInput').type(`${multiQueryPackName}{downArrow}{enter}`); + checkActionItemsInResults({ + cases: false, + lens: false, + discover: false, + timeline: false, + }); }); - }); - cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { - cy.contains('select * from uptime'); - cy.contains('Log message optimized for viewing in a log viewer'); - cy.contains('Days of uptime'); - }); - cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleMultiQuery'); + cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { + cy.contains('select * from uptime'); + cy.contains('Log message optimized for viewing in a log viewer'); + cy.contains('Days of uptime'); + }); + cy.intercept('PUT', '/api/detection_engine/rules').as('saveRuleMultiQuery'); - cy.contains('Save changes').click(); - cy.wait('@saveRuleMultiQuery').should(({ request }) => { - const threeQueries = [ - { - interval: 3600, - query: 'SELECT * FROM memory_info;', - platform: 'linux', - id: Object.keys(multiQueryPackData.queries)[0], - }, - { - interval: 3600, - query: 'SELECT * FROM system_info;', - id: Object.keys(multiQueryPackData.queries)[1], - }, - { - interval: 10, - query: 'select opera_extensions.* from users join opera_extensions using (uid);', - id: Object.keys(multiQueryPackData.queries)[2], - }, - ]; - expect(request.body.response_actions[0].params.queries).to.deep.equal(threeQueries); + cy.contains('Save changes').click(); + cy.wait('@saveRuleMultiQuery').should(({ request }) => { + const threeQueries = [ + { + interval: 3600, + query: 'SELECT * FROM memory_info;', + platform: 'linux', + id: Object.keys(multiQueryPackData.queries)[0], + }, + { + interval: 3600, + query: 'SELECT * FROM system_info;', + id: Object.keys(multiQueryPackData.queries)[1], + }, + { + interval: 10, + query: 'select opera_extensions.* from users join opera_extensions using (uid);', + id: Object.keys(multiQueryPackData.queries)[2], + }, + ]; + expect(request.body.response_actions[0].params.queries).to.deep.equal(threeQueries); + }); }); - }); -}); + } +); diff --git a/x-pack/plugins/reporting/public/management/__test__/report_listing.test.helpers.tsx b/x-pack/plugins/reporting/public/management/__test__/report_listing.test.helpers.tsx index fc1b0f25d9c01..2d24736d7e13b 100644 --- a/x-pack/plugins/reporting/public/management/__test__/report_listing.test.helpers.tsx +++ b/x-pack/plugins/reporting/public/management/__test__/report_listing.test.helpers.tsx @@ -70,6 +70,7 @@ export const mockConfig = { roles: { enabled: false, }, + statefulSettings: { enabled: true }, }; const validCheck = { diff --git a/x-pack/plugins/reporting/public/management/mount_management_section.tsx b/x-pack/plugins/reporting/public/management/mount_management_section.tsx index 604885e8be360..4c994a5bb61b4 100644 --- a/x-pack/plugins/reporting/public/management/mount_management_section.tsx +++ b/x-pack/plugins/reporting/public/management/mount_management_section.tsx @@ -11,6 +11,7 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { Observable } from 'rxjs'; import { CoreSetup, CoreStart } from '@kbn/core/public'; import { ILicense } from '@kbn/licensing-plugin/public'; +import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme'; import { ReportingAPIClient, InternalApiClientProvider } from '../lib/reporting_api_client'; import { IlmPolicyStatusContextProvider } from '../lib/ilm_policy_status_context'; import { ClientConfigType } from '../plugin'; @@ -28,29 +29,31 @@ export async function mountManagementSection( params: ManagementAppMountParams ) { render( - <I18nProvider> - <KibanaContextProvider - services={{ - http: coreSetup.http, - application: coreStart.application, - uiSettings: coreStart.uiSettings, - docLinks: coreStart.docLinks, - }} - > - <InternalApiClientProvider apiClient={apiClient}> - <IlmPolicyStatusContextProvider> - <ReportListing - toasts={coreSetup.notifications.toasts} - license$={license$} - config={config} - redirect={coreStart.application.navigateToApp} - navigateToUrl={coreStart.application.navigateToUrl} - urlService={urlService} - /> - </IlmPolicyStatusContextProvider> - </InternalApiClientProvider> - </KibanaContextProvider> - </I18nProvider>, + <KibanaThemeProvider theme={{ theme$: params.theme$ }}> + <I18nProvider> + <KibanaContextProvider + services={{ + http: coreSetup.http, + application: coreStart.application, + uiSettings: coreStart.uiSettings, + docLinks: coreStart.docLinks, + }} + > + <InternalApiClientProvider apiClient={apiClient}> + <IlmPolicyStatusContextProvider> + <ReportListing + toasts={coreSetup.notifications.toasts} + license$={license$} + config={config} + redirect={coreStart.application.navigateToApp} + navigateToUrl={coreStart.application.navigateToUrl} + urlService={urlService} + /> + </IlmPolicyStatusContextProvider> + </InternalApiClientProvider> + </KibanaContextProvider> + </I18nProvider> + </KibanaThemeProvider>, params.element ); diff --git a/x-pack/plugins/reporting/public/management/report_listing.tsx b/x-pack/plugins/reporting/public/management/report_listing.tsx index 74753437f54ce..49607c6f38710 100644 --- a/x-pack/plugins/reporting/public/management/report_listing.tsx +++ b/x-pack/plugins/reporting/public/management/report_listing.tsx @@ -109,7 +109,7 @@ class ReportListingUi extends Component<Props, State> { } /> - <MigrateIlmPolicyCallOut toasts={toasts} /> + {config.statefulSettings.enabled ? <MigrateIlmPolicyCallOut toasts={toasts} /> : null} <EuiSpacer size={'l'} /> <div>{this.renderTable()}</div> diff --git a/x-pack/plugins/reporting/public/plugin.ts b/x-pack/plugins/reporting/public/plugin.ts index 912f519d60002..46e425b54239d 100644 --- a/x-pack/plugins/reporting/public/plugin.ts +++ b/x-pack/plugins/reporting/public/plugin.ts @@ -47,6 +47,7 @@ export interface ClientConfigType { poll: { jobsRefresh: { interval: number; intervalErrorMultiplier: number } }; roles: { enabled: boolean }; export_types: { pdf: { enabled: boolean }; png: { enabled: boolean }; csv: { enabled: boolean } }; + statefulSettings: { enabled: boolean }; } function getStored(): JobId[] { diff --git a/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap b/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap index 48f834d238795..1c9a695f4a78e 100644 --- a/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap +++ b/x-pack/plugins/reporting/server/config/__snapshots__/schema.test.ts.snap @@ -55,6 +55,9 @@ Object { ], "enabled": true, }, + "statefulSettings": Object { + "enabled": true, + }, } `; @@ -112,5 +115,8 @@ Object { ], "enabled": true, }, + "statefulSettings": Object { + "enabled": true, + }, } `; diff --git a/x-pack/plugins/reporting/server/config/create_config.test.ts b/x-pack/plugins/reporting/server/config/create_config.test.ts index 0a10b859bb18f..dbb16d050297f 100644 --- a/x-pack/plugins/reporting/server/config/create_config.test.ts +++ b/x-pack/plugins/reporting/server/config/create_config.test.ts @@ -51,6 +51,9 @@ describe('Reporting server createConfig', () => { port: 5677, protocol: 'httpsa', }, + statefulSettings: { + enabled: true, + }, }); const result = createConfig(mockCoreSetup, mockConfig, mockLogger); @@ -92,6 +95,9 @@ describe('Reporting server createConfig', () => { "roles": Object { "enabled": false, }, + "statefulSettings": Object { + "enabled": true, + }, } `); expect(mockLogger.warn).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/reporting/server/config/index.ts b/x-pack/plugins/reporting/server/config/index.ts index 5786498035721..3bb4b79dd6fc8 100644 --- a/x-pack/plugins/reporting/server/config/index.ts +++ b/x-pack/plugins/reporting/server/config/index.ts @@ -11,7 +11,7 @@ import { get } from 'lodash'; import { ConfigSchema, ReportingConfigType } from './schema'; export const config: PluginConfigDescriptor<ReportingConfigType> = { - exposeToBrowser: { poll: true, roles: true, export_types: true }, + exposeToBrowser: { poll: true, roles: true, export_types: true, statefulSettings: true }, schema: ConfigSchema, deprecations: ({ unused }) => [ unused('capture.browser.chromium.maxScreenshotDimension', { level: 'warning' }), // unused since 7.8 diff --git a/x-pack/plugins/reporting/server/config/schema.test.ts b/x-pack/plugins/reporting/server/config/schema.test.ts index 14ed1886e9136..f30be71db09ea 100644 --- a/x-pack/plugins/reporting/server/config/schema.test.ts +++ b/x-pack/plugins/reporting/server/config/schema.test.ts @@ -85,6 +85,14 @@ describe('Reporting Config Schema', () => { `); }); + it('disables ilm settings in serverless', () => { + expect(ConfigSchema.validate({}, { serverless: true }).statefulSettings).toMatchInlineSnapshot(` + Object { + "enabled": false, + } + `); + }); + it('disables screenshot type exports in serverless', () => { expect(ConfigSchema.validate({}, { serverless: true }).export_types).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/reporting/server/config/schema.ts b/x-pack/plugins/reporting/server/config/schema.ts index 966f4f20ff313..ff0cda89a693b 100644 --- a/x-pack/plugins/reporting/server/config/schema.ts +++ b/x-pack/plugins/reporting/server/config/schema.ts @@ -128,6 +128,13 @@ const ExportTypeSchema = schema.object({ }), }); +const SettingsSchema = schema.object({ + enabled: offeringBasedSchema({ + serverless: schema.boolean({ defaultValue: false }), + traditional: schema.boolean({ defaultValue: true }), + }), +}); + export const ConfigSchema = schema.object({ enabled: schema.boolean({ defaultValue: true }), kibanaServer: KibanaServerSchema, @@ -138,6 +145,7 @@ export const ConfigSchema = schema.object({ roles: RolesSchema, poll: PollSchema, export_types: ExportTypeSchema, + statefulSettings: SettingsSchema, }); export type ReportingConfigType = TypeOf<typeof ConfigSchema>; diff --git a/x-pack/plugins/reporting/server/lib/store/store.test.ts b/x-pack/plugins/reporting/server/lib/store/store.test.ts index f1400ab357ee9..64556ef1a2c22 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.test.ts @@ -19,6 +19,7 @@ describe('ReportingStore', () => { const reportingConfig = { index: '.reporting-test', queue: { indexInterval: 'week' }, + statefulSettings: { enabled: true }, }; mockCore = await createMockReportingCore(createMockConfigSchema(reportingConfig)); mockEsClient = (await mockCore.getEsClient()).asInternalUser as typeof mockEsClient; @@ -60,6 +61,7 @@ describe('ReportingStore', () => { const reportingConfig = { index: '.reporting-test', queue: { indexInterval: 'centurially' }, + statefulSettings: { enabled: true }, }; mockCore = await createMockReportingCore(createMockConfigSchema(reportingConfig)); diff --git a/x-pack/plugins/reporting/server/lib/store/store.ts b/x-pack/plugins/reporting/server/lib/store/store.ts index 96a3ffacee51c..1a0dcbf16a893 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.ts @@ -87,12 +87,13 @@ export class ReportingStore { private readonly indexInterval: string; // config setting of index prefix: how often to poll for pending work private client?: ElasticsearchClient; private ilmPolicyManager?: IlmPolicyManager; + config: ReportingCore['config']; constructor(private reportingCore: ReportingCore, private logger: Logger) { - const config = reportingCore.getConfig(); + this.config = reportingCore.getConfig(); this.indexPrefix = REPORTING_SYSTEM_INDEX; - this.indexInterval = config.queue.indexInterval; + this.indexInterval = this.config.queue.indexInterval; this.logger = logger.get('store'); } @@ -105,12 +106,8 @@ export class ReportingStore { } private async getIlmPolicyManager() { - if (!this.ilmPolicyManager) { - const client = await this.getClient(); - this.ilmPolicyManager = IlmPolicyManager.create({ client }); - } - - return this.ilmPolicyManager; + const client = await this.getClient(); + return (this.ilmPolicyManager = IlmPolicyManager.create({ client })); } private async createIndex(indexName: string) { @@ -121,10 +118,8 @@ export class ReportingStore { return exists; } - try { - await client.indices.create({ - index: indexName, - body: { + const indexSettings = this.config.statefulSettings.enabled + ? { settings: { number_of_shards: 1, auto_expand_replicas: '0-1', @@ -132,6 +127,14 @@ export class ReportingStore { name: ILM_POLICY_NAME, }, }, + } + : {}; + + try { + await client.indices.create({ + index: indexName, + body: { + ...indexSettings, mappings: { properties: mapping, }, @@ -185,6 +188,9 @@ export class ReportingStore { * configured for storage of reports. */ public async start() { + if (!this.config.statefulSettings.enabled) { + return; + } const ilmPolicyManager = await this.getIlmPolicyManager(); try { if (await ilmPolicyManager.doesIlmPolicyExist()) { diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index 38a7bb8399abb..d96a66bc9b9fd 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -117,6 +117,7 @@ export const createMockConfigSchema = ( csv: { enabled: true }, ...overrides.export_types, }, + statefulSettings: { enabled: true }, } as ReportingConfigType; }; diff --git a/x-pack/plugins/reporting/tsconfig.json b/x-pack/plugins/reporting/tsconfig.json index f307442001655..be183ef08a366 100644 --- a/x-pack/plugins/reporting/tsconfig.json +++ b/x-pack/plugins/reporting/tsconfig.json @@ -41,6 +41,7 @@ "@kbn/saved-search-plugin", "@kbn/core-http-router-server-internal", "@kbn/core-http-common", + "@kbn/react-kibana-context-theme", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts b/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts index f6a394e8c46c9..656deff84ec6d 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts @@ -5488,10 +5488,6 @@ const getAlertsIndexMappings = (): IndexMappings => { index: { auto_expand_replicas: '0-1', hidden: 'true', - lifecycle: { - name: '.alerts-ilm-policy', - rollover_alias: '.alerts-security.alerts-default', - }, mapping: { total_fields: { limit: 1900, diff --git a/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts b/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts index 6c84cd6e5738f..234be86e4aa02 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_loaders/setup_fleet_for_endpoint.ts @@ -21,7 +21,12 @@ import { } from '@kbn/fleet-plugin/common'; import { ToolingLog } from '@kbn/tooling-log'; import { UsageTracker } from './usage_tracker'; -import { EndpointDataLoadingError, retryOnError, wrapErrorAndRejectPromise } from './utils'; +import { + EndpointDataLoadingError, + RETRYABLE_TRANSIENT_ERRORS, + retryOnError, + wrapErrorAndRejectPromise, +} from './utils'; const usageTracker = new UsageTracker({ dumpOnProcessExit: true }); @@ -165,13 +170,7 @@ export const installOrUpgradeEndpointFleetPackage = async ( return bulkResp[0] as BulkInstallPackageInfo; }; - return retryOnError( - updatePackages, - ['no_shard_available_action_exception', 'illegal_index_shard_state_exception'], - logger, - 5, - 10000 - ) + return retryOnError(updatePackages, RETRYABLE_TRANSIENT_ERRORS, logger, 5, 10000) .then((result) => { usageRecord.set('success'); diff --git a/x-pack/plugins/security_solution/common/endpoint/data_loaders/utils.ts b/x-pack/plugins/security_solution/common/endpoint/data_loaders/utils.ts index 0db9fb6f82561..b7f7385a5f119 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_loaders/utils.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_loaders/utils.ts @@ -8,6 +8,11 @@ import { mergeWith } from 'lodash'; import { ToolingLog } from '@kbn/tooling-log'; +export const RETRYABLE_TRANSIENT_ERRORS: Readonly<Array<string | RegExp>> = [ + 'no_shard_available_action_exception', + 'illegal_index_shard_state_exception', +]; + export class EndpointDataLoadingError extends Error { constructor(message: string, public meta?: unknown) { super(message); @@ -43,7 +48,7 @@ export const mergeAndAppendArrays = <T, S>(destinationObj: T, srcObj: S): T => { */ export const retryOnError = async <T>( callback: () => Promise<T>, - errors: Array<string | RegExp>, + errors: Array<string | RegExp> | Readonly<Array<string | RegExp>>, logger?: ToolingLog, tryCount: number = 5, interval: number = 10000 @@ -60,6 +65,8 @@ export const retryOnError = async <T>( }); }; + log.indent(4); + let attempt = 1; let responsePromise: Promise<T>; @@ -71,13 +78,20 @@ export const retryOnError = async <T>( try { responsePromise = callback(); // store promise so that if it fails and no more attempts, we return the last failure - return await responsePromise; + const result = await responsePromise; + + log.info(msg(`attempt ${thisAttempt} was successful. Exiting retry`)); + log.indent(-4); + + return result; } catch (err) { log.info(msg(`attempt ${thisAttempt} failed with: ${err.message}`), err); // If not an error that is retryable, then end loop here and return that error; if (!isRetryableError(err)) { log.error(err); + log.error(msg('non-retryable error encountered')); + log.indent(-4); return Promise.reject(err); } } @@ -85,6 +99,10 @@ export const retryOnError = async <T>( await new Promise((resolve) => setTimeout(resolve, interval)); } + log.error(msg(`max retry attempts reached. returning last failure`)); + log.indent(-4); + + // Last resort: return the last rejected Promise. // @ts-expect-error TS2454: Variable 'responsePromise' is used before being assigned. return responsePromise; }; diff --git a/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.test.ts b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.test.ts new file mode 100644 index 0000000000000..5000244c994a5 --- /dev/null +++ b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.test.ts @@ -0,0 +1,230 @@ +/* + * 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 { defaultGuideTranslations, getSiemGuideConfig, siemGuideId } from './siem_guide_config'; +import * as i18n from './translations'; + +describe('getSiemGuideConfig', () => { + it('returns a GuideConfig object with default values when no arguments are passed', () => { + const result = getSiemGuideConfig(); + expect(result).toEqual({ + title: defaultGuideTranslations.title, + guideName: 'Security', + telemetryId: siemGuideId, + completedGuideRedirectLocation: { + appID: 'securitySolutionUI', + path: '/dashboards', + }, + description: defaultGuideTranslations.description, + docs: { + text: defaultGuideTranslations.docs, + url: 'https://www.elastic.co/guide/en/security/current/ingest-data.html', + }, + steps: [ + { + id: 'add_data', + title: defaultGuideTranslations.steps.add_data.title, + description: { + descriptionText: defaultGuideTranslations.steps.add_data.description, + linkUrl: 'https://docs.elastic.co/en/integrations/endpoint', + isLinkExternal: true, + linkText: i18n.LINK_TEXT, + }, + integration: 'endpoint', + location: { + appID: 'integrations', + path: '/browse/security', + }, + }, + { + id: 'rules', + title: defaultGuideTranslations.steps.rules.title, + description: defaultGuideTranslations.steps.rules.description, + location: { + appID: 'securitySolutionUI', + path: '/rules', + }, + manualCompletion: defaultGuideTranslations.steps.rules.manualCompletion, + }, + { + id: 'alertsCases', + title: defaultGuideTranslations.steps.alertsCases.title, + description: defaultGuideTranslations.steps.alertsCases.description, + location: { + appID: 'securitySolutionUI', + path: '/alerts', + }, + manualCompletion: defaultGuideTranslations.steps.alertsCases.manualCompletion, + }, + ], + }); + }); + + it('returns a GuideConfig object with values from the launchDarkly argument when it is passed', () => { + const launchDarkly = { + title: 'Custom Title', + description: 'Custom Description', + docs: 'Custom Docs', + steps: { + add_data: { + title: 'Custom Add Data Title', + description: 'Custom Add Data Description', + }, + rules: { + title: 'Custom Rules Title', + description: 'Custom Rules Description', + manualCompletion: { + title: 'Custom Rules Manual Title', + description: 'Custom Rules Manual Description', + }, + }, + alertsCases: { + title: 'Custom Alerts Cases Title', + description: 'Custom Alerts Cases Description', + manualCompletion: { + title: 'Custom Alerts Cases Manual Title', + description: 'Custom Alerts Cases Manual Description', + }, + }, + }, + }; + const result = getSiemGuideConfig(launchDarkly); + expect(result).toEqual({ + title: launchDarkly.title, + guideName: 'Security', + telemetryId: siemGuideId, + completedGuideRedirectLocation: { + appID: 'securitySolutionUI', + path: '/dashboards', + }, + description: launchDarkly.description, + docs: { + text: launchDarkly.docs, + url: 'https://www.elastic.co/guide/en/security/current/ingest-data.html', + }, + steps: [ + { + id: 'add_data', + title: launchDarkly.steps.add_data.title, + description: { + descriptionText: launchDarkly.steps.add_data.description, + linkUrl: 'https://docs.elastic.co/en/integrations/endpoint', + isLinkExternal: true, + linkText: i18n.LINK_TEXT, + }, + integration: 'endpoint', + location: { + appID: 'integrations', + path: '/browse/security', + }, + }, + { + id: 'rules', + title: launchDarkly.steps.rules.title, + description: launchDarkly.steps.rules.description, + manualCompletion: { + title: launchDarkly.steps.rules.manualCompletion.title, + description: launchDarkly.steps.rules.manualCompletion.description, + }, + location: { + appID: 'securitySolutionUI', + path: '/rules', + }, + }, + { + id: 'alertsCases', + title: launchDarkly.steps.alertsCases.title, + description: launchDarkly.steps.alertsCases.description, + manualCompletion: { + title: launchDarkly.steps.alertsCases.manualCompletion.title, + description: launchDarkly.steps.alertsCases.manualCompletion.description, + }, + location: { + appID: 'securitySolutionUI', + path: '/alerts', + }, + }, + ], + }); + }); + + it('returns a GuideConfig object with values from the launchDarkly argument and default values when some properties are missing', () => { + const launchDarkly = { + steps: { + add_data: { + title: 'Custom Add Data Title', + }, + rules: { + description: 'Custom Rules Description', + }, + alertsCases: { + manualCompletion: { + title: 'Custom Alerts Cases Manual Title', + }, + }, + }, + }; + // Ignore because intentionally passing an incomplete object to test that we handle missing properties + // since there is no validation on the object from LaunchDarkly + // @ts-ignore + const result = getSiemGuideConfig(launchDarkly); + expect(result).toEqual({ + title: defaultGuideTranslations.title, + guideName: 'Security', + telemetryId: siemGuideId, + completedGuideRedirectLocation: { + appID: 'securitySolutionUI', + path: '/dashboards', + }, + description: defaultGuideTranslations.description, + docs: { + text: defaultGuideTranslations.docs, + url: 'https://www.elastic.co/guide/en/security/current/ingest-data.html', + }, + steps: [ + { + id: 'add_data', + title: launchDarkly.steps.add_data.title, + description: { + descriptionText: defaultGuideTranslations.steps.add_data.description, + linkUrl: 'https://docs.elastic.co/en/integrations/endpoint', + isLinkExternal: true, + linkText: i18n.LINK_TEXT, + }, + integration: 'endpoint', + location: { + appID: 'integrations', + path: '/browse/security', + }, + }, + { + id: 'rules', + title: defaultGuideTranslations.steps.rules.title, + description: launchDarkly.steps.rules.description, + location: { + appID: 'securitySolutionUI', + path: '/rules', + }, + manualCompletion: defaultGuideTranslations.steps.rules.manualCompletion, + }, + { + id: 'alertsCases', + title: defaultGuideTranslations.steps.alertsCases.title, + description: defaultGuideTranslations.steps.alertsCases.description, + manualCompletion: { + title: launchDarkly.steps.alertsCases.manualCompletion.title, + description: defaultGuideTranslations.steps.alertsCases.manualCompletion.description, + }, + location: { + appID: 'securitySolutionUI', + path: '/alerts', + }, + }, + ], + }); + }); +}); diff --git a/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts index 707595d0bd8f8..f260c94262513 100644 --- a/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts +++ b/x-pack/plugins/security_solution/common/guided_onboarding/siem_guide_config.ts @@ -6,50 +6,63 @@ */ import type { GuideConfig } from '@kbn/guided-onboarding'; -import { i18n } from '@kbn/i18n'; +import * as i18n from './translations'; export const siemGuideId = 'siem'; -export const siemGuideConfig: GuideConfig = { - title: i18n.translate('xpack.securitySolution.guideConfig.title', { - defaultMessage: 'Detect threats in my data with SIEM', - }), + +export const defaultGuideTranslations = { + title: i18n.TITLE, + description: i18n.DESCRIPTION, + docs: i18n.DOCS, + steps: { + add_data: { + title: i18n.ADD_DATA_TITLE, + description: i18n.ADD_DATA_DESCRIPTION, + }, + rules: { + title: i18n.RULES_TITLE, + description: i18n.RULES_DESCRIPTION, + manualCompletion: { + title: i18n.RULES_MANUAL_TITLE, + description: i18n.RULES_MANUAL_DESCRIPTION, + }, + }, + alertsCases: { + title: i18n.CASES_TITLE, + description: i18n.CASES_DESCRIPTION, + manualCompletion: { + title: i18n.CASES_MANUAL_TITLE, + description: i18n.CASES_MANUAL_DESCRIPTION, + }, + }, + }, +}; + +export const getSiemGuideConfig = (launchDarkly = defaultGuideTranslations): GuideConfig => ({ + // check each launchDarkly property in case data is misformatted + title: launchDarkly.title ?? defaultGuideTranslations.title, guideName: 'Security', - telemetryId: 'siem', + telemetryId: siemGuideId, completedGuideRedirectLocation: { appID: 'securitySolutionUI', path: '/dashboards', }, - description: i18n.translate('xpack.securitySolution.guideConfig.description', { - defaultMessage: `There are many ways to get your SIEM data into Elastic. In this guide, we'll help you get set up quickly using the Elastic Defend integration.`, - }), + description: launchDarkly.description ?? defaultGuideTranslations.description, docs: { - text: i18n.translate('xpack.securitySolution.guideConfig.documentationLink', { - defaultMessage: 'Learn more', - }), + text: launchDarkly.docs ?? defaultGuideTranslations.docs, url: 'https://www.elastic.co/guide/en/security/current/ingest-data.html', }, steps: [ { id: 'add_data', - title: i18n.translate('xpack.securitySolution.guideConfig.addDataStep.title', { - defaultMessage: 'Add data with Elastic Defend', - }), + title: launchDarkly.steps?.add_data?.title ?? defaultGuideTranslations.steps.add_data.title, description: { - descriptionText: i18n.translate( - 'xpack.securitySolution.guideConfig.addDataStep.description', - { - defaultMessage: - 'Install Elastic Agent and its Elastic Defend integration on one of your computers to get SIEM data flowing.', - } - ), + descriptionText: + launchDarkly.steps?.add_data?.description ?? + defaultGuideTranslations.steps.add_data.description, linkUrl: 'https://docs.elastic.co/en/integrations/endpoint', isLinkExternal: true, - linkText: i18n.translate( - 'xpack.securitySolution.guideConfig.addDataStep.description.linkText', - { - defaultMessage: 'Learn more', - } - ), + linkText: i18n.LINK_TEXT, }, integration: 'endpoint', location: { @@ -59,26 +72,16 @@ export const siemGuideConfig: GuideConfig = { }, { id: 'rules', - title: i18n.translate('xpack.securitySolution.guideConfig.rulesStep.title', { - defaultMessage: 'Turn on rules', - }), - description: i18n.translate('xpack.securitySolution.guideConfig.rulesStep.description', { - defaultMessage: - 'Load the Elastic prebuilt rules, select the rules you want, and enable them to generate alerts.', - }), + title: launchDarkly.steps?.rules?.title ?? defaultGuideTranslations.steps.rules.title, + description: + launchDarkly.steps?.rules?.description ?? defaultGuideTranslations.steps.rules.description, manualCompletion: { - title: i18n.translate( - 'xpack.securitySolution.guideConfig.rulesStep.manualCompletion.title', - { - defaultMessage: 'Continue with the guide', - } - ), - description: i18n.translate( - 'xpack.securitySolution.guideConfig.rulesStep.manualCompletion.description', - { - defaultMessage: `After you've enabled the rules you need, continue.`, - } - ), + title: + launchDarkly.steps?.rules?.manualCompletion?.title ?? + defaultGuideTranslations.steps.rules.manualCompletion.title, + description: + launchDarkly.steps?.rules?.manualCompletion?.description ?? + defaultGuideTranslations.steps.rules.manualCompletion.description, }, location: { appID: 'securitySolutionUI', @@ -87,30 +90,23 @@ export const siemGuideConfig: GuideConfig = { }, { id: 'alertsCases', - title: i18n.translate('xpack.securitySolution.guideConfig.alertsStep.title', { - defaultMessage: 'Manage alerts and cases', - }), - description: i18n.translate('xpack.securitySolution.guideConfig.alertsStep.description', { - defaultMessage: 'Learn how to view and triage alerts with cases.', - }), + title: + launchDarkly.steps?.alertsCases?.title ?? defaultGuideTranslations.steps.alertsCases.title, + description: + launchDarkly.steps?.alertsCases?.description ?? + defaultGuideTranslations.steps.alertsCases.description, location: { appID: 'securitySolutionUI', path: '/alerts', }, manualCompletion: { - title: i18n.translate( - 'xpack.securitySolution.guideConfig.alertsStep.manualCompletion.title', - { - defaultMessage: 'Continue the guide', - } - ), - description: i18n.translate( - 'xpack.securitySolution.guideConfig.alertsStep.manualCompletion.description', - { - defaultMessage: `After you've explored the case, continue.`, - } - ), + title: + launchDarkly.steps?.alertsCases?.manualCompletion?.title ?? + defaultGuideTranslations.steps.alertsCases.manualCompletion.title, + description: + launchDarkly.steps?.alertsCases?.manualCompletion?.description ?? + defaultGuideTranslations.steps.alertsCases.manualCompletion.description, }, }, ], -}; +}); diff --git a/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts b/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts new file mode 100644 index 0000000000000..9d96333796a34 --- /dev/null +++ b/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const TITLE = i18n.translate('xpack.securitySolution.guideConfig.title', { + defaultMessage: 'Detect threats in my data with SIEM', +}); + +export const DESCRIPTION = i18n.translate('xpack.securitySolution.guideConfig.description', { + defaultMessage: `There are many ways to get your SIEM data into Elastic. In this guide, we'll help you get set up quickly using the Elastic Defend integration.`, +}); + +export const DOCS = i18n.translate('xpack.securitySolution.guideConfig.documentationLink', { + defaultMessage: 'Learn more', +}); + +export const LINK_TEXT = i18n.translate( + 'xpack.securitySolution.guideConfig.addDataStep.description.linkText', + { + defaultMessage: 'Learn more', + } +); + +export const ADD_DATA_TITLE = i18n.translate( + 'xpack.securitySolution.guideConfig.addDataStep.title', + { + defaultMessage: 'Add data with Elastic Defend', + } +); + +export const ADD_DATA_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.guideConfig.addDataStep.description', + { + defaultMessage: + 'Install Elastic Agent and its Elastic Defend integration on one of your computers to get SIEM data flowing.', + } +); + +export const RULES_TITLE = i18n.translate('xpack.securitySolution.guideConfig.rulesStep.title', { + defaultMessage: 'Turn on rules', +}); + +export const RULES_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.guideConfig.rulesStep.description', + { + defaultMessage: + 'Load the Elastic prebuilt rules, select the rules you want, and enable them to generate alerts.', + } +); + +export const RULES_MANUAL_TITLE = i18n.translate( + 'xpack.securitySolution.guideConfig.rulesStep.manualCompletion.title', + { + defaultMessage: 'Continue with the guide', + } +); + +export const RULES_MANUAL_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.guideConfig.rulesStep.manualCompletion.description', + { + defaultMessage: `After you've enabled the rules you need, continue.`, + } +); + +export const CASES_TITLE = i18n.translate('xpack.securitySolution.guideConfig.alertsStep.title', { + defaultMessage: 'Manage alerts and cases', +}); +export const CASES_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.guideConfig.alertsStep.description', + { + defaultMessage: 'Learn how to view and triage alerts with cases.', + } +); + +export const CASES_MANUAL_TITLE = i18n.translate( + 'xpack.securitySolution.guideConfig.alertsStep.manualCompletion.title', + { + defaultMessage: 'Continue the guide', + } +); + +export const CASES_MANUAL_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.guideConfig.alertsStep.manualCompletion.description', + { + defaultMessage: `After you've explored the case, continue.`, + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx index 240bb988756f3..6bce996bc14fc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx @@ -9,11 +9,12 @@ import React from 'react'; import { LegacyUrlConflictCallOut } from './legacy_url_conflict_callout'; import { render, screen } from '@testing-library/react'; import type { Rule } from '../../../rule_management/logic'; +import type { SpacesApi } from '@kbn/spaces-plugin/public'; const mockRedirectLegacyUrl = jest.fn(); const mockGetLegacyUrlConflict = jest.fn(); -const mockSpacesApi = { +const mockSpacesApi: SpacesApi = { getActiveSpace$: jest.fn(), getActiveSpace: jest.fn(), ui: { @@ -29,6 +30,7 @@ const mockSpacesApi = { redirectLegacyUrl: mockRedirectLegacyUrl, useSpaces: jest.fn(), }, + hasOnlyDefaultSpace: false, }; describe('<LegacyUrlConflictCallOut />', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts index 454904a251bf4..ee0da0edbfdb9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts @@ -10,11 +10,12 @@ import { renderHook, cleanup } from '@testing-library/react-hooks'; import type { UseLegacyUrlRedirectParams } from './use_redirect_legacy_url'; import { useLegacyUrlRedirect } from './use_redirect_legacy_url'; import type { Rule } from '../../../rule_management/logic'; +import type { SpacesApi } from '@kbn/spaces-plugin/public'; const mockRedirectLegacyUrl = jest.fn(); const mockGetLegacyUrlConflict = jest.fn(); -const mockSpacesApi = { +const mockSpacesApi: SpacesApi = { getActiveSpace$: jest.fn(), getActiveSpace: jest.fn(), ui: { @@ -30,6 +31,7 @@ const mockSpacesApi = { redirectLegacyUrl: mockRedirectLegacyUrl, useSpaces: jest.fn(), }, + hasOnlyDefaultSpace: false, }; describe('useLegacyUrlRedirect', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx index a324c19ff994d..6053b56bf5d5a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/exception_item_card/meta.tsx @@ -22,13 +22,10 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import styled from 'styled-components'; +import { LinkToRuleDetails, LinkToListDetails } from '../../../../exceptions/components'; import * as i18n from './translations'; import { FormattedDate } from '../../../../common/components/formatted_date'; -import { SecurityPageName } from '../../../../../common/constants'; import type { ExceptionListRuleReferencesSchema } from '../../../../../common/api/detection_engine/rule_exceptions'; -import { SecuritySolutionLinkAnchor } from '../../../../common/components/links'; -import { RuleDetailTabs } from '../../../rule_details_ui/pages/rule_details/use_rule_details_tabs'; -import { getRuleDetailsTabUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; const StyledFlexItem = styled(EuiFlexItem)` border-right: 1px solid #d3dae6; @@ -66,14 +63,7 @@ export const ExceptionItemCardMetaInfo = memo<ExceptionItemCardMetaInfoProps>( key={reference.id} > <EuiToolTip content={reference.name} anchorClassName="eui-textTruncate"> - <SecuritySolutionLinkAnchor - data-test-subj="ruleName" - deepLinkId={SecurityPageName.rules} - path={getRuleDetailsTabUrl(reference.id, RuleDetailTabs.alerts)} - external - > - {reference.name} - </SecuritySolutionLinkAnchor> + <LinkToRuleDetails external referenceId={reference.id} referenceName={reference.name} /> </EuiToolTip> </EuiContextMenuItem> )); @@ -136,15 +126,12 @@ export const ExceptionItemCardMetaInfo = memo<ExceptionItemCardMetaInfoProps>( key={listAndReferences.id} > <EuiToolTip content={listAndReferences.name} anchorClassName="eui-textTruncate"> - <SecuritySolutionLinkAnchor - data-test-subj="ruleName" - deepLinkId={SecurityPageName.exceptions} - // TODO: Update to list details URL once available - path={`/details/${listAndReferences?.list_id}`} + <LinkToListDetails + dataTestSubj="link-to-exception-list" + linkTitle={listAndReferences.name} + listId={listAndReferences?.list_id} external - > - {listAndReferences.name} - </SecuritySolutionLinkAnchor> + /> </EuiToolTip> </EuiContextMenuItem>, ]} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx index 1b6f7bcb069b1..e963c8d7707f9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/linked_to_rule/index.test.tsx @@ -24,8 +24,7 @@ describe('ExceptionsLinkedToRule', () => { /> </TestProviders> ); - expect(wrapper.find('[data-test-subj="ruleNameCell"]').at(0).text()).toEqual('NameMy rule'); - expect(wrapper.find('[data-test-subj="ruleAction-viewDetails"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="linkToRuleSecuritySolutionLink"]').exists()).toBeTruthy(); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx index 712da253477ab..0a92a46592dfd 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx @@ -20,8 +20,6 @@ import { generateLinkedRulesMenuItems, } from '@kbn/securitysolution-exception-list-components'; import { PopoverItems } from '../../../../common/components/popover_items'; -import { SecurityPageName } from '../../../../../common/constants'; -import { ListDetailsLinkAnchor } from '../../../../exceptions/components'; import { enrichExceptionItemsWithOS, enrichNewExceptionItemsWithComments, @@ -31,14 +29,12 @@ import { enrichSharedExceptions, lowercaseHashValues, } from '../../utils/helpers'; -import { SecuritySolutionLinkAnchor } from '../../../../common/components/links'; -import { getRuleDetailsTabUrl } from '../../../../common/components/link_to/redirect_to_detection_engine'; -import { RuleDetailTabs } from '../../../rule_details_ui/pages/rule_details/use_rule_details_tabs'; import type { ExceptionListRuleReferencesInfoSchema, ExceptionListRuleReferencesSchema, } from '../../../../../common/api/detection_engine/rule_exceptions'; import type { Rule } from '../../../rule_management/logic/types'; +import { LinkToRuleDetails, LinkToListDetails } from '../../../../exceptions/components'; import * as i18n from './translations'; /** @@ -222,7 +218,7 @@ export const getSharedListsTableColumns = () => [ actions={generateLinkedRulesMenuItems({ dataTestSubj: 'addToSharedListsLinkedRulesMenu', linkedRules: references, - securityLinkAnchorComponent: ListDetailsLinkAnchor, + securityLinkAnchorComponent: LinkToRuleDetails, })} panelPaddingSize="none" disableActions={false} @@ -237,14 +233,12 @@ export const getSharedListsTableColumns = () => [ 'data-test-subj': 'exceptionListRulesActionCell', render: (list: ExceptionListRuleReferencesSchema) => { return ( - <SecuritySolutionLinkAnchor - data-test-subj="exceptionListActionCell-link" - deepLinkId={SecurityPageName.exceptions} - path={`/details/${list.list_id}`} + <LinkToListDetails + dataTestSubj="exceptionListActionCell-link" + linkTitle={i18n.VIEW_LIST_DETAIL_ACTION} + listId={list.list_id} external - > - {i18n.VIEW_LIST_DETAIL_ACTION} - </SecuritySolutionLinkAnchor> + /> ); }, }, @@ -294,14 +288,11 @@ export const getRulesTableColumn = () => [ 'data-test-subj': 'ruleAction-view', render: (rule: Rule) => { return ( - <SecuritySolutionLinkAnchor - data-test-subj="ruleAction-viewDetails" - deepLinkId={SecurityPageName.rules} - path={getRuleDetailsTabUrl(rule.id, RuleDetailTabs.alerts)} + <LinkToRuleDetails external - > - {i18n.VIEW_RULE_DETAIL_ACTION} - </SecuritySolutionLinkAnchor> + referenceId={rule.id} + referenceName={i18n.VIEW_RULE_DETAIL_ACTION} + /> ); }, }, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.tsx index 791a4b9872fb5..1bf260aff69ed 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.tsx @@ -295,6 +295,9 @@ export const RulesTableContextProvider = ({ children }: RulesTableContextProvide pagination, }, { + // We don't need refreshes on windows focus and reconnects if auto-refresh if off + refetchOnWindowFocus: isRefreshOn && !isActionInProgress, + refetchOnReconnect: isRefreshOn && !isActionInProgress, refetchInterval: isRefreshOn && !isActionInProgress && autoRefreshSettings.value, keepPreviousData: true, // Use this option so that the state doesn't jump between "success" and "loading" on page change } diff --git a/x-pack/plugins/security_solution/public/exceptions/components/index.ts b/x-pack/plugins/security_solution/public/exceptions/components/index.ts index 8de30af731151..66d203327cc37 100644 --- a/x-pack/plugins/security_solution/public/exceptions/components/index.ts +++ b/x-pack/plugins/security_solution/public/exceptions/components/index.ts @@ -8,7 +8,8 @@ export * from './create_shared_exception_list'; export * from './exceptions_list_card'; export * from './exceptions_utility'; export * from './import_exceptions_list_flyout'; -export * from './list_details_link_anchor'; +export * from './link_to_rule_details'; +export * from './link_to_list_details'; export * from './list_exception_items'; export * from './list_with_search'; export * from './manage_rules'; diff --git a/x-pack/plugins/security_solution/public/exceptions/components/link_to_list_details/index.tsx b/x-pack/plugins/security_solution/public/exceptions/components/link_to_list_details/index.tsx new file mode 100644 index 0000000000000..20e99dc7de60b --- /dev/null +++ b/x-pack/plugins/security_solution/public/exceptions/components/link_to_list_details/index.tsx @@ -0,0 +1,45 @@ +/* + * 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 type { FC } from 'react'; + +import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; +import { SecurityPageName } from '../../../../common/constants'; + +interface LinkToListDetailsProps { + linkTitle: string; + listId: string; + external?: boolean; + dataTestSubj?: string; +} +// This component should be removed and moved to @kbn/securitysolution-exception-list-components +// once all the building components get moved + +const LinkToListDetailsComponent: FC<LinkToListDetailsProps> = ({ + linkTitle, + listId, + external, + dataTestSubj, +}) => { + return ( + <SecuritySolutionLinkAnchor + data-test-subj={`linkToRuleSecuritySolutionLink${dataTestSubj ?? ''}`} + deepLinkId={SecurityPageName.exceptions} + path={`/details/${listId}`} + target={external ? '_blank' : undefined} + > + {linkTitle} + </SecuritySolutionLinkAnchor> + ); +}; + +LinkToListDetailsComponent.displayName = 'LinkToListDetailsComponent'; + +export const LinkToListDetails = React.memo(LinkToListDetailsComponent); + +LinkToListDetails.displayName = 'LinkToListDetails'; diff --git a/x-pack/plugins/security_solution/public/exceptions/components/list_details_link_anchor/index.tsx b/x-pack/plugins/security_solution/public/exceptions/components/link_to_rule_details/index.tsx similarity index 68% rename from x-pack/plugins/security_solution/public/exceptions/components/list_details_link_anchor/index.tsx rename to x-pack/plugins/security_solution/public/exceptions/components/link_to_rule_details/index.tsx index 4b54600fc454d..d2526f6fdef03 100644 --- a/x-pack/plugins/security_solution/public/exceptions/components/list_details_link_anchor/index.tsx +++ b/x-pack/plugins/security_solution/public/exceptions/components/link_to_rule_details/index.tsx @@ -7,34 +7,41 @@ import React from 'react'; import type { FC } from 'react'; + +import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; import { RuleDetailTabs } from '../../../detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs'; import { SecurityPageName } from '../../../../common/constants'; import { getRuleDetailsTabUrl } from '../../../common/components/link_to/redirect_to_detection_engine'; -import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; -interface LinkAnchorProps { +interface LinkToRuleDetailsProps { referenceName: string; referenceId: string; external?: boolean; + dataTestSubj?: string; } // This component should be removed and moved to @kbn/securitysolution-exception-list-components // once all the building components get moved -const LinkAnchor: FC<LinkAnchorProps> = ({ referenceName, referenceId, external }) => { +const LinkToRuleDetailsComponent: FC<LinkToRuleDetailsProps> = ({ + referenceName, + referenceId, + external, + dataTestSubj, +}) => { return ( <SecuritySolutionLinkAnchor - data-test-subj="SecuritySolutionLinkAnchor" + data-test-subj={`linkToRuleSecuritySolutionLink${dataTestSubj ?? ''}`} deepLinkId={SecurityPageName.rules} path={getRuleDetailsTabUrl(referenceId, RuleDetailTabs.alerts)} - external={external} + target={external ? '_blank' : undefined} > {referenceName} </SecuritySolutionLinkAnchor> ); }; -LinkAnchor.displayName = 'LinkAnchor'; +LinkToRuleDetailsComponent.displayName = 'LinkToRuleDetailsComponent'; -export const ListDetailsLinkAnchor = React.memo(LinkAnchor); +export const LinkToRuleDetails = React.memo(LinkToRuleDetailsComponent); -ListDetailsLinkAnchor.displayName = 'ListDetailsLinkAnchor'; +LinkToRuleDetails.displayName = 'LinkToRuleDetails'; diff --git a/x-pack/plugins/security_solution/public/exceptions/components/list_exception_items/index.tsx b/x-pack/plugins/security_solution/public/exceptions/components/list_exception_items/index.tsx index ee45e7414184f..1b1b6ad36d1ea 100644 --- a/x-pack/plugins/security_solution/public/exceptions/components/list_exception_items/index.tsx +++ b/x-pack/plugins/security_solution/public/exceptions/components/list_exception_items/index.tsx @@ -19,7 +19,7 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t import type { Pagination } from '@elastic/eui'; import { FormattedDate } from '../../../common/components/formatted_date'; import { getFormattedComments } from '../../utils/ui.helpers'; -import { ListDetailsLinkAnchor } from '../list_details_link_anchor'; +import { LinkToRuleDetails } from '../link_to_rule_details'; import { ExceptionsUtility } from '../exceptions_utility'; import * as i18n from '../../translations/list_exception_items'; @@ -89,7 +89,7 @@ const ListExceptionItemsComponent: FC<ListExceptionItemsProps> = ({ onEditExceptionItem={onEditExceptionItem} onDeleteException={onDeleteException} getFormattedComments={getFormattedComments} - securityLinkAnchorComponent={ListDetailsLinkAnchor} + securityLinkAnchorComponent={LinkToRuleDetails} formattedDateComponent={FormattedDate} onCreateExceptionListItem={onCreateExceptionListItem} exceptionsUtilityComponent={() => diff --git a/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx b/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx index 4272632d28a10..c153f1e983b0a 100644 --- a/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx +++ b/x-pack/plugins/security_solution/public/exceptions/pages/list_detail_view/index.tsx @@ -22,7 +22,7 @@ import type { Rule } from '../../../detection_engine/rule_management/logic/types import { MissingPrivilegesCallOut } from '../../../detections/components/callouts/missing_privileges_callout'; import { NotFoundPage } from '../../../app/404'; import { AutoDownload } from '../../../common/components/auto_download/auto_download'; -import { ListWithSearch, ManageRules, ListDetailsLinkAnchor } from '../../components'; +import { ListWithSearch, ManageRules, LinkToRuleDetails } from '../../components'; import { useListDetailsView } from '../../hooks'; import * as i18n from '../../translations'; import type { CheckExceptionTtlActionTypes } from '../../components/expired_exceptions_list_items_modal'; @@ -109,7 +109,7 @@ export const ListsDetailViewComponent: FC = () => { isReadonly={isReadOnly} canUserEditList={canUserEditList} backOptions={headerBackOptions} - securityLinkAnchorComponent={ListDetailsLinkAnchor} + securityLinkAnchorComponent={LinkToRuleDetails} onEditListDetails={onEditListDetails} onExportList={handleExportList} onDeleteList={handleDelete} diff --git a/x-pack/plugins/security_solution/public/flyout/isolate_host/header.test.tsx b/x-pack/plugins/security_solution/public/flyout/isolate_host/header.test.tsx new file mode 100644 index 0000000000000..fa4b57a4313fa --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/isolate_host/header.test.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; 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 { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import { useIsolateHostPanelContext } from './context'; +import { PanelHeader } from './header'; +import { FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids'; + +jest.mock('./context'); + +const renderPanelHeader = () => + render( + <IntlProvider locale="en"> + <PanelHeader /> + </IntlProvider> + ); + +describe('<PanelHeader />', () => { + (useIsolateHostPanelContext as jest.Mock).mockReturnValue({ isolateAction: 'isolateHost' }); + + it('should display isolate host message', () => { + const { getByTestId } = renderPanelHeader(); + + expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent('Isolate host'); + }); + + it('should display release host message', () => { + (useIsolateHostPanelContext as jest.Mock).mockReturnValue({ isolateAction: 'unisolateHost' }); + + const { getByTestId } = renderPanelHeader(); + + expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent('Release host'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/isolate_host/header.tsx b/x-pack/plugins/security_solution/public/flyout/isolate_host/header.tsx index 168175878d802..0e5ef2e309b69 100644 --- a/x-pack/plugins/security_solution/public/flyout/isolate_host/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/isolate_host/header.tsx @@ -8,9 +8,9 @@ import { EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import type { FC } from 'react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useIsolateHostPanelContext } from './context'; import { FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids'; -import { PANEL_HEADER_ISOLATE_TITLE, PANEL_HEADER_RELEASE_TITLE } from './translations'; /** * Document details expandable right section header for the isolate host panel @@ -19,7 +19,17 @@ export const PanelHeader: FC = () => { const { isolateAction } = useIsolateHostPanelContext(); const title = - isolateAction === 'isolateHost' ? PANEL_HEADER_ISOLATE_TITLE : PANEL_HEADER_RELEASE_TITLE; + isolateAction === 'isolateHost' ? ( + <FormattedMessage + id="xpack.securitySolution.flyout.isolateHost.isolateTitle" + defaultMessage="Isolate host" + /> + ) : ( + <FormattedMessage + id="xpack.securitySolution.flyout.isolateHost.releaseTitle" + defaultMessage="Release host" + /> + ); return ( <EuiFlyoutHeader hasBorder> diff --git a/x-pack/plugins/security_solution/public/flyout/isolate_host/translations.ts b/x-pack/plugins/security_solution/public/flyout/isolate_host/translations.ts deleted file mode 100644 index 84ec8d62c09de..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/isolate_host/translations.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const PANEL_HEADER_ISOLATE_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.isolateHostPanelHeaderIsolateTitle', - { - defaultMessage: `Isolate host`, - } -); - -export const PANEL_HEADER_RELEASE_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.isolateHostPanelHeaderReleaseTitle', - { - defaultMessage: `Release host`, - } -); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx index dcd8c5884c6fb..2bbfa8f4ab7c5 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.test.tsx @@ -20,8 +20,8 @@ import { CORRELATIONS_DETAILS_BY_SESSION_SECTION_TABLE_TEST_ID, CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TABLE_TEST_ID, CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID, + CORRELATIONS_DETAILS_NO_DATA_TEST_ID, CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_SECTION_TEST_ID, - CORRELATIONS_DETAILS_TEST_ID, } from './test_ids'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; @@ -102,13 +102,14 @@ describe('CorrelationsDetails', () => { dataCount: 1, }); - const { getByTestId } = renderCorrelationDetails(); + const { getByTestId, queryByTestId } = renderCorrelationDetails(); expect(getByTestId(CORRELATIONS_DETAILS_BY_ANCESTRY_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_BY_SESSION_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); expect(getByTestId(CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_TITLE_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(CORRELATIONS_DETAILS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render no section and show error message if show values are false', () => { @@ -139,7 +140,10 @@ describe('CorrelationsDetails', () => { expect( queryByTestId(CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_TITLE_TEST_ID) ).not.toBeInTheDocument(); - expect(getByTestId(`${CORRELATIONS_DETAILS_TEST_ID}Error`)).toBeInTheDocument(); + expect(getByTestId(CORRELATIONS_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(CORRELATIONS_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( + 'No correlations data available.' + ); }); it('should render no section if values are null', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx index 0e6e927779710..f7def1d23ac98 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details.tsx @@ -7,8 +7,8 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { CORRELATIONS_ERROR_MESSAGE } from './translations'; -import { CORRELATIONS_DETAILS_TEST_ID } from './test_ids'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { CORRELATIONS_DETAILS_NO_DATA_TEST_ID } from './test_ids'; import { RelatedAlertsBySession } from './related_alerts_by_session'; import { RelatedAlertsBySameSourceEvent } from './related_alerts_by_same_source_event'; import { RelatedCases } from './related_cases'; @@ -98,9 +98,12 @@ export const CorrelationsDetails: React.FC = () => { )} </EuiFlexGroup> ) : ( - <div data-test-subj={`${CORRELATIONS_DETAILS_TEST_ID}Error`}> - {CORRELATIONS_ERROR_MESSAGE} - </div> + <p data-test-subj={CORRELATIONS_DETAILS_NO_DATA_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.noDataDescription" + defaultMessage="No correlations data available." + /> + </p> )} </> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.test.tsx index 3d36a54e728e2..250889402e455 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.test.tsx @@ -67,7 +67,7 @@ describe('CorrelationsDetailsAlertsTable', () => { const { getByTestId } = render( <TestProviders> <CorrelationsDetailsAlertsTable - title={'title'} + title={<p>{'title'}</p>} loading={false} alertIds={alertIds} scopeId={scopeId} diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx index 4099db06d6c5a..0f113efe317aa 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/correlations_details_alerts_table.tsx @@ -5,17 +5,18 @@ * 2.0. */ -import type { ReactNode } from 'react'; +import type { ReactElement, ReactNode } from 'react'; import React, { type FC, useMemo, useCallback } from 'react'; import { type Criteria, EuiBasicTable, formatDate } from '@elastic/eui'; import { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; import type { Filter } from '@kbn/es-query'; import { isRight } from 'fp-ts/lib/Either'; import { ALERT_REASON, ALERT_RULE_NAME } from '@kbn/rule-data-utils'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; import type { DataProvider } from '../../../../common/types'; import { SeverityBadge } from '../../../detections/components/rules/severity_badge'; import { usePaginatedAlerts } from '../hooks/use_paginated_alerts'; -import * as i18n from './translations'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { InvestigateInTimelineButton } from '../../../common/components/event_details/table/investigate_in_timeline_button'; import { ACTION_INVESTIGATE_IN_TIMELINE } from '../../../detections/components/alerts_table/translations'; @@ -27,24 +28,44 @@ const dataProviderLimit = 5; export const columns = [ { field: '@timestamp', - name: i18n.CORRELATIONS_TIMESTAMP_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.timestampColumnLabel" + defaultMessage="Timestamp" + /> + ), truncateText: true, dataType: 'date' as const, render: (value: string) => formatDate(value, TIMESTAMP_DATE_FORMAT), }, { field: ALERT_RULE_NAME, - name: i18n.CORRELATIONS_RULE_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.ruleColumnLabel" + defaultMessage="Rule" + /> + ), truncateText: true, }, { field: ALERT_REASON, - name: i18n.CORRELATIONS_REASON_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.reasonColumnLabel" + defaultMessage="Reason" + /> + ), truncateText: true, }, { field: 'kibana.alert.severity', - name: i18n.CORRELATIONS_SEVERITY_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.severityColumnLabel" + defaultMessage="Severity" + /> + ), truncateText: true, render: (value: string) => { const decodedSeverity = Severity.decode(value); @@ -57,7 +78,7 @@ export interface CorrelationsDetailsAlertsTableProps { /** * Text to display in the ExpandablePanel title section */ - title: string; + title: ReactElement; /** * Whether the table is loading */ @@ -188,7 +209,12 @@ const getFilters = (alertIds?: string[]) => { return [ { meta: { - alias: i18n.CORRELATIONS_DETAILS_TABLE_FILTER, + alias: i18n.translate( + 'xpack.securitySolution.flyout.left.insights.correlations.tableFilterLabel', + { + defaultMessage: 'Correlations Details Table Alert IDs.', + } + ), type: 'phrases', key: '_id', params: [...alertIds], diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx index eb56069bb7646..a4a1e9de5f62e 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.test.tsx @@ -42,7 +42,7 @@ const HOST_TEST_ID = EXPANDABLE_PANEL_CONTENT_TEST_ID(HOST_DETAILS_TEST_ID); describe('<EntitiesDetails />', () => { it('renders entities details correctly', () => { - const { getByTestId } = render( + const { getByTestId, queryByTestId } = render( <TestProviders> <LeftPanelContext.Provider value={mockContextValue}> <EntitiesDetails /> @@ -52,6 +52,7 @@ describe('<EntitiesDetails />', () => { expect(getByTestId(ENTITIES_DETAILS_TEST_ID)).toBeInTheDocument(); expect(getByTestId(USER_TEST_ID)).toBeInTheDocument(); expect(getByTestId(HOST_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render no data message if user name and host name are not available', () => { @@ -69,6 +70,9 @@ describe('<EntitiesDetails />', () => { </TestProviders> ); expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( + 'Host and user information are unavailable for this alert.' + ); expect(queryByTestId(USER_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(HOST_TEST_ID)).not.toBeInTheDocument(); }); @@ -96,6 +100,9 @@ describe('<EntitiesDetails />', () => { </TestProviders> ); expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ENTITIES_DETAILS_NO_DATA_TEST_ID)).toHaveTextContent( + 'Host and user information are unavailable for this alert.' + ); expect(queryByTestId(USER_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(HOST_TEST_ID)).not.toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx index ff3678a06e428..78ee648581162 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/entities_details.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { ENTITIES_NO_DATA_MESSAGE } from './translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useLeftPanelContext } from '../context'; import { getField } from '../../shared/utils'; import { UserDetails } from './user_details'; @@ -45,7 +45,12 @@ export const EntitiesDetails: React.FC = () => { )} </EuiFlexGroup> ) : ( - <div data-test-subj={ENTITIES_DETAILS_NO_DATA_TEST_ID}>{ENTITIES_NO_DATA_MESSAGE}</div> + <p data-test-subj={ENTITIES_DETAILS_NO_DATA_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.noDataDescription" + defaultMessage="Host and user information are unavailable for this alert." + /> + </p> )} </> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/host_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/host_details.tsx index 5941c39cb8c8d..2bccfbc8ac34b 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/host_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/host_details.tsx @@ -20,6 +20,7 @@ import { EuiPanel, } from '@elastic/eui'; import type { EuiBasicTableColumn } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { getSourcererScopeId } from '../../../helpers'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import type { RelatedUser } from '../../../../common/search_strategy/security_solution/related_entities/related_users'; @@ -50,7 +51,6 @@ import { getEmptyTagValue } from '../../../common/components/empty_value'; import { HOST_DETAILS_TEST_ID, HOST_DETAILS_RELATED_USERS_TABLE_TEST_ID } from './test_ids'; import { ENTITY_RISK_CLASSIFICATION } from '../../../explore/components/risk_score/translations'; import { USER_RISK_TOOLTIP } from '../../../explore/users/components/all_users/translations'; -import * as i18n from './translations'; import { useHasSecurityCapability } from '../../../helper_hooks'; const HOST_DETAILS_ID = 'entities-hosts-details'; @@ -128,7 +128,12 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s () => [ { field: 'user', - name: i18n.RELATED_ENTITIES_NAME_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedUsersNameColumnLabel" + defaultMessage="Name" + /> + ), render: (user: string) => ( <EuiText grow={false} size="xs"> <SecurityCellActions @@ -150,7 +155,12 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s }, { field: 'ip', - name: i18n.RELATED_ENTITIES_IP_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedUsersIpColumnLabel" + defaultMessage="Ip addresses" + /> + ), render: (ips: string[]) => { return ( <DefaultFieldRenderer @@ -199,7 +209,13 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s </EuiFlexItem> <EuiFlexItem grow={false}> <EuiTitle size="xxxs"> - <EuiText>{`${i18n.RELATED_USERS_TITLE}: ${totalCount}`}</EuiText> + <EuiText> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedUsersCountLabel" + defaultMessage="Related users: {count}" + values={{ count: totalCount }} + /> + </EuiText> </EuiTitle> </EuiFlexItem> </EuiFlexGroup> @@ -215,7 +231,12 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s return ( <> <EuiTitle size="xs"> - <h4>{i18n.HOST_TITLE}</h4> + <h4> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.hostDetailsTitle" + defaultMessage="Host" + /> + </h4> </EuiTitle> <EuiSpacer size="s" /> <ExpandablePanel @@ -228,7 +249,12 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s data-test-subj={HOST_DETAILS_TEST_ID} > <EuiTitle size="xxs"> - <h5>{i18n.HOSTS_INFO_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.hostDetailsInfoTitle" + defaultMessage="Host information" + /> + </h5> </EuiTitle> <EuiSpacer size="s" /> <AnomalyTableProvider @@ -263,11 +289,24 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s <EuiFlexGroup direction="row" gutterSize="xs" alignItems="center"> <EuiFlexItem grow={false}> <EuiTitle size="xxs"> - <h5>{i18n.RELATED_USERS_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedUsersTitle" + defaultMessage="Related users" + /> + </h5> </EuiTitle> </EuiFlexItem> <EuiFlexItem grow={false}> - <EuiToolTip content={i18n.RELATED_USERS_TOOL_TIP(hostName)}> + <EuiToolTip + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedUsersTooltip" + defaultMessage="After this alert was generated, these users logged into {hostName}. Check if this activity is normal." + values={{ hostName }} + /> + } + > <EuiIcon color="subdued" type="iInCircle" className="eui-alignTop" /> </EuiToolTip> </EuiFlexItem> @@ -287,11 +326,21 @@ export const HostDetails: React.FC<HostDetailsProps> = ({ hostName, timestamp, s loading={isRelatedUsersLoading} data-test-subj={HOST_DETAILS_RELATED_USERS_TABLE_TEST_ID} pagination={pagination} - message={i18n.RELATED_USERS_TABLE_NO_DATA} + message={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedUsersNoDataDescription" + defaultMessage="No users identified" + /> + } /> <InspectButton queryId={relatedUsersQueryId} - title={i18n.RELATED_USERS_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedUsersInspectButtonTitle" + defaultMessage="Related users" + /> + } inspectIndex={0} /> </RelatedUsersManage> diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx index b5a7f229b9979..37d91600bbe5e 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.test.tsx @@ -55,6 +55,9 @@ describe('<InvestigationGuide />', () => { }); const { getByTestId } = render(renderInvestigationGuide()); expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( + `There’s no investigation guide for this rule. Edit the rule's settingsExternal link(opens in a new tab or window) to add one.` + ); }); it('should render no data message when there is no rule note', () => { @@ -64,6 +67,9 @@ describe('<InvestigationGuide />', () => { }); const { getByTestId } = render(renderInvestigationGuide()); expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( + `There’s no investigation guide for this rule. Edit the rule's settingsExternal link(opens in a new tab or window) to add one.` + ); }); it('should render no data message when useInvestigationGuide errors out', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx index 8cf39210bbac7..1152e11df6ba6 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/investigation_guide.tsx @@ -49,9 +49,9 @@ export const InvestigationGuide: React.FC = () => { showFullView={true} /> ) : ( - <div data-test-subj={INVESTIGATION_GUIDE_NO_DATA_TEST_ID}> + <p data-test-subj={INVESTIGATION_GUIDE_NO_DATA_TEST_ID}> <FormattedMessage - id="xpack.securitySolution.flyout.investigationGuideNoData" + id="xpack.securitySolution.flyout.left.investigation.noDataDescription" defaultMessage="There’s no investigation guide for this rule. {documentation} to add one." values={{ documentation: ( @@ -60,14 +60,14 @@ export const InvestigationGuide: React.FC = () => { target="_blank" > <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.investigationGuideDocumentationLink" + id="xpack.securitySolution.flyout.left.investigation.noDataLinkText" defaultMessage="Edit the rule's settings" /> </EuiLink> ), }} /> - </div> + </p> )} </> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx index 233eb7c22371e..45cde1423ba4f 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx @@ -17,6 +17,7 @@ import { PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID, PREVALENCE_DETAILS_TABLE_TEST_ID, + PREVALENCE_DETAILS_TABLE_UPSELL_TEST_ID, PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID, } from './test_ids'; @@ -53,6 +54,15 @@ const panelContextValue = { dataFormattedForFieldBrowser: [], } as unknown as LeftPanelContext; +const renderPrevalenceDetails = () => + render( + <TestProviders> + <LeftPanelContext.Provider value={panelContextValue}> + <PrevalenceDetails /> + </LeftPanelContext.Provider> + </TestProviders> + ); + describe('PrevalenceDetails', () => { const licenseServiceMock = licenseService as jest.Mocked<typeof licenseService>; @@ -86,13 +96,7 @@ describe('PrevalenceDetails', () => { ], }); - const { getByTestId, getAllByTestId, queryByTestId } = render( - <TestProviders> - <LeftPanelContext.Provider value={panelContextValue}> - <PrevalenceDetails /> - </LeftPanelContext.Provider> - </TestProviders> - ); + const { getByTestId, getAllByTestId, queryByTestId } = renderPrevalenceDetails(); expect(getByTestId(PREVALENCE_DETAILS_TABLE_TEST_ID)).toBeInTheDocument(); expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID).length).toBeGreaterThan(1); @@ -109,7 +113,8 @@ describe('PrevalenceDetails', () => { expect( getAllByTestId(PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID).length ).toBeGreaterThan(1); - expect(queryByTestId(`${PREVALENCE_DETAILS_TABLE_TEST_ID}UpSell`)).not.toBeInTheDocument(); + expect(queryByTestId(PREVALENCE_DETAILS_TABLE_UPSELL_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render formatted numbers for the alert and document count columns', () => { @@ -176,13 +181,7 @@ describe('PrevalenceDetails', () => { }); licenseServiceMock.isPlatinumPlus.mockReturnValue(false); - const { getByTestId, getAllByTestId } = render( - <TestProviders> - <LeftPanelContext.Provider value={panelContextValue}> - <PrevalenceDetails /> - </LeftPanelContext.Provider> - </TestProviders> - ); + const { getByTestId, getAllByTestId } = renderPrevalenceDetails(); expect(getByTestId(PREVALENCE_DETAILS_TABLE_TEST_ID)).toBeInTheDocument(); expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID).length).toBeGreaterThan(1); @@ -199,7 +198,7 @@ describe('PrevalenceDetails', () => { expect( getAllByTestId(PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID).length ).toBeGreaterThan(1); - expect(getByTestId(`${PREVALENCE_DETAILS_TABLE_TEST_ID}UpSell`)).toBeInTheDocument(); + expect(getByTestId(PREVALENCE_DETAILS_TABLE_UPSELL_TEST_ID)).toBeInTheDocument(); }); it('should render loading', () => { @@ -209,13 +208,11 @@ describe('PrevalenceDetails', () => { data: [], }); - const { getByTestId } = render( - <LeftPanelContext.Provider value={panelContextValue}> - <PrevalenceDetails /> - </LeftPanelContext.Provider> - ); + const { getByTestId, queryByTestId } = renderPrevalenceDetails(); expect(getByTestId(PREVALENCE_DETAILS_LOADING_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(PREVALENCE_DETAILS_TABLE_UPSELL_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render no data message if call errors out', () => { @@ -225,12 +222,28 @@ describe('PrevalenceDetails', () => { data: [], }); - const { getByTestId } = render( - <LeftPanelContext.Provider value={panelContextValue}> - <PrevalenceDetails /> - </LeftPanelContext.Provider> + const { getByTestId, queryByTestId } = renderPrevalenceDetails(); + + expect(getByTestId(PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID)).toHaveTextContent( + 'No prevalence data available.' ); + expect(queryByTestId(PREVALENCE_DETAILS_LOADING_TEST_ID)).not.toBeInTheDocument(); + }); - expect(getByTestId(`${PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID}Error`)).toBeInTheDocument(); + it('should render no data message if no data', () => { + (usePrevalence as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + }); + + const { getByTestId, queryByTestId } = renderPrevalenceDetails(); + + expect(getByTestId(PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID)).toHaveTextContent( + 'No prevalence data available.' + ); + expect(queryByTestId(PREVALENCE_DETAILS_LOADING_TEST_ID)).not.toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx index cd4283613a453..4c1865738ce0c 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx @@ -27,21 +27,6 @@ import { useLicense } from '../../../common/hooks/use_license'; import { InvestigateInTimelineButton } from '../../../common/components/event_details/table/investigate_in_timeline_button'; import type { PrevalenceData } from '../../shared/hooks/use_prevalence'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; -import { - HOST_TITLE, - PREVALENCE_TABLE_ALERT_COUNT_COLUMN_TITLE, - PREVALENCE_TABLE_COUNT_COLUMN_TITLE, - PREVALENCE_TABLE_DOC_COUNT_COLUMN_TITLE, - PREVALENCE_TABLE_VALUE_COLUMN_TITLE, - PREVALENCE_TABLE_PREVALENCE_COLUMN_TITLE, - PREVALENCE_TABLE_FIELD_COLUMN_TITLE, - USER_TITLE, - PREVALENCE_NO_DATA_MESSAGE, - PREVALENCE_TABLE_ALERT_COUNT_COLUMN_TITLE_TOOLTIP, - PREVALENCE_TABLE_DOC_COUNT_COLUMN_TITLE_TOOLTIP, - HOST_PREVALENCE_COLUMN_TITLE_TOOLTIP, - USER_PREVALENCE_COLUMN_TITLE_TOOLTIP, -} from './translations'; import { PREVALENCE_DETAILS_LOADING_TEST_ID, PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID, @@ -53,6 +38,7 @@ import { PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID, PREVALENCE_DETAILS_DATE_PICKER_TEST_ID, PREVALENCE_DETAILS_TABLE_TEST_ID, + PREVALENCE_DETAILS_TABLE_UPSELL_TEST_ID, } from './test_ids'; import { useLeftPanelContext } from '../context'; import { @@ -80,24 +66,51 @@ interface PrevalenceDetailsRow extends PrevalenceData { const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [ { field: 'field', - name: PREVALENCE_TABLE_FIELD_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.fieldColumnLabel" + defaultMessage="Field" + /> + ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID, render: (field: string) => <EuiText size="xs">{field}</EuiText>, width: '20%', }, { field: 'value', - name: PREVALENCE_TABLE_VALUE_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.valueColumnLabel" + defaultMessage="Value" + /> + ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID, render: (value: string) => <EuiText size="xs">{value}</EuiText>, width: '20%', }, { name: ( - <EuiToolTip content={PREVALENCE_TABLE_ALERT_COUNT_COLUMN_TITLE_TOOLTIP}> + <EuiToolTip + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.alertCountColumnTooltip" + defaultMessage="Total number of alerts with identical field value pairs." + /> + } + > <EuiFlexGroup direction="column" gutterSize="none"> - <EuiFlexItem>{PREVALENCE_TABLE_ALERT_COUNT_COLUMN_TITLE}</EuiFlexItem> - <EuiFlexItem>{PREVALENCE_TABLE_COUNT_COLUMN_TITLE}</EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.alertCountColumnLabel" + defaultMessage="Alert" + /> + </EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.alertCountColumnCountLabel" + defaultMessage="count" + /> + </EuiFlexItem> </EuiFlexGroup> </EuiToolTip> ), @@ -123,10 +136,27 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [ }, { name: ( - <EuiToolTip content={PREVALENCE_TABLE_DOC_COUNT_COLUMN_TITLE_TOOLTIP}> + <EuiToolTip + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.documentCountColumnTooltip" + defaultMessage="Total number of event documents with identical field value pairs." + /> + } + > <EuiFlexGroup direction="column" gutterSize="none"> - <EuiFlexItem>{PREVALENCE_TABLE_DOC_COUNT_COLUMN_TITLE}</EuiFlexItem> - <EuiFlexItem>{PREVALENCE_TABLE_COUNT_COLUMN_TITLE}</EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.documentCountColumnLabel" + defaultMessage="Document" + /> + </EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.documentCountColumnCountLabel" + defaultMessage="count" + /> + </EuiFlexItem> </EuiFlexGroup> </EuiToolTip> ), @@ -169,10 +199,27 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [ { field: 'hostPrevalence', name: ( - <EuiToolTip content={HOST_PREVALENCE_COLUMN_TITLE_TOOLTIP}> + <EuiToolTip + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.hostPrevalenceColumnTooltip" + defaultMessage="Percentage of unique hosts with identical field value pairs." + /> + } + > <EuiFlexGroup direction="column" gutterSize="none"> - <EuiFlexItem>{HOST_TITLE}</EuiFlexItem> - <EuiFlexItem>{PREVALENCE_TABLE_PREVALENCE_COLUMN_TITLE}</EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.hostPrevalenceColumnLabel" + defaultMessage="Host" + /> + </EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.hostPrevalenceColumnCountLabel" + defaultMessage="prevalence" + /> + </EuiFlexItem> </EuiFlexGroup> </EuiToolTip> ), @@ -185,10 +232,27 @@ const columns: Array<EuiBasicTableColumn<PrevalenceDetailsRow>> = [ { field: 'userPrevalence', name: ( - <EuiToolTip content={USER_PREVALENCE_COLUMN_TITLE_TOOLTIP}> + <EuiToolTip + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.userPrevalenceColumnTooltip" + defaultMessage="Percentage of unique users with identical field value pairs." + /> + } + > <EuiFlexGroup direction="column" gutterSize="none"> - <EuiFlexItem>{USER_TITLE}</EuiFlexItem> - <EuiFlexItem>{PREVALENCE_TABLE_PREVALENCE_COLUMN_TITLE}</EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.userPrevalenceColumnLabel" + defaultMessage="User" + /> + </EuiFlexItem> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.userPrevalenceColumnCountLabel" + defaultMessage="prevalence" + /> + </EuiFlexItem> </EuiFlexGroup> </EuiToolTip> ), @@ -270,15 +334,15 @@ export const PrevalenceDetails: React.FC = () => { const upsell = ( <> - <EuiCallOut data-test-subj={`${PREVALENCE_DETAILS_TABLE_TEST_ID}UpSell`}> + <EuiCallOut data-test-subj={PREVALENCE_DETAILS_TABLE_UPSELL_TEST_ID}> <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.prevalenceTableAlertUpsell" + id="xpack.securitySolution.flyout.left.insights.prevalence.tableAlertUpsellDescription" defaultMessage="Preview of a {subscription} feature showing host and user prevalence." values={{ subscription: ( <EuiLink href="https://www.elastic.co/pricing/" target="_blank"> <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.prevalenceTableAlertUpsellLink" + id="xpack.securitySolution.flyout.left.insights.prevalence.tableAlertUpsellLinkText" defaultMessage="Platinum" /> </EuiLink> @@ -308,9 +372,12 @@ export const PrevalenceDetails: React.FC = () => { data-test-subj={PREVALENCE_DETAILS_TABLE_TEST_ID} /> ) : ( - <div data-test-subj={`${PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID}Error`}> - {PREVALENCE_NO_DATA_MESSAGE} - </div> + <p data-test-subj={PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalence.noDataDescription" + defaultMessage="No prevalence data available." + /> + </p> )} </EuiPanel> </> diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.test.tsx index c54b76468841b..7a1cb79b90364 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.test.tsx @@ -111,4 +111,30 @@ describe('<RelatedAlertsByAncestry />', () => { ); expect(container).toBeEmptyDOMElement(); }); + + it('should render no data message', () => { + (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + dataCount: 0, + }); + (usePaginatedAlerts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + }); + + const { getByText } = render( + <TestProviders> + <RelatedAlertsByAncestry + documentId={documentId} + indices={indices} + scopeId={scopeId} + eventId={eventId} + /> + </TestProviders> + ); + expect(getByText('No alerts related by ancestry.')).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.tsx index ac0ac0a351e9a..050d2b4ae1966 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_ancestry.tsx @@ -6,9 +6,8 @@ */ import React from 'react'; -import { RELATED_ALERTS_BY_ANCESTRY_NO_DATA } from './translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { CorrelationsDetailsAlertsTable } from './correlations_details_alerts_table'; -import { CORRELATIONS_ANCESTRY_ALERTS } from '../../shared/translations'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; import { CORRELATIONS_DETAILS_BY_ANCESTRY_SECTION_TEST_ID } from './test_ids'; @@ -45,7 +44,6 @@ export const RelatedAlertsByAncestry: React.VFC<RelatedAlertsByAncestryProps> = indices, scopeId, }); - const title = `${dataCount} ${CORRELATIONS_ANCESTRY_ALERTS(dataCount)}`; if (error) { return null; @@ -53,12 +51,23 @@ export const RelatedAlertsByAncestry: React.VFC<RelatedAlertsByAncestryProps> = return ( <CorrelationsDetailsAlertsTable - title={title} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.ancestryAlertsTitle" + defaultMessage="{count} {count, plural, one {alert} other {alerts}} related by ancestry" + values={{ count: dataCount }} + /> + } loading={loading} alertIds={data} scopeId={scopeId} eventId={eventId} - noItemsMessage={RELATED_ALERTS_BY_ANCESTRY_NO_DATA} + noItemsMessage={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.ancestryAlertsNoDataDescription" + defaultMessage="No alerts related by ancestry." + /> + } data-test-subj={CORRELATIONS_DETAILS_BY_ANCESTRY_SECTION_TEST_ID} /> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.test.tsx index 77dbe5ef21a2c..55d2323dc413a 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.test.tsx @@ -108,4 +108,29 @@ describe('<RelatedAlertsBySameSourceEvent />', () => { ); expect(container).toBeEmptyDOMElement(); }); + + it('should render no data message', () => { + (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + dataCount: 0, + }); + (usePaginatedAlerts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + }); + + const { getByText } = render( + <TestProviders> + <RelatedAlertsBySameSourceEvent + originalEventId={originalEventId} + scopeId={scopeId} + eventId={eventId} + /> + </TestProviders> + ); + expect(getByText('No related source events.')).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.tsx index 0a0cdeb8fd29c..e3bbf48c5fe15 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_same_source_event.tsx @@ -6,8 +6,7 @@ */ import React from 'react'; -import { RELATED_ALERTS_BY_SOURCE_EVENT_NO_DATA } from './translations'; -import { CORRELATIONS_SAME_SOURCE_ALERTS } from '../../shared/translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; import { CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TEST_ID } from './test_ids'; import { CorrelationsDetailsAlertsTable } from './correlations_details_alerts_table'; @@ -39,7 +38,6 @@ export const RelatedAlertsBySameSourceEvent: React.VFC<RelatedAlertsBySameSource originalEventId, scopeId, }); - const title = `${dataCount} ${CORRELATIONS_SAME_SOURCE_ALERTS(dataCount)}`; if (error) { return null; @@ -47,12 +45,23 @@ export const RelatedAlertsBySameSourceEvent: React.VFC<RelatedAlertsBySameSource return ( <CorrelationsDetailsAlertsTable - title={title} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.sourceAlertsTitle" + defaultMessage="{count} {count, plural, one {alert} other {alerts}} related by source event" + values={{ count: dataCount }} + /> + } loading={loading} alertIds={data} scopeId={scopeId} eventId={eventId} - noItemsMessage={RELATED_ALERTS_BY_SOURCE_EVENT_NO_DATA} + noItemsMessage={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.sourceAlertsNoDataDescription" + defaultMessage="No related source events." + /> + } data-test-subj={CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TEST_ID} /> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.test.tsx index de1725eef64c9..2f2f4468440e1 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.test.tsx @@ -100,4 +100,25 @@ describe('<RelatedAlertsBySession />', () => { ); expect(container).toBeEmptyDOMElement(); }); + + it('should render no data message', () => { + (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + dataCount: 0, + }); + (usePaginatedAlerts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + }); + + const { getByText } = render( + <TestProviders> + <RelatedAlertsBySession entityId={entityId} scopeId={scopeId} eventId={eventId} /> + </TestProviders> + ); + expect(getByText('No alerts related by session.')).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.tsx index 8a55aa3651708..1aa5a2b9dd619 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_alerts_by_session.tsx @@ -6,8 +6,7 @@ */ import React from 'react'; -import { RELATED_ALERTS_BY_SESSION_NO_DATA } from './translations'; -import { CORRELATIONS_SESSION_ALERTS } from '../../shared/translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { CorrelationsDetailsAlertsTable } from './correlations_details_alerts_table'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; import { CORRELATIONS_DETAILS_BY_SESSION_SECTION_TEST_ID } from './test_ids'; @@ -39,7 +38,6 @@ export const RelatedAlertsBySession: React.VFC<RelatedAlertsBySessionProps> = ({ entityId, scopeId, }); - const title = `${dataCount} ${CORRELATIONS_SESSION_ALERTS(dataCount)}`; if (error) { return null; @@ -47,12 +45,23 @@ export const RelatedAlertsBySession: React.VFC<RelatedAlertsBySessionProps> = ({ return ( <CorrelationsDetailsAlertsTable - title={title} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.sessionAlertsTitle" + defaultMessage="{count} {count, plural, one {alert} other {alerts}} related by session" + values={{ count: dataCount }} + /> + } loading={loading} alertIds={data} scopeId={scopeId} eventId={eventId} - noItemsMessage={RELATED_ALERTS_BY_SESSION_NO_DATA} + noItemsMessage={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.sessionAlertsNoDataDescription" + defaultMessage="No alerts related by session." + /> + } data-test-subj={CORRELATIONS_DETAILS_BY_SESSION_SECTION_TEST_ID} /> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.test.tsx index ce11b234e8359..264794666234a 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID, @@ -38,6 +39,13 @@ const TITLE_TEXT = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID( CORRELATIONS_DETAILS_CASES_SECTION_TEST_ID ); +const renderRelatedCases = () => + render( + <IntlProvider locale="en"> + <RelatedCases eventId={eventId} /> + </IntlProvider> + ); + describe('<RelatedCases />', () => { it('should render many related cases correctly', () => { (useFetchRelatedCases as jest.Mock).mockReturnValue({ @@ -54,7 +62,7 @@ describe('<RelatedCases />', () => { dataCount: 1, }); - const { getByTestId } = render(<RelatedCases eventId={eventId} />); + const { getByTestId } = renderRelatedCases(); expect(getByTestId(TOGGLE_ICON)).toBeInTheDocument(); expect(getByTestId(TITLE_ICON)).toBeInTheDocument(); expect(getByTestId(TITLE_TEXT)).toHaveTextContent('1 related case'); @@ -67,7 +75,19 @@ describe('<RelatedCases />', () => { error: true, }); - const { container } = render(<RelatedCases eventId={eventId} />); + const { container } = renderRelatedCases(); expect(container).toBeEmptyDOMElement(); }); + + it('should render no data message', () => { + (useFetchRelatedCases as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], + dataCount: 0, + }); + + const { getByText } = renderRelatedCases(); + expect(getByText('No related cases.')).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx index 707087d6360e8..5818b9314390c 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/related_cases.tsx @@ -9,26 +9,26 @@ import React from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; import { EuiInMemoryTable, EuiSkeletonText } from '@elastic/eui'; import type { RelatedCase } from '@kbn/cases-plugin/common'; +import { FormattedMessage } from '@kbn/i18n-react'; import { CaseDetailsLink } from '../../../common/components/links'; -import { CORRELATIONS_RELATED_CASES } from '../../shared/translations'; import { CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID, CORRELATIONS_DETAILS_CASES_SECTION_TEST_ID, } from './test_ids'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; -import { - CORRELATIONS_CASE_NAME_COLUMN_TITLE, - CORRELATIONS_CASE_STATUS_COLUMN_TITLE, - RELATED_CASES_NO_DATA, -} from './translations'; const ICON = 'warning'; const columns: Array<EuiBasicTableColumn<RelatedCase>> = [ { field: 'title', - name: CORRELATIONS_CASE_NAME_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.nameColumnLabel" + defaultMessage="Name" + /> + ), truncateText: true, render: (value: string, caseData: RelatedCase) => ( <CaseDetailsLink detailName={caseData.id} title={caseData.title}> @@ -38,7 +38,12 @@ const columns: Array<EuiBasicTableColumn<RelatedCase>> = [ }, { field: 'status', - name: CORRELATIONS_CASE_STATUS_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.statusColumnLabel" + defaultMessage="Status" + /> + ), truncateText: true, }, ]; @@ -55,7 +60,6 @@ export interface RelatedCasesProps { */ export const RelatedCases: React.VFC<RelatedCasesProps> = ({ eventId }) => { const { loading, error, data, dataCount } = useFetchRelatedCases({ eventId }); - const title = `${dataCount} ${CORRELATIONS_RELATED_CASES(dataCount)}`; if (loading) { return <EuiSkeletonText lines={1} size="m" isLoading={loading} contentAriaLabel="Loading" />; @@ -68,7 +72,13 @@ export const RelatedCases: React.VFC<RelatedCasesProps> = ({ eventId }) => { return ( <ExpandablePanel header={{ - title, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.relatedCasesTitle" + defaultMessage="{count} related {count, plural, one {case} other {cases}}" + values={{ count: dataCount }} + /> + ), iconType: ICON, }} content={{ error }} @@ -83,7 +93,12 @@ export const RelatedCases: React.VFC<RelatedCasesProps> = ({ eventId }) => { items={data} columns={columns} pagination={true} - message={RELATED_CASES_NO_DATA} + message={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.relatedCasesNoDataDescription" + defaultMessage="No related cases." + /> + } data-test-subj={CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID} /> </ExpandablePanel> diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx index 435df5fb3dcd1..b4720c433ea02 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.test.tsx @@ -125,5 +125,8 @@ describe('<ResponseDetails />', () => { expect(wrapper.queryByTestId('osqueryViewWrapper')).not.toBeInTheDocument(); expect(wrapper.getByTestId(RESPONSE_EMPTY_TEST_ID)).toBeInTheDocument(); + expect(wrapper.getByTestId(RESPONSE_EMPTY_TEST_ID)).toHaveTextContent( + 'There are no response actions defined for this event. To add some, edit the rule’s settings and set up response actionsExternal link(opens in a new tab or window).' + ); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx index 03e16c0118cfa..37b1b6b83b203 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx @@ -19,7 +19,6 @@ import { useLeftPanelContext } from '../context'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { useOsqueryTab } from '../../../common/components/event_details/osquery_tab'; import { useResponseActionsView } from '../../../common/components/event_details/response_actions_view'; -import * as i18n from './translations'; const ExtendedFlyoutWrapper = styled.div` figure { @@ -58,13 +57,18 @@ export const ResponseDetails: React.FC = () => { return ( <div data-test-subj={RESPONSE_DETAILS_TEST_ID}> <EuiTitle size="xxxs"> - <h5>{i18n.RESPONSE_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.left.response.responseTitle" + defaultMessage="Responses" + /> + </h5> </EuiTitle> <EuiSpacer size="s" /> {!responseActions ? ( <InlineBlock data-test-subj={RESPONSE_EMPTY_TEST_ID}> <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.response.emptyMessage" + id="xpack.securitySolution.flyout.left.response.noDataDescription" defaultMessage="There are no response actions defined for this event. To add some, edit the rule’s settings and set up {link}." values={{ link: ( @@ -73,7 +77,7 @@ export const ResponseDetails: React.FC = () => { target="_blank" > <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.response.responseActionLink" + id="xpack.securitySolution.flyout.left.response.noDataLinkText" defaultMessage="response actions" /> </EuiLink> diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/session_view.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/session_view.tsx index 48f1164f75168..4fd548e60a21a 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/session_view.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/session_view.tsx @@ -8,14 +8,13 @@ import type { FC } from 'react'; import React from 'react'; import { EuiEmptyPrompt } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ANCESTOR_INDEX, ENTRY_LEADER_ENTITY_ID, ENTRY_LEADER_START, } from '../../shared/constants/field_names'; import { getField } from '../../shared/utils'; -import { ERROR_MESSAGE, ERROR_TITLE } from '../../shared/translations'; -import { SESSION_VIEW_ERROR_MESSAGE } from './translations'; import { SESSION_VIEW_ERROR_TEST_ID, SESSION_VIEW_TEST_ID } from './test_ids'; import { useKibana } from '../../../common/lib/kibana'; import { useLeftPanelContext } from '../context'; @@ -39,8 +38,24 @@ export const SessionView: FC = () => { <EuiEmptyPrompt iconType="error" color="danger" - title={<h2>{ERROR_TITLE(SESSION_VIEW_ERROR_MESSAGE)}</h2>} - body={<p>{ERROR_MESSAGE(SESSION_VIEW_ERROR_MESSAGE)}</p>} + title={ + <h2> + <FormattedMessage + id="xpack.securitySolution.flyout.left.visualize.sessionView.errorMessageTitle" + defaultMessage="Unable to display {title}" + values={{ title: 'session view' }} + /> + </h2> + } + body={ + <p> + <FormattedMessage + id="xpack.securitySolution.flyout.left.visualize.sessionView.errorMessageDescription" + defaultMessage="There was an error displaying {message}" + values={{ message: 'session view' }} + /> + </p> + } data-test-subj={SESSION_VIEW_ERROR_TEST_ID} /> ); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.test.tsx index 646cbb2fc9bd5..4bc1a8f5fb0d0 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.test.tsx @@ -36,15 +36,21 @@ const TITLE_TEXT = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID( ); const INVESTIGATE_IN_TIMELINE_BUTTON_TEST_ID = `${CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_SECTION_TEST_ID}InvestigateInTimeline`; +const renderSuppressedAlerts = (alertSuppressionCount: number) => + render( + <TestProviders> + <LeftPanelContext.Provider value={mockContextValue}> + <SuppressedAlerts + alertSuppressionCount={alertSuppressionCount} + dataAsNestedObject={mockDataAsNestedObject} + /> + </LeftPanelContext.Provider> + </TestProviders> + ); + describe('<SuppressedAlerts />', () => { it('should render zero component correctly', () => { - const { getByTestId, queryByTestId } = render( - <TestProviders> - <LeftPanelContext.Provider value={mockContextValue}> - <SuppressedAlerts alertSuppressionCount={0} dataAsNestedObject={mockDataAsNestedObject} /> - </LeftPanelContext.Provider> - </TestProviders> - ); + const { getByTestId, queryByTestId } = renderSuppressedAlerts(0); expect(getByTestId(TITLE_ICON)).toBeInTheDocument(); expect(getByTestId(TITLE_TEXT)).toHaveTextContent('0 suppressed alert'); @@ -54,13 +60,7 @@ describe('<SuppressedAlerts />', () => { }); it('should render single component correctly', () => { - const { getByTestId, queryByTestId } = render( - <TestProviders> - <LeftPanelContext.Provider value={mockContextValue}> - <SuppressedAlerts alertSuppressionCount={1} dataAsNestedObject={mockDataAsNestedObject} /> - </LeftPanelContext.Provider> - </TestProviders> - ); + const { getByTestId, queryByTestId } = renderSuppressedAlerts(1); expect(getByTestId(TITLE_ICON)).toBeInTheDocument(); expect(getByTestId(TITLE_TEXT)).toHaveTextContent('1 suppressed alert'); @@ -70,13 +70,7 @@ describe('<SuppressedAlerts />', () => { }); it('should render multiple component correctly', () => { - const { getByTestId, queryByTestId } = render( - <TestProviders> - <LeftPanelContext.Provider value={mockContextValue}> - <SuppressedAlerts alertSuppressionCount={2} dataAsNestedObject={mockDataAsNestedObject} /> - </LeftPanelContext.Provider> - </TestProviders> - ); + const { getByTestId, queryByTestId } = renderSuppressedAlerts(2); expect(getByTestId(TITLE_ICON)).toBeInTheDocument(); expect(getByTestId(TITLE_TEXT)).toHaveTextContent('2 suppressed alerts'); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.tsx index 2fc96ab4d47fd..c2123ced63feb 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/suppressed_alerts.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { EuiBetaBadge, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; -import { CORRELATIONS_SUPPRESSED_ALERTS } from '../../shared/translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_SECTION_TEST_ID, @@ -38,7 +38,11 @@ export const SuppressedAlerts: React.VFC<SuppressedAlertsProps> = ({ const title = ( <EuiFlexGroup alignItems="center" gutterSize="s"> <EuiFlexItem> - {`${alertSuppressionCount} ${CORRELATIONS_SUPPRESSED_ALERTS(alertSuppressionCount)}`} + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlations.suppressedAlertsTitle" + defaultMessage="{count} suppressed {count, plural, =1 {alert} other {alerts}}" + values={{ count: alertSuppressionCount }} + /> </EuiFlexItem> <EuiFlexItem> <EuiBetaBadge diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/left/components/test_ids.ts index 03b768607c20c..57e1deb59136e 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/left/components/test_ids.ts @@ -23,21 +23,23 @@ export const PREVALENCE_DETAILS_DATE_PICKER_TEST_ID = export const PREVALENCE_DETAILS_TABLE_TEST_ID = `${PREFIX}PrevalenceDetailsTable` as const; export const PREVALENCE_DETAILS_LOADING_TEST_ID = `${PREFIX}PrevalenceDetailsLoading` as const; export const PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID = - `${PREFIX}PrevalenceDetailsTableFieldCell` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}FieldCell` as const; export const PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID = - `${PREFIX}PrevalenceDetailsTableValueCell` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}ValueCell` as const; export const PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID = - `${PREFIX}PrevalenceDetailsTableAlertCountCell` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}AlertCountCell` as const; export const PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID = - `${PREFIX}PrevalenceDetailsTableDocCountCell` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}DocCountCell` as const; export const PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID = - `${PREFIX}PrevalenceDetailsTableHostPrevalenceCell` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}HostPrevalenceCell` as const; export const PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID = - `${PREFIX}PrevalenceDetailsTableUserPrevalenceCell` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}UserPrevalenceCell` as const; export const PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID = - `${PREFIX}PrevalenceDetailsTableError` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}Error` as const; export const PREVALENCE_DETAILS_TABLE_NO_DATA_TEST_ID = - `${PREFIX}PrevalenceDetailsTableNoData` as const; + `${PREVALENCE_DETAILS_TABLE_TEST_ID}NoData` as const; +export const PREVALENCE_DETAILS_TABLE_UPSELL_TEST_ID = + `${PREVALENCE_DETAILS_TABLE_TEST_ID}Upsell` as const; /* Entities */ @@ -53,6 +55,8 @@ export const HOST_DETAILS_RELATED_USERS_TABLE_TEST_ID = `${PREFIX}HostsDetailsRelatedUsersTable` as const; export const CORRELATIONS_DETAILS_TEST_ID = `${PREFIX}CorrelationsDetails` as const; +export const CORRELATIONS_DETAILS_NO_DATA_TEST_ID = + `${CORRELATIONS_DETAILS_TEST_ID}NoData` as const; export const THREAT_INTELLIGENCE_DETAILS_ENRICHMENTS_TEST_ID = `threat-match-detected` as const; export const THREAT_INTELLIGENCE_DETAILS_SPINNER_TEST_ID = diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/translations.ts b/x-pack/plugins/security_solution/public/flyout/left/components/translations.ts deleted file mode 100644 index 16c2349d87316..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/left/components/translations.ts +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const ENTITIES_NO_DATA_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.entitiesNoDataMessage', - { - defaultMessage: 'Host and user information are unavailable for this alert.', - } -); - -export const ANALYZER_ERROR_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.analyzerErrorMessage', - { - defaultMessage: 'analyzer', - } -); - -export const SESSION_VIEW_ERROR_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.sessionViewErrorMessage', - { - defaultMessage: 'session view', - } -); - -export const CORRELATIONS_ERROR_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.correlationsErrorMessage', - { - defaultMessage: 'No correlations data available', - } -); - -export const USER_TITLE = i18n.translate('xpack.securitySolution.flyout.entities.userTitle', { - defaultMessage: 'User', -}); - -export const USER_PREVALENCE_COLUMN_TITLE_TOOLTIP = i18n.translate( - 'xpack.securitySolution.flyout.entities.userPrevalenceColumTitleTooltip', - { - defaultMessage: 'Percentage of unique users with identical field value pairs', - } -); - -export const USERS_INFO_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.entities.usersInfoTitle', - { - defaultMessage: 'User information', - } -); - -export const RELATED_HOSTS_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.entities.relatedHostsTitle', - { - defaultMessage: 'Related hosts', - } -); - -export const RELATED_HOSTS_TABLE_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.entities.relatedHostsTableNoData', - { - defaultMessage: 'No hosts identified', - } -); - -export const RELATED_HOSTS_TOOL_TIP = (userName: string) => - i18n.translate('xpack.securitySolution.flyout.entities.relatedHostsToolTip', { - defaultMessage: - 'After this alert was generated, {userName} logged into these hosts. Check if this activity is normal.', - values: { userName }, - }); - -export const RELATED_ENTITIES_NAME_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.entities.relatedEntitiesNameColumn', - { - defaultMessage: 'Name', - } -); - -export const RELATED_ENTITIES_IP_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.entities.relatedEntitiesIpColumn', - { - defaultMessage: 'Ip addresses', - } -); - -export const HOST_TITLE = i18n.translate('xpack.securitySolution.flyout.entities.hostTitle', { - defaultMessage: 'Host', -}); - -export const HOST_PREVALENCE_COLUMN_TITLE_TOOLTIP = i18n.translate( - 'xpack.securitySolution.flyout.entities.hostPrevalenceColumTitleTooltip', - { - defaultMessage: 'Percentage of unique hosts with identical field value pairs', - } -); - -export const HOSTS_INFO_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.entities.hostsInfoTitle', - { - defaultMessage: 'Host information', - } -); - -export const RELATED_USERS_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.entities.relatedUsersTitle', - { - defaultMessage: 'Related users', - } -); - -export const RELATED_USERS_TABLE_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.entities.relatedUsersTableNoData', - { - defaultMessage: 'No users identified', - } -); - -export const RELATED_USERS_TOOL_TIP = (hostName: string) => - i18n.translate('xpack.securitySolution.flyout.entities.relatedUsersToolTip', { - defaultMessage: - 'After this alert was generated, these users logged into {hostName}. Check if this activity is normal.', - values: { hostName }, - }); - -export const PREVALENCE_NO_DATA_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceNoDataMessage', - { - defaultMessage: 'No prevalence data available', - } -); - -export const PREVALENCE_TABLE_FIELD_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTableFieldColumnTitle', - { - defaultMessage: 'Field', - } -); - -export const PREVALENCE_TABLE_VALUE_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTableValueColumnTitle', - { - defaultMessage: 'Value', - } -); - -export const PREVALENCE_TABLE_ALERT_COUNT_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTableAlertCountColumnTitle', - { - defaultMessage: 'Alert', - } -); - -export const PREVALENCE_TABLE_ALERT_COUNT_COLUMN_TITLE_TOOLTIP = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTableAlertCountColumnTitleTooltip', - { - defaultMessage: 'Total number of alerts with identical field value pairs', - } -); - -export const PREVALENCE_TABLE_DOC_COUNT_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTableDocCountColumnTitle', - { - defaultMessage: 'Document', - } -); - -export const PREVALENCE_TABLE_DOC_COUNT_COLUMN_TITLE_TOOLTIP = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTableDocCountColumnTitleTooltip', - { - defaultMessage: 'Total number of event documents with identical field value pairs', - } -); - -export const PREVALENCE_TABLE_COUNT_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTableCountColumnTitle', - { - defaultMessage: 'count', - } -); - -export const PREVALENCE_TABLE_PREVALENCE_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.prevalenceTablePrevalenceColumnTitle', - { - defaultMessage: 'prevalence', - } -); - -export const RESPONSE_TITLE = i18n.translate('xpack.securitySolution.flyout.response.title', { - defaultMessage: 'Responses', -}); - -export const CORRELATIONS_TIMESTAMP_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.correlations.timestampColumnTitle', - { - defaultMessage: 'Timestamp', - } -); - -export const CORRELATIONS_RULE_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.correlations.ruleColumnTitle', - { - defaultMessage: 'Rule', - } -); - -export const CORRELATIONS_REASON_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.correlations.reasonColumnTitle', - { - defaultMessage: 'Reason', - } -); - -export const CORRELATIONS_SEVERITY_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.correlations.severityColumnTitle', - { - defaultMessage: 'Severity', - } -); - -export const CORRELATIONS_CASE_STATUS_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.correlations.statusColumnTitle', - { - defaultMessage: 'Status', - } -); - -export const CORRELATIONS_CASE_NAME_COLUMN_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.correlations.caseNameColumnTitle', - { - defaultMessage: 'Name', - } -); - -export const CORRELATIONS_DETAILS_TABLE_FILTER = i18n.translate( - 'xpack.securitySolution.flyout.correlations.correlationsDetailsTableFilter', - { - defaultMessage: 'Correlations Details Table Alert IDs', - } -); - -export const RELATED_ALERTS_BY_ANCESTRY_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.correlations.relatedAlertsByAncestryNoData', - { - defaultMessage: 'No alerts related by ancestry', - } -); - -export const RELATED_ALERTS_BY_SOURCE_EVENT_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.correlations.relatedAlertsBySourceEventNoData', - { - defaultMessage: 'No related source events', - } -); - -export const RELATED_ALERTS_BY_SESSION_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.correlations.relatedAlertsBySessionNoData', - { - defaultMessage: 'No alerts related by session', - } -); - -export const RELATED_CASES_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.correlations.relatedCasesNoData', - { - defaultMessage: 'No related cases', - } -); diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/user_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/user_details.tsx index c5a135eb621bb..12ad057284cd6 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/user_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/user_details.tsx @@ -20,6 +20,7 @@ import { EuiPanel, } from '@elastic/eui'; import type { EuiBasicTableColumn } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { getSourcererScopeId } from '../../../helpers'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import type { RelatedHost } from '../../../../common/search_strategy/security_solution/related_entities/related_hosts'; @@ -50,7 +51,6 @@ import { getEmptyTagValue } from '../../../common/components/empty_value'; import { USER_DETAILS_RELATED_HOSTS_TABLE_TEST_ID, USER_DETAILS_TEST_ID } from './test_ids'; import { ENTITY_RISK_CLASSIFICATION } from '../../../explore/components/risk_score/translations'; import { HOST_RISK_TOOLTIP } from '../../../explore/hosts/components/hosts_table/translations'; -import * as i18n from './translations'; import { useHasSecurityCapability } from '../../../helper_hooks'; const USER_DETAILS_ID = 'entities-users-details'; @@ -129,7 +129,12 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s () => [ { field: 'host', - name: i18n.RELATED_ENTITIES_NAME_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedHostsNameColumnLabel" + defaultMessage="Name" + /> + ), render: (host: string) => ( <EuiText grow={false} size="xs"> <SecurityCellActions @@ -151,7 +156,12 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s }, { field: 'ip', - name: i18n.RELATED_ENTITIES_IP_COLUMN_TITLE, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedHostsIpColumnLabel" + defaultMessage="Ip addresses" + /> + ), render: (ips: string[]) => { return ( <DefaultFieldRenderer @@ -200,7 +210,13 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s </EuiFlexItem> <EuiFlexItem grow={false}> <EuiTitle size="xxxs"> - <EuiText>{`${i18n.RELATED_HOSTS_TITLE}: ${totalCount}`}</EuiText> + <EuiText> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedHostsCountLabel" + defaultMessage="Related hosts: {count}" + values={{ count: totalCount }} + /> + </EuiText> </EuiTitle> </EuiFlexItem> </EuiFlexGroup> @@ -216,7 +232,12 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s return ( <> <EuiTitle size="xs"> - <h4>{i18n.USER_TITLE}</h4> + <h4> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.userDetailsTitle" + defaultMessage="User" + /> + </h4> </EuiTitle> <EuiSpacer size="s" /> <ExpandablePanel @@ -232,7 +253,12 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s data-test-subj={USER_DETAILS_TEST_ID} > <EuiTitle size="xxs"> - <h5>{i18n.USERS_INFO_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.userDetailsInfoTitle" + defaultMessage="User information" + /> + </h5> </EuiTitle> <EuiSpacer size="s" /> <AnomalyTableProvider @@ -266,11 +292,24 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s <EuiFlexGroup direction="row" gutterSize="xs" alignItems="center"> <EuiFlexItem grow={false}> <EuiTitle size="xxs"> - <h5>{i18n.RELATED_HOSTS_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedHostsTitle" + defaultMessage="Related hosts" + /> + </h5> </EuiTitle> </EuiFlexItem> <EuiFlexItem grow={false}> - <EuiToolTip content={i18n.RELATED_HOSTS_TOOL_TIP(userName)}> + <EuiToolTip + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedHostsTooltip" + defaultMessage="After this alert was generated, {userName} logged into these hosts. Check if this activity is normal." + values={{ userName }} + /> + } + > <EuiIcon color="subdued" type="iInCircle" className="eui-alignTop" /> </EuiToolTip> </EuiFlexItem> @@ -290,11 +329,21 @@ export const UserDetails: React.FC<UserDetailsProps> = ({ userName, timestamp, s loading={isRelatedHostLoading} data-test-subj={USER_DETAILS_RELATED_HOSTS_TABLE_TEST_ID} pagination={pagination} - message={i18n.RELATED_HOSTS_TABLE_NO_DATA} + message={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedHostsNoDataDescription" + defaultMessage="No hosts identified" + /> + } /> <InspectButton queryId={relatedHostsQueryId} - title={i18n.RELATED_HOSTS_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entities.relatedHostsInspectButtonTitle" + defaultMessage="Related hosts" + /> + } inspectIndex={0} /> </RelatedHostsManage> diff --git a/x-pack/plugins/security_solution/public/flyout/left/tabs.tsx b/x-pack/plugins/security_solution/public/flyout/left/tabs.tsx index 9ac70d515cc45..c2fc6e5fe20db 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/tabs.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/tabs.tsx @@ -5,10 +5,11 @@ * 2.0. */ +import type { ReactElement } from 'react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { VisualizeTab } from './tabs/visualize_tab'; import { InvestigationTab } from './tabs/investigation_tab'; -import { INSIGHTS_TAB, INVESTIGATIONS_TAB, RESPONSE_TAB, VISUALIZE_TAB } from './translations'; import { InsightsTab } from './tabs/insights_tab'; import type { LeftPanelPaths } from '.'; import { @@ -22,7 +23,7 @@ import { ResponseTab } from './tabs/response_tab'; export type LeftPanelTabsType = Array<{ id: LeftPanelPaths; 'data-test-subj': string; - name: string; + name: ReactElement; content: React.ReactElement; visible: boolean; }>; @@ -31,28 +32,48 @@ export const tabs: LeftPanelTabsType = [ { id: 'visualize', 'data-test-subj': VISUALIZE_TAB_TEST_ID, - name: VISUALIZE_TAB, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.visualize.tabLabel" + defaultMessage="Visualize" + /> + ), content: <VisualizeTab />, visible: false, }, { id: 'insights', 'data-test-subj': INSIGHTS_TAB_TEST_ID, - name: INSIGHTS_TAB, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.tabLabel" + defaultMessage="Insights" + /> + ), content: <InsightsTab />, visible: true, }, { id: 'investigation', 'data-test-subj': INVESTIGATION_TAB_TEST_ID, - name: INVESTIGATIONS_TAB, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.investigations.tabLabel" + defaultMessage="Investigation" + /> + ), content: <InvestigationTab />, visible: true, }, { id: 'response', 'data-test-subj': RESPONSE_TAB_TEST_ID, - name: RESPONSE_TAB, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.response.tabLabel" + defaultMessage="Response" + /> + ), content: <ResponseTab />, visible: true, }, diff --git a/x-pack/plugins/security_solution/public/flyout/left/tabs/insights_tab.tsx b/x-pack/plugins/security_solution/public/flyout/left/tabs/insights_tab.tsx index a041a980752be..6f35b6b26f3c8 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/tabs/insights_tab.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/tabs/insights_tab.tsx @@ -10,6 +10,8 @@ import React, { memo, useCallback, useState, useEffect } from 'react'; import { EuiButtonGroup, EuiSpacer } from '@elastic/eui'; import type { EuiButtonGroupOptionProps } from '@elastic/eui/src/components/button/button_group/button_group'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { INSIGHTS_TAB_BUTTON_GROUP_TEST_ID, INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID, @@ -19,13 +21,6 @@ import { } from './test_ids'; import { useLeftPanelContext } from '../context'; import { LeftPanelKey, LeftPanelInsightsTab } from '..'; -import { - INSIGHTS_BUTTONGROUP_OPTIONS, - ENTITIES_BUTTON, - THREAT_INTELLIGENCE_BUTTON, - PREVALENCE_BUTTON, - CORRELATIONS_BUTTON, -} from './translations'; import { ENTITIES_TAB_ID, EntitiesDetails } from '../components/entities_details'; import { THREAT_INTELLIGENCE_TAB_ID, @@ -37,22 +32,42 @@ import { CORRELATIONS_TAB_ID, CorrelationsDetails } from '../components/correlat const insightsButtons: EuiButtonGroupOptionProps[] = [ { id: ENTITIES_TAB_ID, - label: ENTITIES_BUTTON, + label: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.entitiesButtonLabel" + defaultMessage="Entities" + /> + ), 'data-test-subj': INSIGHTS_TAB_ENTITIES_BUTTON_TEST_ID, }, { id: THREAT_INTELLIGENCE_TAB_ID, - label: THREAT_INTELLIGENCE_BUTTON, + label: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.threatIntelligenceButtonLabel" + defaultMessage="Threat intelligence" + /> + ), 'data-test-subj': INSIGHTS_TAB_THREAT_INTELLIGENCE_BUTTON_TEST_ID, }, { id: PREVALENCE_TAB_ID, - label: PREVALENCE_BUTTON, + label: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.prevalenceButtonLabel" + defaultMessage="Prevalence" + /> + ), 'data-test-subj': INSIGHTS_TAB_PREVALENCE_BUTTON_TEST_ID, }, { id: CORRELATIONS_TAB_ID, - label: CORRELATIONS_BUTTON, + label: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.insights.correlationsButtonLabel" + defaultMessage="Correlations" + /> + ), 'data-test-subj': INSIGHTS_TAB_CORRELATIONS_BUTTON_TEST_ID, }, ]; @@ -97,7 +112,12 @@ export const InsightsTab: React.FC = memo(() => { <EuiButtonGroup color="primary" name="coarsness" - legend={INSIGHTS_BUTTONGROUP_OPTIONS} + legend={i18n.translate( + 'xpack.securitySolution.flyout.left.insights.buttonGroupButtonLabel', + { + defaultMessage: 'Insights options', + } + )} options={insightsButtons} idSelected={activeInsightsId} onChange={onChangeCompressed} diff --git a/x-pack/plugins/security_solution/public/flyout/left/tabs/translations.ts b/x-pack/plugins/security_solution/public/flyout/left/tabs/translations.ts deleted file mode 100644 index e000ba2feabf8..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/left/tabs/translations.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const VISUALIZE_BUTTONGROUP_OPTIONS = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.visualizeOptions', - { - defaultMessage: 'Visualize options', - } -); - -export const SESSION_VIEW_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.sessionViewButton', - { - defaultMessage: 'Session View', - } -); - -export const ANALYZER_GRAPH_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.analyzerGraphButton', - { - defaultMessage: 'Analyzer Graph', - } -); - -export const INSIGHTS_BUTTONGROUP_OPTIONS = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.insightsOptions', - { - defaultMessage: 'Insights options', - } -); - -export const ENTITIES_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.entitiesButton', - { - defaultMessage: 'Entities', - } -); - -export const THREAT_INTELLIGENCE_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.threatIntelligenceButton', - { - defaultMessage: 'Threat intelligence', - } -); - -export const PREVALENCE_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.prevalenceButton', - { - defaultMessage: 'Prevalence', - } -); - -export const CORRELATIONS_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.correlationsButton', - { - defaultMessage: 'Correlations', - } -); diff --git a/x-pack/plugins/security_solution/public/flyout/left/tabs/visualize_tab.tsx b/x-pack/plugins/security_solution/public/flyout/left/tabs/visualize_tab.tsx index baedc5c1cec73..923a2e9aa3ed6 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/tabs/visualize_tab.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/tabs/visualize_tab.tsx @@ -10,6 +10,8 @@ import React, { memo, useState, useCallback, useEffect } from 'react'; import { EuiButtonGroup, EuiSpacer } from '@elastic/eui'; import type { EuiButtonGroupOptionProps } from '@elastic/eui/src/components/button/button_group/button_group'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useLeftPanelContext } from '../context'; import { LeftPanelKey, LeftPanelVisualizeTab } from '..'; import { @@ -18,11 +20,6 @@ import { VISUALIZE_TAB_SESSION_VIEW_BUTTON_TEST_ID, } from './test_ids'; import { ANALYZE_GRAPH_ID, AnalyzeGraph } from '../components/analyze_graph'; -import { - ANALYZER_GRAPH_BUTTON, - SESSION_VIEW_BUTTON, - VISUALIZE_BUTTONGROUP_OPTIONS, -} from './translations'; import { SESSION_VIEW_ID, SessionView } from '../components/session_view'; import { ALERTS_ACTIONS } from '../../../common/lib/apm/user_actions'; import { useStartTransaction } from '../../../common/lib/apm/use_start_transaction'; @@ -30,12 +27,22 @@ import { useStartTransaction } from '../../../common/lib/apm/use_start_transacti const visualizeButtons: EuiButtonGroupOptionProps[] = [ { id: SESSION_VIEW_ID, - label: SESSION_VIEW_BUTTON, + label: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.visualize.sessionViewButtonLabel" + defaultMessage="Session View" + /> + ), 'data-test-subj': VISUALIZE_TAB_SESSION_VIEW_BUTTON_TEST_ID, }, { id: ANALYZE_GRAPH_ID, - label: ANALYZER_GRAPH_BUTTON, + label: ( + <FormattedMessage + id="xpack.securitySolution.flyout.left.visualize.analyzerGraphButtonLabel" + defaultMessage="Analyzer Graph" + /> + ), 'data-test-subj': VISUALIZE_TAB_GRAPH_ANALYZER_BUTTON_TEST_ID, }, ]; @@ -83,7 +90,12 @@ export const VisualizeTab: FC = memo(() => { <EuiButtonGroup color="primary" name="coarsness" - legend={VISUALIZE_BUTTONGROUP_OPTIONS} + legend={i18n.translate( + 'xpack.securitySolution.flyout.left.visualize.buttonGroupButtonLabel', + { + defaultMessage: 'Visualize options', + } + )} options={visualizeButtons} idSelected={activeVisualizationId} onChange={(id) => onChangeCompressed(id)} diff --git a/x-pack/plugins/security_solution/public/flyout/left/translations.ts b/x-pack/plugins/security_solution/public/flyout/left/translations.ts deleted file mode 100644 index c2dc888ab9aef..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/left/translations.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const VISUALIZE_TAB = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.visualizeTab', - { - defaultMessage: 'Visualize', - } -); - -export const INSIGHTS_TAB = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.insightsTab', - { - defaultMessage: 'Insights', - } -); - -export const INVESTIGATIONS_TAB = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.investigationsTab', - { - defaultMessage: 'Investigation', - } -); - -export const RESPONSE_TAB = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.responseTab', - { - defaultMessage: 'Response', - } -); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx index f84983e5ce13b..99540e38da725 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { PreviewPanelContext } from '../context'; import { mockContextValue } from '../mocks/mock_preview_panel_context'; @@ -23,12 +24,15 @@ const panelContextValue = { describe('<AlertReasonPreview />', () => { it('should render alert reason preview', () => { const { getByTestId } = render( - <PreviewPanelContext.Provider value={panelContextValue}> - <ThemeProvider theme={mockTheme}> - <AlertReasonPreview /> - </ThemeProvider> - </PreviewPanelContext.Provider> + <IntlProvider locale="en>"> + <PreviewPanelContext.Provider value={panelContextValue}> + <ThemeProvider theme={mockTheme}> + <AlertReasonPreview /> + </ThemeProvider> + </PreviewPanelContext.Provider> + </IntlProvider> ); expect(getByTestId(ALERT_REASON_PREVIEW_BODY_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ALERT_REASON_PREVIEW_BODY_TEST_ID)).toHaveTextContent('Alert reason'); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx index e7460c1042788..476a1f3551948 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/alert_reason_preview.tsx @@ -9,7 +9,7 @@ import React, { useMemo } from 'react'; import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import styled from '@emotion/styled'; import { euiThemeVars } from '@kbn/ui-theme'; -import { ALERT_REASON_TITLE } from './translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ALERT_REASON_PREVIEW_BODY_TEST_ID } from './test_ids'; import { usePreviewPanelContext } from '../context'; import { getRowRenderer } from '../../../timelines/components/timeline/body/renderers/get_row_renderer'; @@ -53,7 +53,12 @@ export const AlertReasonPreview: React.FC = () => { return ( <EuiPanel hasShadow={false} data-test-subj={ALERT_REASON_PREVIEW_BODY_TEST_ID}> <EuiTitle> - <h6>{ALERT_REASON_TITLE}</h6> + <h6> + <FormattedMessage + id="xpack.securitySolution.flyout.preview.alertReason.panelTitle" + defaultMessage="Alert reason" + /> + </h6> </EuiTitle> <EuiSpacer size="m" /> <ReasonPreviewContainerWrapper> diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx index 13be8994a7d14..68ada8b17cce8 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.test.tsx @@ -88,12 +88,16 @@ describe('<RulePreview />', () => { expect(getByTestId(RULE_PREVIEW_BODY_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RULE_PREVIEW_ABOUT_HEADER_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_PREVIEW_ABOUT_HEADER_TEST_ID)).toHaveTextContent('About'); expect(getByTestId(RULE_PREVIEW_ABOUT_CONTENT_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RULE_PREVIEW_DEFINITION_HEADER_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_PREVIEW_DEFINITION_HEADER_TEST_ID)).toHaveTextContent('Definition'); expect(getByTestId(RULE_PREVIEW_DEFINITION_CONTENT_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RULE_PREVIEW_SCHEDULE_HEADER_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_PREVIEW_SCHEDULE_HEADER_TEST_ID)).toHaveTextContent('Schedule'); expect(getByTestId(RULE_PREVIEW_SCHEDULE_CONTENT_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RULE_PREVIEW_ACTIONS_HEADER_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_PREVIEW_ACTIONS_HEADER_TEST_ID)).toHaveTextContent('Actions'); expect(getByTestId(RULE_PREVIEW_ACTIONS_CONTENT_TEST_ID)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx index d1595f7419aa0..db87a9a681902 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview.tsx @@ -6,6 +6,7 @@ */ import React, { memo, useState, useEffect } from 'react'; import { EuiText, EuiHorizontalRule, EuiSpacer, EuiPanel, EuiLoadingSpinner } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useKibana } from '../../../common/lib/kibana'; import { useGetSavedQuery } from '../../../detections/pages/detection_engine/rules/use_get_saved_query'; import type { Rule } from '../../../detection_engine/rule_management/logic'; @@ -26,7 +27,6 @@ import { RULE_PREVIEW_ACTIONS_TEST_ID, RULE_PREVIEW_LOADING_TEST_ID, } from './test_ids'; -import * as i18n from './translations'; /** * Rule summary on a preview panel on top of the right section of expandable flyout @@ -84,7 +84,12 @@ export const RulePreview: React.FC = memo(() => { <RulePreviewTitle rule={rule} isSuppressed={!isExistingRule} /> <EuiHorizontalRule margin="s" /> <ExpandableSection - title={i18n.RULE_PREVIEW_ABOUT_TEXT} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.preview.rule.aboutLabel" + defaultMessage="About" + /> + } expanded data-test-subj={RULE_PREVIEW_ABOUT_TEST_ID} > @@ -103,7 +108,12 @@ export const RulePreview: React.FC = memo(() => { {defineRuleData && !isSavedQueryLoading && ( <> <ExpandableSection - title={i18n.RULE_PREVIEW_DEFINITION_TEXT} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.preview.rule.definitionLabel" + defaultMessage="Definition" + /> + } expanded={false} data-test-subj={RULE_PREVIEW_DEFINITION_TEST_ID} > @@ -125,7 +135,12 @@ export const RulePreview: React.FC = memo(() => { {scheduleRuleData && ( <> <ExpandableSection - title={i18n.RULE_PREVIEW_SCHEDULE_TEXT} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.preview.rule.scheduleLabel" + defaultMessage="Schedule" + /> + } expanded={false} data-test-subj={RULE_PREVIEW_SCHEDULE_TEST_ID} > @@ -141,7 +156,12 @@ export const RulePreview: React.FC = memo(() => { )} {hasActions && ( <ExpandableSection - title={i18n.RULE_PREVIEW_ACTIONS_TEXT} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.preview.rule.actionsLabel" + defaultMessage="Actions" + /> + } expanded={false} data-test-subj={RULE_PREVIEW_ACTIONS_TEST_ID} > diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.test.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.test.tsx index 6a300c42976c9..383a034e55af1 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.test.tsx @@ -30,6 +30,9 @@ describe('<RulePreviewFooter />', () => { expect(getByTestId(RULE_PREVIEW_FOOTER_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RULE_PREVIEW_NAVIGATE_TO_RULE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RULE_PREVIEW_NAVIGATE_TO_RULE_TEST_ID)).toHaveTextContent( + 'Show rule details' + ); }); it('should not render rule details link when ruleId is not available', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.tsx b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.tsx index 161a28c53137d..e645a08f18197 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/components/rule_preview_footer.tsx @@ -7,9 +7,9 @@ import React, { memo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiFlyoutFooter } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { usePreviewPanelContext } from '../context'; import { RenderRuleName } from '../../../timelines/components/timeline/body/renderers/formatted_field_helpers'; -import { SHOW_RULE_DETAILS } from './translations'; import { SIGNAL_RULE_NAME_FIELD_NAME } from '../../../timelines/components/timeline/body/renderers/constants'; import { RULE_PREVIEW_FOOTER_TEST_ID } from './test_ids'; @@ -31,7 +31,9 @@ export const RulePreviewFooter: React.FC = memo(() => { isAggregatable={false} isDraggable={false} linkValue={ruleId} - value={SHOW_RULE_DETAILS} + value={i18n.translate('xpack.securitySolution.flyout.preview.rule.viewDetailsLabel', { + defaultMessage: 'Show rule details', + })} openInNewTab /> </EuiFlexItem> diff --git a/x-pack/plugins/security_solution/public/flyout/preview/components/translations.ts b/x-pack/plugins/security_solution/public/flyout/preview/components/translations.ts deleted file mode 100644 index 36bfdd33ea2ca..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/preview/components/translations.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const SHOW_RULE_DETAILS = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.viewRuleDetailsText', - { defaultMessage: 'Show rule details' } -); - -export const RULE_PREVIEW_ABOUT_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.rulePreviewAboutSectionText', - { defaultMessage: 'About' } -); - -export const RULE_PREVIEW_DEFINITION_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.rulePreviewDefinitionSectionText', - { defaultMessage: 'Definition' } -); - -export const RULE_PREVIEW_SCHEDULE_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.rulePreviewScheduleSectionText', - { defaultMessage: 'Schedule' } -); - -export const RULE_PREVIEW_ACTIONS_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.rulePreviewActionsSectionText', - { defaultMessage: 'Actions' } -); - -export const ALERT_REASON_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.alertReasonTitle', - { defaultMessage: 'Alert reason' } -); diff --git a/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx b/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx index e585c58945d9c..b5e42754a46d3 100644 --- a/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx +++ b/x-pack/plugins/security_solution/public/flyout/preview/panels.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { AlertReasonPreview } from './components/alert_reason_preview'; import type { PreviewPanelPaths } from '.'; -import { ALERT_REASON_PREVIEW, RULE_PREVIEW } from './translations'; import { RulePreview } from './components/rule_preview'; import { RulePreviewFooter } from './components/rule_preview_footer'; @@ -17,10 +16,6 @@ export type PreviewPanelType = Array<{ * Id of the preview panel */ id: PreviewPanelPaths; - /** - * Panel name - */ - name: string; /** * Main body component to be rendered in the panel */ @@ -37,13 +32,11 @@ export type PreviewPanelType = Array<{ export const panels: PreviewPanelType = [ { id: 'rule-preview', - name: RULE_PREVIEW, content: <RulePreview />, footer: <RulePreviewFooter />, }, { id: 'alert-reason-preview', - name: ALERT_REASON_PREVIEW, content: <AlertReasonPreview />, }, ]; diff --git a/x-pack/plugins/security_solution/public/flyout/preview/translations.ts b/x-pack/plugins/security_solution/public/flyout/preview/translations.ts deleted file mode 100644 index cf359e7900cea..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/preview/translations.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const RULE_PREVIEW = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.rulePreviewPanel', - { defaultMessage: 'Rule preview' } -); - -export const ALERT_REASON_PREVIEW = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.alertReasonPreviewPanel', - { defaultMessage: 'Alert reason preview' } -); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/about_section.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/about_section.tsx index d1cc1ca3f0a65..0d28b1c13f641 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/about_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/about_section.tsx @@ -8,9 +8,9 @@ import { EuiSpacer } from '@elastic/eui'; import type { VFC } from 'react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandableSection } from './expandable_section'; import { ABOUT_SECTION_TEST_ID } from './test_ids'; -import { ABOUT_TITLE } from './translations'; import { Description } from './description'; import { Reason } from './reason'; import { MitreAttack } from './mitre_attack'; @@ -29,7 +29,12 @@ export const AboutSection: VFC<AboutSectionProps> = ({ expanded = true }) => { return ( <ExpandableSection expanded={expanded} - title={ABOUT_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.sectionTitle" + defaultMessage="About" + /> + } data-test-subj={ABOUT_SECTION_TEST_ID} > <Description /> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx index 3d872640a5a22..42749285de612 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx @@ -7,9 +7,9 @@ import React, { useEffect, useMemo, useState } from 'react'; import { find } from 'lodash/fp'; import { EuiTreeView } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; import { getTreeNodes } from '../utils/analyzer_helpers'; -import { ANALYZER_PREVIEW_TITLE } from './translations'; import { ANCESTOR_ID, RULE_INDICES } from '../../shared/constants/field_names'; import { useRightPanelContext } from '../context'; import { useAlertPrevalenceFromProcessTree } from '../../../common/containers/alerts/use_alert_prevalence_from_process_tree'; @@ -67,7 +67,12 @@ export const AnalyzerPreview: React.FC = () => { <EuiTreeView items={items} display="compressed" - aria-label={ANALYZER_PREVIEW_TITLE} + aria-label={i18n.translate( + 'xpack.securitySolution.flyout.right.visualizations.analyzerPreview.treeViewAriaLabel', + { + defaultMessage: 'Analyzer preview', + } + )} showExpansionArrows /> </div> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx index cecddeec1b987..4e764483680b5 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { RightPanelContext } from '../context'; import { AnalyzerPreviewContainer } from './analyzer_preview_container'; import { isInvestigateInResolverActionEnabled } from '../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver'; -import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; +import { ANALYZER_PREVIEW_NO_DATA_TEST_ID, ANALYZER_PREVIEW_TEST_ID } from './test_ids'; import { useAlertPrevalenceFromProcessTree } from '../../../common/containers/alerts/use_alert_prevalence_from_process_tree'; import * as mock from '../mocks/mock_analyzer_data'; import { @@ -38,9 +38,6 @@ const panelContextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, } as unknown as RightPanelContext; -const TEST_ID = ANALYZER_PREVIEW_TEST_ID; -const ERROR_TEST_ID = `${ANALYZER_PREVIEW_TEST_ID}Error`; - const renderAnalyzerPreview = () => render( <TestProviders> @@ -69,8 +66,8 @@ describe('AnalyzerPreviewContainer', () => { const { getByTestId, queryByTestId } = renderAnalyzerPreview(); - expect(getByTestId(TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(ERROR_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(ANALYZER_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(ANALYZER_PREVIEW_NO_DATA_TEST_ID)).not.toBeInTheDocument(); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) ).toBeInTheDocument(); @@ -96,8 +93,11 @@ describe('AnalyzerPreviewContainer', () => { const { getByTestId, queryByTestId } = renderAnalyzerPreview(); - expect(queryByTestId(TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(ERROR_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(ANALYZER_PREVIEW_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(ANALYZER_PREVIEW_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(ANALYZER_PREVIEW_NO_DATA_TEST_ID)).toHaveTextContent( + 'You can only visualize events triggered by hosts configured with the Elastic Defend integration or any sysmon data from winlogbeat. Refer to Visual event analyzerExternal link(opens in a new tab or window) for more information.' + ); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(ANALYZER_PREVIEW_TEST_ID)) ).toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx index ede2169fce268..fd582b37d6fcb 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview_container.tsx @@ -18,8 +18,7 @@ import { setActiveTabTimeline } from '../../../timelines/store/timeline/actions' import { useRightPanelContext } from '../context'; import { isInvestigateInResolverActionEnabled } from '../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver'; import { AnalyzerPreview } from './analyzer_preview'; -import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; -import { ANALYZER_PREVIEW_TITLE } from './translations'; +import { ANALYZER_PREVIEW_NO_DATA_TEST_ID, ANALYZER_PREVIEW_TEST_ID } from './test_ids'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; const timelineId = 'timeline-1'; @@ -58,7 +57,12 @@ export const AnalyzerPreviewContainer: React.FC = () => { return ( <ExpandablePanel header={{ - title: ANALYZER_PREVIEW_TITLE, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.visualizations.analyzerPreview.analyzerPreviewTitle" + defaultMessage="Analyzer preview" + /> + ), iconType: 'timeline', ...(isEnabled && { callback: goToAnalyzerTab }), }} @@ -67,9 +71,9 @@ export const AnalyzerPreviewContainer: React.FC = () => { {isEnabled ? ( <AnalyzerPreview /> ) : ( - <div data-test-subj={`${ANALYZER_PREVIEW_TEST_ID}Error`}> + <p data-test-subj={ANALYZER_PREVIEW_NO_DATA_TEST_ID}> <FormattedMessage - id="xpack.securitySolution.flyout.analyzerPreviewError" + id="xpack.securitySolution.flyout.right.visualizations.analyzerPreview.noDataDescription" defaultMessage="You can only visualize events triggered by hosts configured with the Elastic Defend integration or any {sysmon} data from {winlogbeat}. Refer to {link} for more information." values={{ sysmon: <EuiMark>{'sysmon'}</EuiMark>, @@ -80,14 +84,14 @@ export const AnalyzerPreviewContainer: React.FC = () => { target="_blank" > <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.analyzerPreviewErrorLink" + id="xpack.securitySolution.flyout.right.visualizations.analyzerPreview.noDataLinkText" defaultMessage="Visual event analyzer" /> </EuiLink> ), }} /> - </div> + </p> )} </ExpandablePanel> ); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx index 664b90a54b767..a579c124539d1 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.test.tsx @@ -14,6 +14,7 @@ import { CorrelationsOverview } from './correlations_overview'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import { + INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID, INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID, INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID, INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID, @@ -74,7 +75,6 @@ const RELATED_ALERTS_BY_SESSION_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( const RELATED_CASES_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID( INSIGHTS_CORRELATIONS_RELATED_CASES_TEST_ID ); -const CORRELATIONS_ERROR_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}Error`; const panelContextValue = { eventId: 'event id', @@ -141,12 +141,13 @@ describe('<CorrelationsOverview />', () => { dataCount: 1, }); - const { getByTestId } = render(renderCorrelationsOverview(panelContextValue)); + const { getByTestId, queryByTestId } = render(renderCorrelationsOverview(panelContextValue)); expect(getByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RELATED_CASES_TEST_ID)).toBeInTheDocument(); expect(getByTestId(SUPPRESSED_ALERTS_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should hide rows and show error message if show values are false', () => { @@ -168,7 +169,10 @@ describe('<CorrelationsOverview />', () => { expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_CASES_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(SUPPRESSED_ALERTS_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(CORRELATIONS_ERROR_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID)).toHaveTextContent( + 'No correlations data available.' + ); }); it('should hide rows if values are null', () => { @@ -184,6 +188,7 @@ describe('<CorrelationsOverview />', () => { expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(RELATED_CASES_TEST_ID)).not.toBeInTheDocument(); expect(queryByTestId(SUPPRESSED_ALERTS_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should navigate to the left section Insights tab when clicking on button', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx index 750d260bbf21f..675e520c4bfb2 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx @@ -8,6 +8,7 @@ import React, { useCallback } from 'react'; import { EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { useShowRelatedAlertsBySession } from '../../shared/hooks/use_show_related_alerts_by_session'; import { RelatedAlertsBySession } from './related_alerts_by_session'; @@ -19,9 +20,8 @@ import { SuppressedAlerts } from './suppressed_alerts'; import { useShowSuppressedAlerts } from '../../shared/hooks/use_show_suppressed_alerts'; import { RelatedCases } from './related_cases'; import { useShowRelatedCases } from '../../shared/hooks/use_show_related_cases'; -import { INSIGHTS_CORRELATIONS_TEST_ID } from './test_ids'; +import { INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID, INSIGHTS_CORRELATIONS_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; -import { CORRELATIONS_ERROR, CORRELATIONS_TITLE } from './translations'; import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; @@ -84,7 +84,12 @@ export const CorrelationsOverview: React.FC = () => { return ( <ExpandablePanel header={{ - title: CORRELATIONS_TITLE, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.correlations.overviewTitle" + defaultMessage="Correlations" + /> + ), callback: goToCorrelationsTab, iconType: 'arrowStart', }} @@ -107,7 +112,12 @@ export const CorrelationsOverview: React.FC = () => { )} </EuiFlexGroup> ) : ( - <div data-test-subj={`${INSIGHTS_CORRELATIONS_TEST_ID}Error`}>{CORRELATIONS_ERROR}</div> + <p data-test-subj={INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.correlations.noDataDescription" + defaultMessage="No correlations data available." + /> + </p> )} </ExpandablePanel> ); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx index 48b12f31599cf..5b94bff38c3d9 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/description.test.tsx @@ -6,13 +6,9 @@ */ import React from 'react'; +import { FormattedMessage, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { DESCRIPTION_TITLE_TEST_ID, RULE_SUMMARY_BUTTON_TEST_ID } from './test_ids'; -import { - DOCUMENT_DESCRIPTION_TITLE, - PREVIEW_RULE_DETAILS, - RULE_DESCRIPTION_TITLE, -} from './translations'; import { Description } from './description'; import { RightPanelContext } from '../context'; import { mockGetFieldsData } from '../mocks/mock_context'; @@ -59,11 +55,13 @@ const panelContextValue = (dataFormattedForFieldBrowser: TimelineEventsDetailsIt const renderDescription = (panelContext: RightPanelContext) => render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContext}> - <Description /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> + <IntlProvider locale="en"> + <ExpandableFlyoutContext.Provider value={flyoutContextValue}> + <RightPanelContext.Provider value={panelContext}> + <Description /> + </RightPanelContext.Provider> + </ExpandableFlyoutContext.Provider> + </IntlProvider> ); describe('<Description />', () => { @@ -73,7 +71,7 @@ describe('<Description />', () => { ); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent(RULE_DESCRIPTION_TITLE); + expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent('Rule description'); expect(getByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).toBeInTheDocument(); }); @@ -83,7 +81,7 @@ describe('<Description />', () => { ); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent(RULE_DESCRIPTION_TITLE); + expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent('Rule description'); expect(queryByTestId(RULE_SUMMARY_BUTTON_TEST_ID)).not.toBeInTheDocument(); }); @@ -91,7 +89,7 @@ describe('<Description />', () => { const { getByTestId } = renderDescription(panelContextValue([ruleDescription])); expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent(DOCUMENT_DESCRIPTION_TITLE); + expect(getByTestId(DESCRIPTION_TITLE_TEST_ID)).toHaveTextContent('Document description'); }); it('should open preview panel when clicking on button', () => { @@ -109,7 +107,12 @@ describe('<Description />', () => { indexName: panelContext.indexName, scopeId: panelContext.scopeId, banner: { - title: PREVIEW_RULE_DETAILS, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.description.rulePreviewTitle" + defaultMessage="Preview rule details" + /> + ), backgroundColor: 'warning', textColor: 'warning', }, diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx index 521609a4c267c..ac8ec64a0ee34 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/description.tsx @@ -10,6 +10,7 @@ import type { FC } from 'react'; import React, { useMemo, useCallback } from 'react'; import { isEmpty } from 'lodash'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useRightPanelContext } from '../context'; import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; import { @@ -17,12 +18,6 @@ import { DESCRIPTION_TITLE_TEST_ID, RULE_SUMMARY_BUTTON_TEST_ID, } from './test_ids'; -import { - DOCUMENT_DESCRIPTION_TITLE, - RULE_DESCRIPTION_TITLE, - RULE_SUMMARY_TEXT, - PREVIEW_RULE_DETAILS, -} from './translations'; import { PreviewPanelKey, type PreviewPanelProps, RulePreviewPanel } from '../../preview'; /** @@ -45,7 +40,12 @@ export const Description: FC = () => { indexName, scopeId, banner: { - title: PREVIEW_RULE_DETAILS, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.description.rulePreviewTitle" + defaultMessage="Preview rule details" + /> + ), backgroundColor: 'warning', textColor: 'warning', }, @@ -66,7 +66,10 @@ export const Description: FC = () => { iconSide="right" data-test-subj={RULE_SUMMARY_BUTTON_TEST_ID} > - {RULE_SUMMARY_TEXT} + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.description.ruleSummaryButtonLabel" + defaultMessage="Show rule summary" + /> </EuiButtonEmpty> </EuiFlexItem> ), @@ -82,12 +85,22 @@ export const Description: FC = () => { {isAlert ? ( <EuiFlexGroup justifyContent="spaceBetween" alignItems="center"> <EuiFlexItem> - <h5>{RULE_DESCRIPTION_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.description.ruleTitle" + defaultMessage="Rule description" + /> + </h5> </EuiFlexItem> {viewRule} </EuiFlexGroup> ) : ( - <h5>{DOCUMENT_DESCRIPTION_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.description.documentTitle" + defaultMessage="Document description" + /> + </h5> )} </EuiTitle> </EuiFlexItem> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx index 9c79f100bf9e2..67ccba02712ed 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.test.tsx @@ -54,7 +54,7 @@ describe('<EntitiesOverview />', () => { }); it('should render user and host', () => { - const { getByTestId } = render( + const { getByTestId, queryByTestId } = render( <TestProviders> <RightPanelContext.Provider value={mockContextValue}> <EntitiesOverview /> @@ -63,6 +63,7 @@ describe('<EntitiesOverview />', () => { ); expect(getByTestId(ENTITIES_USER_OVERVIEW_TEST_ID)).toBeInTheDocument(); expect(getByTestId(ENTITIES_HOST_OVERVIEW_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should only render user when host name is null', () => { @@ -81,6 +82,7 @@ describe('<EntitiesOverview />', () => { expect(getByTestId(ENTITIES_USER_OVERVIEW_TEST_ID)).toBeInTheDocument(); expect(queryByTestId(ENTITIES_HOST_OVERVIEW_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should only render host when user name is null', () => { @@ -99,6 +101,7 @@ describe('<EntitiesOverview />', () => { expect(getByTestId(ENTITIES_HOST_OVERVIEW_TEST_ID)).toBeInTheDocument(); expect(queryByTestId(ENTITIES_USER_OVERVIEW_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render no data message if both host name and user name are null/blank', () => { @@ -116,5 +119,8 @@ describe('<EntitiesOverview />', () => { ); expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(INSIGHTS_ENTITIES_NO_DATA_TEST_ID)).toHaveTextContent( + 'Host and user information are unavailable for this alert.' + ); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx index 920b54be950c1..ff2c314ec76f4 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/entities_overview.tsx @@ -8,10 +8,10 @@ import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { INSIGHTS_ENTITIES_NO_DATA_TEST_ID, INSIGHTS_ENTITIES_TEST_ID } from './test_ids'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { useRightPanelContext } from '../context'; -import { ENTITIES_NO_DATA_MESSAGE, ENTITIES_TITLE } from './translations'; import { getField } from '../../shared/utils'; import { HostEntityOverview } from './host_entity_overview'; import { UserEntityOverview } from './user_entity_overview'; @@ -46,7 +46,12 @@ export const EntitiesOverview: React.FC = () => { <> <ExpandablePanel header={{ - title: ENTITIES_TITLE, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.entities.entitiesTitle" + defaultMessage="Entities" + /> + ), callback: goToEntitiesTab, iconType: 'arrowStart', }} @@ -67,7 +72,12 @@ export const EntitiesOverview: React.FC = () => { )} </EuiFlexGroup> ) : ( - <div data-test-subj={INSIGHTS_ENTITIES_NO_DATA_TEST_ID}>{ENTITIES_NO_DATA_MESSAGE}</div> + <p data-test-subj={INSIGHTS_ENTITIES_NO_DATA_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.entities.noDataDescription" + defaultMessage="Host and user information are unavailable for this alert." + /> + </p> )} </ExpandablePanel> </> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.test.tsx index b1d893b19a153..55a371e4a640c 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { RightPanelContext } from '../context'; import { ExpandDetailButton } from './expand_detail_button'; @@ -13,6 +14,20 @@ import { COLLAPSE_DETAILS_BUTTON_TEST_ID, EXPAND_DETAILS_BUTTON_TEST_ID } from ' import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { LeftPanelKey } from '../../left'; +const renderExpandDetailButton = ( + flyoutContextValue: ExpandableFlyoutContext, + panelContextValue: RightPanelContext +) => + render( + <IntlProvider locale="en"> + <ExpandableFlyoutContext.Provider value={flyoutContextValue}> + <RightPanelContext.Provider value={panelContextValue}> + <ExpandDetailButton /> + </RightPanelContext.Provider> + </ExpandableFlyoutContext.Provider> + </IntlProvider> + ); + describe('<ExpandDetailButton />', () => { it('should render expand button', () => { const flyoutContextValue = { @@ -25,15 +40,14 @@ describe('<ExpandDetailButton />', () => { scopeId: 'scopeId', } as unknown as RightPanelContext; - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContextValue}> - <ExpandDetailButton /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> + const { getByTestId, queryByTestId } = renderExpandDetailButton( + flyoutContextValue, + panelContextValue ); expect(getByTestId(EXPAND_DETAILS_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(EXPAND_DETAILS_BUTTON_TEST_ID)).toHaveTextContent('Expand details'); + expect(queryByTestId(COLLAPSE_DETAILS_BUTTON_TEST_ID)).not.toBeInTheDocument(); getByTestId(EXPAND_DETAILS_BUTTON_TEST_ID).click(); expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ @@ -55,15 +69,14 @@ describe('<ExpandDetailButton />', () => { } as unknown as ExpandableFlyoutContext; const panelContextValue = {} as unknown as RightPanelContext; - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContextValue}> - <ExpandDetailButton /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> + const { getByTestId, queryByTestId } = renderExpandDetailButton( + flyoutContextValue, + panelContextValue ); expect(getByTestId(COLLAPSE_DETAILS_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(COLLAPSE_DETAILS_BUTTON_TEST_ID)).toHaveTextContent('Collapse details'); + expect(queryByTestId(EXPAND_DETAILS_BUTTON_TEST_ID)).not.toBeInTheDocument(); getByTestId(COLLAPSE_DETAILS_BUTTON_TEST_ID).click(); expect(flyoutContextValue.closeLeftPanel).toHaveBeenCalled(); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.tsx index 4e02f423d1720..f066e1d411ddf 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/expand_detail_button.tsx @@ -9,10 +9,10 @@ import { EuiButtonEmpty } from '@elastic/eui'; import type { FC } from 'react'; import React, { memo, useCallback } from 'react'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { COLLAPSE_DETAILS_BUTTON_TEST_ID, EXPAND_DETAILS_BUTTON_TEST_ID } from './test_ids'; import { LeftPanelKey } from '../../left'; import { useRightPanelContext } from '../context'; -import { COLLAPSE_DETAILS_BUTTON, EXPAND_DETAILS_BUTTON } from './translations'; /** * Button displayed in the top left corner of the panel, to expand the left section of the document details expandable flyout @@ -43,7 +43,10 @@ export const ExpandDetailButton: FC = memo(() => { iconType="arrowEnd" data-test-subj={COLLAPSE_DETAILS_BUTTON_TEST_ID} > - {COLLAPSE_DETAILS_BUTTON} + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.collapseDetailButtonLabel" + defaultMessage="Collapse details" + /> </EuiButtonEmpty> ) : ( <EuiButtonEmpty @@ -52,7 +55,10 @@ export const ExpandDetailButton: FC = memo(() => { iconType="arrowStart" data-test-subj={EXPAND_DETAILS_BUTTON_TEST_ID} > - {EXPAND_DETAILS_BUTTON} + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.expandDetailButtonLabel" + defaultMessage="Expand details" + /> </EuiButtonEmpty> ); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.stories.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.stories.tsx index 64411fbe69513..bb315fe04ac2e 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.stories.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.stories.tsx @@ -9,7 +9,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { ExpandableSection } from './expandable_section'; -const title = 'title'; +const title = <p>{'title'}</p>; const children = <div>{'content'}</div>; export default { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.test.tsx index e0d08e260f944..cad0c5563f629 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { CONTENT_TEST_ID, ExpandableSection, HEADER_TEST_ID } from './expandable_section'; -const title = 'title'; +const title = <p>{'title'}</p>; const children = <div>{'content'}</div>; const testId = 'test'; const headerTestId = testId + HEADER_TEST_ID; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.tsx index 0e59643ae3d27..d3c95661f7fe5 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/expandable_section.tsx @@ -6,6 +6,7 @@ */ import { EuiAccordion, EuiFlexGroup, EuiSpacer, EuiTitle, useGeneratedHtmlId } from '@elastic/eui'; +import type { ReactElement } from 'react'; import React, { type VFC } from 'react'; import { useAccordionState } from '../hooks/use_accordion_state'; @@ -20,7 +21,7 @@ export interface DescriptionSectionProps { /** * Title value to render in the header of the accordion */ - title: string; + title: ReactElement; /** * React component to render in the expandable section of the accordion */ diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/header_title.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/header_title.test.tsx index 3256d3c3895cd..0495198cd152d 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/header_title.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/header_title.test.tsx @@ -17,7 +17,6 @@ import { FLYOUT_HEADER_TITLE_TEST_ID, } from './test_ids'; import { HeaderTitle } from './header_title'; -import { EVENT_DETAILS } from './translations'; import moment from 'moment-timezone'; import { useDateFormat, useTimeZone } from '../../../common/lib/kibana'; import { mockDataFormattedForFieldBrowser, mockGetFieldsData } from '../mocks/mock_context'; @@ -118,6 +117,6 @@ describe('<HeaderTitle />', () => { const { getByTestId } = renderHeader(contextValue); - expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent(EVENT_DETAILS); + expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent('Event details'); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx index 716db70b60947..d3badd25eaa24 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx @@ -11,6 +11,7 @@ import { NewChatById } from '@kbn/elastic-assistant'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; import { isEmpty } from 'lodash'; import { css } from '@emotion/react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useGetAlertDetailsFlyoutLink } from '../../../timelines/components/side_panel/event_details/use_get_alert_details_flyout_link'; import { DocumentStatus } from './status'; import { useAssistant } from '../hooks/use_assistant'; @@ -20,7 +21,6 @@ import { } from '../../../common/components/event_details/translations'; import { DocumentSeverity } from './severity'; import { RiskScore } from './risk_score'; -import { EVENT_DETAILS } from './translations'; import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; import { useRightPanelContext } from '../context'; import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; @@ -87,7 +87,14 @@ export const HeaderTitle: VFC<HeaderTitleProps> = memo(({ flyoutIsExpandable }) <EuiSpacer size="s" /> <EuiTitle size="s"> <h4 data-test-subj={FLYOUT_HEADER_TITLE_TEST_ID}> - {isAlert && !isEmpty(ruleName) ? ruleName : EVENT_DETAILS} + {isAlert && !isEmpty(ruleName) ? ( + ruleName + ) : ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.headerTitle" + defaultMessage="Event details" + /> + )} </h4> </EuiTitle> <EuiSpacer size="s" /> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx index f6944df60396a..d47ab0c4b3c02 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx @@ -9,6 +9,7 @@ import type { FC } from 'react'; import React, { useMemo } from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, EuiPanel, EuiTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { getSourcererScopeId } from '../../../helpers'; import { convertHighlightedFieldsToTableRow } from '../../shared/utils/highlighted_fields_helpers'; import { useRuleWithFallback } from '../../../detection_engine/rule_management/logic/use_rule_with_fallback'; @@ -20,11 +21,6 @@ import { SecurityCellActionsTrigger, } from '../../../common/components/cell_actions'; import { HIGHLIGHTED_FIELDS_DETAILS_TEST_ID, HIGHLIGHTED_FIELDS_TITLE_TEST_ID } from './test_ids'; -import { - HIGHLIGHTED_FIELDS_FIELD_COLUMN, - HIGHLIGHTED_FIELDS_TITLE, - HIGHLIGHTED_FIELDS_VALUE_COLUMN, -} from './translations'; import { useRightPanelContext } from '../context'; import { useHighlightedFields } from '../../shared/hooks/use_highlighted_fields'; @@ -52,13 +48,23 @@ export interface HighlightedFieldsTableRow { const columns: Array<EuiBasicTableColumn<HighlightedFieldsTableRow>> = [ { field: 'field', - name: HIGHLIGHTED_FIELDS_FIELD_COLUMN, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.investigation.highlightedFields.tableFieldColumnLabel" + defaultMessage="Field" + /> + ), 'data-test-subj': 'fieldCell', width: '50%', }, { field: 'description', - name: HIGHLIGHTED_FIELDS_VALUE_COLUMN, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.investigation.highlightedFields.tableValueColumnLabel" + defaultMessage="Value" + /> + ), 'data-test-subj': 'valueCell', width: '50%', render: (description: { @@ -108,7 +114,12 @@ export const HighlightedFields: FC = () => { <EuiFlexGroup direction="column" gutterSize="s"> <EuiFlexItem data-test-subj={HIGHLIGHTED_FIELDS_TITLE_TEST_ID}> <EuiTitle size="xxs"> - <h5>{HIGHLIGHTED_FIELDS_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.right.investigation.highlightedFields.highlightedFieldsTitle" + defaultMessage="Highlighted fields" + /> + </h5> </EuiTitle> </EuiFlexItem> <EuiFlexItem data-test-subj={HIGHLIGHTED_FIELDS_DETAILS_TEST_ID}> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx index 88804ffb97d12..60d045006ac49 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/host_entity_overview.tsx @@ -18,6 +18,7 @@ import { import { css } from '@emotion/css'; import { getOr } from 'lodash/fp'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useRightPanelContext } from '../context'; import type { DescriptionList } from '../../../../common/utility_types'; import { @@ -44,7 +45,6 @@ import { ENTITIES_HOST_OVERVIEW_LINK_TEST_ID, TECHNICAL_PREVIEW_ICON_TEST_ID, } from './test_ids'; -import { TECHNICAL_PREVIEW_TITLE, TECHNICAL_PREVIEW_MESSAGE } from './translations'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; const HOST_ICON = 'storage'; @@ -150,10 +150,20 @@ export const HostEntityOverview: React.FC<HostEntityOverviewProps> = ({ hostName <> {i18n.HOST_RISK_CLASSIFICATION} <EuiIconTip - title={TECHNICAL_PREVIEW_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.entities.hostTechnicalPreviewButtonLabel" + defaultMessage="Technical preview" + /> + } size="m" type="iInCircle" - content={TECHNICAL_PREVIEW_MESSAGE} + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.entities.hostTechnicalPreviewTooltip" + defaultMessage="This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but features in technical preview are not subject to the support SLA of official GA features." + /> + } position="bottom" iconProps={{ className: 'eui-alignTop', diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx index 86d0447a5a590..a51d5c8fec3fb 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { CorrelationsOverview } from './correlations_overview'; import { PrevalenceOverview } from './prevalence_overview'; import { ThreatIntelligenceOverview } from './threat_intelligence_overview'; import { INSIGHTS_TEST_ID } from './test_ids'; -import { INSIGHTS_TITLE } from './translations'; import { EntitiesOverview } from './entities_overview'; import { ExpandableSection } from './expandable_section'; @@ -27,7 +27,16 @@ export interface InsightsSectionProps { */ export const InsightsSection: React.FC<InsightsSectionProps> = ({ expanded = false }) => { return ( - <ExpandableSection title={INSIGHTS_TITLE} expanded={expanded} data-test-subj={INSIGHTS_TEST_ID}> + <ExpandableSection + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.sectionTitle" + defaultMessage="Insights" + /> + } + expanded={expanded} + data-test-subj={INSIGHTS_TEST_ID} + > <EntitiesOverview /> <EuiSpacer size="s" /> <ThreatIntelligenceOverview /> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx index f3d8e6d25d9d5..8a981d037667f 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import type { VFC } from 'react'; +import type { ReactElement, VFC } from 'react'; import React from 'react'; import { css } from '@emotion/react'; import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiSkeletonText } from '@elastic/eui'; @@ -31,7 +31,7 @@ export interface InsightsSummaryRowProps { /** * Text corresponding of the number of results/entries */ - text: string; + text: string | ReactElement; /** * Optional parameter for now, will be used to display a dot on the right side * (corresponding to some sort of severity?) diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx index a3d6c932b6f14..22f7f4502858a 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { InvestigationGuide } from './investigation_guide'; import { RightPanelContext } from '../context'; @@ -13,20 +14,24 @@ import { INVESTIGATION_GUIDE_BUTTON_TEST_ID, INVESTIGATION_GUIDE_LOADING_TEST_ID, INVESTIGATION_GUIDE_NO_DATA_TEST_ID, + INVESTIGATION_GUIDE_TEST_ID, } from './test_ids'; import { mockContextValue } from '../mocks/mock_right_panel_context'; import { mockFlyoutContextValue } from '../../shared/mocks/mock_flyout_context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { useInvestigationGuide } from '../../shared/hooks/use_investigation_guide'; +import { LeftPanelInvestigationTab, LeftPanelKey } from '../../left'; jest.mock('../../shared/hooks/use_investigation_guide'); -const renderInvestigationGuide = (context: RightPanelContext = mockContextValue) => ( - <ExpandableFlyoutContext.Provider value={mockFlyoutContextValue}> - <RightPanelContext.Provider value={context}> - <InvestigationGuide /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> +const renderInvestigationGuide = () => ( + <IntlProvider locale="en"> + <ExpandableFlyoutContext.Provider value={mockFlyoutContextValue}> + <RightPanelContext.Provider value={mockContextValue}> + <InvestigationGuide /> + </RightPanelContext.Provider> + </ExpandableFlyoutContext.Provider> + </IntlProvider> ); describe('<InvestigationGuide />', () => { @@ -37,16 +42,26 @@ describe('<InvestigationGuide />', () => { basicAlertData: { ruleId: 'ruleId' }, ruleNote: 'test note', }); - const { getByTestId } = render(renderInvestigationGuide()); + const { getByTestId, queryByTestId } = render(renderInvestigationGuide()); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toHaveTextContent('Investigation guide'); expect(getByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).toHaveTextContent( + 'Show investigation guide' + ); + expect(queryByTestId(INVESTIGATION_GUIDE_LOADING_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render loading', () => { (useInvestigationGuide as jest.Mock).mockReturnValue({ loading: true, }); - const { getByTestId } = render(renderInvestigationGuide()); + const { getByTestId, queryByTestId } = render(renderInvestigationGuide()); expect(getByTestId(INVESTIGATION_GUIDE_LOADING_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(INVESTIGATION_GUIDE_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render no data message when there is no ruleId', () => { @@ -54,8 +69,12 @@ describe('<InvestigationGuide />', () => { basicAlertData: {}, ruleNote: 'test note', }); - const { getByTestId } = render(renderInvestigationGuide()); + const { getByTestId, queryByTestId } = render(renderInvestigationGuide()); + expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( + 'There’s no investigation guide for this rule.' + ); }); it('should render no data message when there is no rule note', () => { @@ -63,18 +82,45 @@ describe('<InvestigationGuide />', () => { basicAlertData: { ruleId: 'ruleId' }, ruleNote: undefined, }); - const { getByTestId } = render(renderInvestigationGuide()); + const { getByTestId, queryByTestId } = render(renderInvestigationGuide()); + expect(queryByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID)).not.toBeInTheDocument(); expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toHaveTextContent( + 'There’s no investigation guide for this rule.' + ); }); it('should render no data message when useInvestigationGuide errors out', () => { (useInvestigationGuide as jest.Mock).mockReturnValue({ loading: false, error: true, - show: false, }); const { getByTestId } = render(renderInvestigationGuide()); expect(getByTestId(INVESTIGATION_GUIDE_NO_DATA_TEST_ID)).toBeInTheDocument(); }); + + it('should navigate to investigation guide when clicking on button', () => { + (useInvestigationGuide as jest.Mock).mockReturnValue({ + loading: false, + error: false, + basicAlertData: { ruleId: 'ruleId' }, + ruleNote: 'test note', + }); + + const { getByTestId } = render(renderInvestigationGuide()); + getByTestId(INVESTIGATION_GUIDE_BUTTON_TEST_ID).click(); + + expect(mockFlyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ + id: LeftPanelKey, + path: { + tab: LeftPanelInvestigationTab, + }, + params: { + id: mockContextValue.eventId, + indexName: mockContextValue.indexName, + scopeId: mockContextValue.scopeId, + }, + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx index 2175e67bbef53..a033ee74ddabf 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_guide.tsx @@ -7,6 +7,7 @@ import React, { useCallback } from 'react'; import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiTitle } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useInvestigationGuide } from '../../shared/hooks/use_investigation_guide'; import { useRightPanelContext } from '../context'; import { LeftPanelKey, LeftPanelInvestigationTab } from '../../left'; @@ -16,11 +17,6 @@ import { INVESTIGATION_GUIDE_NO_DATA_TEST_ID, INVESTIGATION_GUIDE_TEST_ID, } from './test_ids'; -import { - INVESTIGATION_GUIDE_BUTTON, - INVESTIGATION_GUIDE_NO_DATA, - INVESTIGATION_GUIDE_TITLE, -} from './translations'; /** * Render either the investigation guide button that opens Investigation section in the left panel, @@ -65,7 +61,12 @@ export const InvestigationGuide: React.FC = () => { <EuiFlexGroup direction="column" gutterSize="s"> <EuiFlexItem data-test-subj={INVESTIGATION_GUIDE_TEST_ID}> <EuiTitle size="xxs"> - <h5>{INVESTIGATION_GUIDE_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.right.investigation.investigationGuide.investigationGuideTitle" + defaultMessage="Investigation guide" + /> + </h5> </EuiTitle> </EuiFlexItem> <EuiFlexItem> @@ -75,12 +76,18 @@ export const InvestigationGuide: React.FC = () => { iconType="documentation" data-test-subj={INVESTIGATION_GUIDE_BUTTON_TEST_ID} > - {INVESTIGATION_GUIDE_BUTTON} + <FormattedMessage + id="xpack.securitySolution.flyout.right.investigation.investigationGuide.investigationGuideButtonLabel" + defaultMessage="Show investigation guide" + /> </EuiButton> ) : ( - <div data-test-subj={INVESTIGATION_GUIDE_NO_DATA_TEST_ID}> - {INVESTIGATION_GUIDE_NO_DATA} - </div> + <p data-test-subj={INVESTIGATION_GUIDE_NO_DATA_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.right.investigation.investigationGuide.noDataDescription" + defaultMessage="There’s no investigation guide for this rule." + /> + </p> )} </EuiFlexItem> </EuiFlexGroup> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.test.tsx index 2d4141c4207a8..d7dea0bf1c92d 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { INVESTIGATION_SECTION_CONTENT_TEST_ID, @@ -25,44 +26,37 @@ const panelContextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, } as unknown as RightPanelContext; +const renderInvestigationSection = (expanded: boolean = false) => + render( + <IntlProvider locale="en"> + <ExpandableFlyoutContext.Provider value={flyoutContextValue}> + <RightPanelContext.Provider value={panelContextValue}> + <InvestigationSection expanded={expanded} /> + </RightPanelContext.Provider> + </ExpandableFlyoutContext.Provider> + </IntlProvider> + ); + describe('<InvestigationSection />', () => { beforeEach(() => { jest.clearAllMocks(); mockUseRuleWithFallback.mockReturnValue({ rule: { note: 'test note' } }); }); it('should render the component collapsed', () => { - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContextValue}> - <InvestigationSection /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> - ); + const { getByTestId } = renderInvestigationSection(); expect(getByTestId(INVESTIGATION_SECTION_HEADER_TEST_ID)).toBeInTheDocument(); }); it('should render the component expanded', () => { - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContextValue}> - <InvestigationSection expanded={true} /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> - ); + const { getByTestId } = renderInvestigationSection(true); expect(getByTestId(INVESTIGATION_SECTION_HEADER_TEST_ID)).toBeInTheDocument(); expect(getByTestId(INVESTIGATION_SECTION_CONTENT_TEST_ID)).toBeInTheDocument(); }); it('should expand the component when clicking on the arrow on header', () => { - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContextValue}> - <InvestigationSection /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> - ); + const { getByTestId } = renderInvestigationSection(); getByTestId(INVESTIGATION_SECTION_HEADER_TEST_ID).click(); expect(getByTestId(INVESTIGATION_SECTION_CONTENT_TEST_ID)).toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.tsx index 655aa13ea177b..2cf91392ff154 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.tsx @@ -8,10 +8,10 @@ import type { VFC } from 'react'; import React from 'react'; import { EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandableSection } from './expandable_section'; import { HighlightedFields } from './highlighted_fields'; import { INVESTIGATION_SECTION_TEST_ID } from './test_ids'; -import { INVESTIGATION_TITLE } from './translations'; import { InvestigationGuide } from './investigation_guide'; export interface DescriptionSectionProps { /** @@ -27,7 +27,12 @@ export const InvestigationSection: VFC<DescriptionSectionProps> = ({ expanded = return ( <ExpandableSection expanded={expanded} - title={INVESTIGATION_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.investigation.sectionTitle" + defaultMessage="Investigation" + /> + } data-test-subj={INVESTIGATION_SECTION_TEST_ID} > <InvestigationGuide /> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx index affaaca1e27bf..1c348f90b8627 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx @@ -9,7 +9,7 @@ import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { render } from '@testing-library/react'; import { TestProviders } from '../../../common/mock'; import { RightPanelContext } from '../context'; -import { INSIGHTS_PREVALENCE_TEST_ID } from './test_ids'; +import { INSIGHTS_PREVALENCE_NO_DATA_TEST_ID, INSIGHTS_PREVALENCE_TEST_ID } from './test_ids'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import React from 'react'; import { PrevalenceOverview } from './prevalence_overview'; @@ -68,11 +68,12 @@ describe('<PrevalenceOverview />', () => { data: [], }); - const { getByTestId } = render(renderPrevalenceOverview()); + const { getByTestId, queryByTestId } = render(renderPrevalenceOverview()); expect( getByTestId(EXPANDABLE_PANEL_LOADING_TEST_ID(INSIGHTS_PREVALENCE_TEST_ID)) ).toBeInTheDocument(); + expect(queryByTestId(INSIGHTS_PREVALENCE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should render no-data message', () => { @@ -84,7 +85,10 @@ describe('<PrevalenceOverview />', () => { const { getByTestId } = render(renderPrevalenceOverview()); - expect(getByTestId(`${INSIGHTS_PREVALENCE_TEST_ID}Error`)).toBeInTheDocument(); + expect(getByTestId(INSIGHTS_PREVALENCE_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(INSIGHTS_PREVALENCE_NO_DATA_TEST_ID)).toHaveTextContent( + 'No prevalence data available.' + ); }); it('should render only data with prevalence less than 10%', () => { @@ -127,6 +131,8 @@ describe('<PrevalenceOverview />', () => { const valueDataTestSubj2 = `${INSIGHTS_PREVALENCE_TEST_ID}${field2}Value`; expect(queryByTestId(iconDataTestSubj2)).not.toBeInTheDocument(); expect(queryByTestId(valueDataTestSubj2)).not.toBeInTheDocument(); + + expect(queryByTestId(INSIGHTS_PREVALENCE_NO_DATA_TEST_ID)).not.toBeInTheDocument(); }); it('should navigate to left section Insights tab when clicking on button', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx index 53e2d636d4bb6..e82219504dba1 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx @@ -9,11 +9,11 @@ import type { FC } from 'react'; import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; -import { INSIGHTS_PREVALENCE_TEST_ID } from './test_ids'; +import { INSIGHTS_PREVALENCE_NO_DATA_TEST_ID, INSIGHTS_PREVALENCE_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; -import { PREVALENCE_NO_DATA, PREVALENCE_ROW_UNCOMMON, PREVALENCE_TITLE } from './translations'; import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { PREVALENCE_TAB_ID } from '../../left/components/prevalence_details'; import { InsightsSummaryRow } from './insights_summary_row'; @@ -70,7 +70,12 @@ export const PrevalenceOverview: FC = () => { return ( <ExpandablePanel header={{ - title: PREVALENCE_TITLE, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.prevalence.prevalenceTitle" + defaultMessage="Prevalence" + /> + ), callback: goToCorrelationsTab, iconType: 'arrowStart', }} @@ -82,12 +87,23 @@ export const PrevalenceOverview: FC = () => { uncommonData.map((d) => ( <InsightsSummaryRow icon={'warning'} - text={`${d.field}, ${d.value} ${PREVALENCE_ROW_UNCOMMON}`} + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.prevalence.rowDescription" + defaultMessage="{field}, {value} is uncommon" + values={{ field: d.field, value: d.value }} + /> + } data-test-subj={`${INSIGHTS_PREVALENCE_TEST_ID}${d.field}`} /> )) ) : ( - <div data-test-subj={`${INSIGHTS_PREVALENCE_TEST_ID}Error`}>{PREVALENCE_NO_DATA}</div> + <p data-test-subj={INSIGHTS_PREVALENCE_NO_DATA_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.prevalence.noDataDescription" + defaultMessage="No prevalence data available." + /> + </p> )} </EuiFlexGroup> </ExpandablePanel> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx index 069dd973718a1..2edba002600e9 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/reason.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { FormattedMessage, __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { REASON_DETAILS_PREVIEW_BUTTON_TEST_ID, REASON_DETAILS_TEST_ID, @@ -17,7 +18,6 @@ import { RightPanelContext } from '../context'; import { mockDataFormattedForFieldBrowser, mockGetFieldsData } from '../mocks/mock_context'; import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; import { PreviewPanelKey } from '../../preview'; -import { PREVIEW_ALERT_REASON_DETAILS } from './translations'; const flyoutContextValue = { openPreviewPanel: jest.fn(), @@ -33,17 +33,36 @@ const panelContextValue = { const renderReason = (panelContext: RightPanelContext = panelContextValue) => render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContext}> - <Reason /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> + <IntlProvider locale="en"> + <ExpandableFlyoutContext.Provider value={flyoutContextValue}> + <RightPanelContext.Provider value={panelContext}> + <Reason /> + </RightPanelContext.Provider> + </ExpandableFlyoutContext.Provider> + </IntlProvider> ); describe('<Reason />', () => { - it('should render the component', () => { + it('should render the component for alert', () => { const { getByTestId } = renderReason(); expect(getByTestId(REASON_TITLE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(REASON_TITLE_TEST_ID)).toHaveTextContent('Alert reason'); + expect(getByTestId(REASON_DETAILS_PREVIEW_BUTTON_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(REASON_DETAILS_PREVIEW_BUTTON_TEST_ID)).toHaveTextContent( + 'Show full reason' + ); + }); + + it('should render the component for document', () => { + const dataFormattedForFieldBrowser = [...mockDataFormattedForFieldBrowser]; + dataFormattedForFieldBrowser.shift(); + const panelContext = { + ...panelContextValue, + dataFormattedForFieldBrowser, + }; + const { getByTestId } = renderReason(panelContext); + expect(getByTestId(REASON_TITLE_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(REASON_TITLE_TEST_ID)).toHaveTextContent('Document reason'); }); it('should render no reason if the field is null', () => { @@ -70,7 +89,12 @@ describe('<Reason />', () => { indexName: panelContextValue.indexName, scopeId: panelContextValue.scopeId, banner: { - title: PREVIEW_ALERT_REASON_DETAILS, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.reason.alertReasonPreviewTitle" + defaultMessage="Preview alert reason" + /> + ), backgroundColor: 'warning', textColor: 'warning', }, diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx index e7cd3c7fddf11..a245b0dbfa6e2 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/reason.tsx @@ -10,6 +10,7 @@ import React, { useCallback, useMemo } from 'react'; import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { ALERT_REASON } from '@kbn/rule-data-utils'; +import { FormattedMessage } from '@kbn/i18n-react'; import { getField } from '../../shared/utils'; import { AlertReasonPreviewPanel, PreviewPanelKey } from '../../preview'; import { @@ -17,12 +18,6 @@ import { REASON_DETAILS_TEST_ID, REASON_TITLE_TEST_ID, } from './test_ids'; -import { - ALERT_REASON_DETAILS_TEXT, - ALERT_REASON_TITLE, - DOCUMENT_REASON_TITLE, - PREVIEW_ALERT_REASON_DETAILS, -} from './translations'; import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers'; import { useRightPanelContext } from '../context'; @@ -45,7 +40,12 @@ export const Reason: FC = () => { indexName, scopeId, banner: { - title: PREVIEW_ALERT_REASON_DETAILS, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.reason.alertReasonPreviewTitle" + defaultMessage="Preview alert reason" + /> + ), backgroundColor: 'warning', textColor: 'warning', }, @@ -63,7 +63,10 @@ export const Reason: FC = () => { iconSide="right" data-test-subj={REASON_DETAILS_PREVIEW_BUTTON_TEST_ID} > - {ALERT_REASON_DETAILS_TEXT} + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.reason.alertReasonButtonLabel" + defaultMessage="Show full reason" + /> </EuiButtonEmpty> </EuiFlexItem> ), @@ -78,12 +81,22 @@ export const Reason: FC = () => { {isAlert ? ( <EuiFlexGroup justifyContent="spaceBetween" alignItems="center"> <EuiFlexItem> - <h5>{ALERT_REASON_TITLE}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.reason.alertReasonTitle" + defaultMessage="Alert reason" + /> + </h5> </EuiFlexItem> {viewPreview} </EuiFlexGroup> ) : ( - DOCUMENT_REASON_TITLE + <p> + <FormattedMessage + id="xpack.securitySolution.flyout.right.about.reason.documentReasonTitle" + defaultMessage="Document reason" + /> + </p> )} </h5> </EuiTitle> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.test.tsx index 9f6a4ec83a2c2..b27f108d8723f 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_ICON_TEST_ID, @@ -32,6 +33,13 @@ const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID ); +const renderRelatedAlertsByAncestry = () => + render( + <IntlProvider locale="en"> + <RelatedAlertsByAncestry documentId={documentId} indices={indices} scopeId={scopeId} /> + </IntlProvider> + ); + describe('<RelatedAlertsByAncestry />', () => { it('should render many related alerts correctly', () => { (useFetchRelatedAlertsByAncestry as jest.Mock).mockReturnValue({ @@ -40,9 +48,7 @@ describe('<RelatedAlertsByAncestry />', () => { dataCount: 2, }); - const { getByTestId } = render( - <RelatedAlertsByAncestry documentId={documentId} indices={indices} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsByAncestry(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -57,9 +63,7 @@ describe('<RelatedAlertsByAncestry />', () => { dataCount: 1, }); - const { getByTestId } = render( - <RelatedAlertsByAncestry documentId={documentId} indices={indices} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsByAncestry(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -72,9 +76,7 @@ describe('<RelatedAlertsByAncestry />', () => { loading: true, }); - const { getByTestId } = render( - <RelatedAlertsByAncestry documentId={documentId} indices={indices} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsByAncestry(); expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); @@ -84,9 +86,7 @@ describe('<RelatedAlertsByAncestry />', () => { error: true, }); - const { container } = render( - <RelatedAlertsByAncestry documentId={documentId} indices={indices} scopeId={scopeId} /> - ); + const { container } = renderRelatedAlertsByAncestry(); expect(container).toBeEmptyDOMElement(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.tsx index 0a48443de7320..db1bc2e42bb2b 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_ancestry.tsx @@ -6,8 +6,8 @@ */ import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_related_alerts_by_ancestry'; -import { CORRELATIONS_ANCESTRY_ALERTS } from '../../shared/translations'; import { InsightsSummaryRow } from './insights_summary_row'; import { INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID } from './test_ids'; @@ -41,7 +41,13 @@ export const RelatedAlertsByAncestry: React.VFC<RelatedAlertsByAncestryProps> = indices, scopeId, }); - const text = CORRELATIONS_ANCESTRY_ALERTS(dataCount); + const text = ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.correlations.ancestryAlertsLabel" + defaultMessage="{count, plural, one {alert} other {alerts}} related by ancestry" + values={{ count: dataCount }} + /> + ); return ( <InsightsSummaryRow diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.test.tsx index afcbaeb8c5c88..4d1c8b7aa9ea3 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_ICON_TEST_ID, @@ -31,6 +32,13 @@ const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID ); +const renderRelatedAlertsBySameSourceEvent = () => + render( + <IntlProvider locale="en"> + <RelatedAlertsBySameSourceEvent originalEventId={originalEventId} scopeId={scopeId} /> + </IntlProvider> + ); + describe('<RelatedAlertsBySameSourceEvent />', () => { it('should render many related alerts correctly', () => { (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ @@ -39,9 +47,7 @@ describe('<RelatedAlertsBySameSourceEvent />', () => { dataCount: 2, }); - const { getByTestId } = render( - <RelatedAlertsBySameSourceEvent originalEventId={originalEventId} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -56,9 +62,7 @@ describe('<RelatedAlertsBySameSourceEvent />', () => { dataCount: 1, }); - const { getByTestId } = render( - <RelatedAlertsBySameSourceEvent originalEventId={originalEventId} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -71,9 +75,7 @@ describe('<RelatedAlertsBySameSourceEvent />', () => { loading: true, }); - const { getByTestId } = render( - <RelatedAlertsBySameSourceEvent originalEventId={originalEventId} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); @@ -83,9 +85,7 @@ describe('<RelatedAlertsBySameSourceEvent />', () => { error: true, }); - const { container } = render( - <RelatedAlertsBySameSourceEvent originalEventId={originalEventId} scopeId={scopeId} /> - ); + const { container } = renderRelatedAlertsBySameSourceEvent(); expect(container).toBeEmptyDOMElement(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.tsx index 1d5df7a326c44..17743ed068a5e 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_same_source_event.tsx @@ -6,8 +6,8 @@ */ import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; -import { CORRELATIONS_SAME_SOURCE_ALERTS } from '../../shared/translations'; import { InsightsSummaryRow } from './insights_summary_row'; import { INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID } from './test_ids'; @@ -35,7 +35,13 @@ export const RelatedAlertsBySameSourceEvent: React.VFC<RelatedAlertsBySameSource originalEventId, scopeId, }); - const text = CORRELATIONS_SAME_SOURCE_ALERTS(dataCount); + const text = ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.correlations.sourceAlertsLabel" + defaultMessage="{count, plural, one {alert} other {alerts}} related by source event" + values={{ count: dataCount }} + /> + ); return ( <InsightsSummaryRow diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.test.tsx index 133f00e44b26b..263bda7a17af4 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_ICON_TEST_ID, @@ -31,6 +32,13 @@ const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID( INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID ); +const renderRelatedAlertsBySession = () => + render( + <IntlProvider locale="en"> + <RelatedAlertsBySession entityId={entityId} scopeId={scopeId} /> + </IntlProvider> + ); + describe('<RelatedAlertsBySession />', () => { it('should render many related alerts correctly', () => { (useFetchRelatedAlertsBySession as jest.Mock).mockReturnValue({ @@ -39,9 +47,7 @@ describe('<RelatedAlertsBySession />', () => { dataCount: 2, }); - const { getByTestId } = render( - <RelatedAlertsBySession entityId={entityId} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsBySession(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -56,9 +62,7 @@ describe('<RelatedAlertsBySession />', () => { dataCount: 1, }); - const { getByTestId } = render( - <RelatedAlertsBySession entityId={entityId} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsBySession(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -71,9 +75,7 @@ describe('<RelatedAlertsBySession />', () => { loading: true, }); - const { getByTestId } = render( - <RelatedAlertsBySession entityId={entityId} scopeId={scopeId} /> - ); + const { getByTestId } = renderRelatedAlertsBySession(); expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); @@ -83,7 +85,7 @@ describe('<RelatedAlertsBySession />', () => { error: true, }); - const { container } = render(<RelatedAlertsBySession entityId={entityId} scopeId={scopeId} />); + const { container } = renderRelatedAlertsBySession(); expect(container).toBeEmptyDOMElement(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.tsx index 2a015c0c880d9..982f34ec1720a 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_alerts_by_session.tsx @@ -6,8 +6,8 @@ */ import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useFetchRelatedAlertsBySession } from '../../shared/hooks/use_fetch_related_alerts_by_session'; -import { CORRELATIONS_SESSION_ALERTS } from '../../shared/translations'; import { InsightsSummaryRow } from './insights_summary_row'; import { INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID } from './test_ids'; @@ -35,7 +35,13 @@ export const RelatedAlertsBySession: React.VFC<RelatedAlertsBySessionProps> = ({ entityId, scopeId, }); - const text = CORRELATIONS_SESSION_ALERTS(dataCount); + const text = ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.correlations.sessionAlertsLabel" + defaultMessage="{count, plural, one {alert} other {alerts}} related by session" + values={{ count: dataCount }} + /> + ); return ( <InsightsSummaryRow diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.test.tsx index 7d0d1a88fb2ec..d280b25f93414 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { INSIGHTS_CORRELATIONS_RELATED_CASES_TEST_ID, @@ -24,6 +25,13 @@ const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(INSIGHTS_CORRELATIONS_RELATED_CASE const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(INSIGHTS_CORRELATIONS_RELATED_CASES_TEST_ID); const LOADING_TEST_ID = SUMMARY_ROW_LOADING_TEST_ID(INSIGHTS_CORRELATIONS_RELATED_CASES_TEST_ID); +const renderRelatedCases = () => + render( + <IntlProvider locale="en"> + <RelatedCases eventId={eventId} /> + </IntlProvider> + ); + describe('<RelatedCases />', () => { it('should render many related cases correctly', () => { (useFetchRelatedCases as jest.Mock).mockReturnValue({ @@ -32,7 +40,7 @@ describe('<RelatedCases />', () => { dataCount: 2, }); - const { getByTestId } = render(<RelatedCases eventId={eventId} />); + const { getByTestId } = renderRelatedCases(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -47,7 +55,7 @@ describe('<RelatedCases />', () => { dataCount: 1, }); - const { getByTestId } = render(<RelatedCases eventId={eventId} />); + const { getByTestId } = renderRelatedCases(); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); @@ -60,7 +68,7 @@ describe('<RelatedCases />', () => { loading: true, }); - const { getByTestId } = render(<RelatedCases eventId={eventId} />); + const { getByTestId } = renderRelatedCases(); expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); @@ -70,7 +78,7 @@ describe('<RelatedCases />', () => { error: true, }); - const { container } = render(<RelatedCases eventId={eventId} />); + const { container } = renderRelatedCases(); expect(container).toBeEmptyDOMElement(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.tsx index d20e4fc09d56b..e56e35d7acd2a 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/related_cases.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { CORRELATIONS_RELATED_CASES } from '../../shared/translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; import { InsightsSummaryRow } from './insights_summary_row'; import { INSIGHTS_CORRELATIONS_RELATED_CASES_TEST_ID } from './test_ids'; @@ -25,7 +25,13 @@ export interface RelatedCasesProps { */ export const RelatedCases: React.VFC<RelatedCasesProps> = ({ eventId }) => { const { loading, error, dataCount } = useFetchRelatedCases({ eventId }); - const text = CORRELATIONS_RELATED_CASES(dataCount); + const text = ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.correlations.relatedCasesLabel" + defaultMessage="related {count, plural, one {case} other {cases}}" + values={{ count: dataCount }} + /> + ); return ( <InsightsSummaryRow diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/response_button.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/response_button.test.tsx index 3cbed8191f342..0116b26e5c900 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/response_button.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/response_button.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { RightPanelContext } from '../context'; import { RESPONSE_BUTTON_TEST_ID, RESPONSE_EMPTY_TEST_ID } from './test_ids'; @@ -34,40 +35,32 @@ const mockInvalidSearchHit = { fields: {}, } as unknown as SearchHit; -describe('<ResponseButton />', () => { - it('should render response button correctly', () => { - const { getByTestId } = render( +const renderResponseButton = (panelContextValue: RightPanelContext = mockContextValue) => + render( + <IntlProvider locale="en"> <ExpandableFlyoutContext.Provider value={mockFlyoutContextValue}> - <RightPanelContext.Provider value={{ ...mockContextValue, searchHit: mockValidSearchHit }}> + <RightPanelContext.Provider value={panelContextValue}> <ResponseButton /> </RightPanelContext.Provider> </ExpandableFlyoutContext.Provider> - ); + </IntlProvider> + ); +describe('<ResponseButton />', () => { + it('should render response button correctly', () => { + const panelContextValue = { ...mockContextValue, searchHit: mockValidSearchHit }; + const { getByTestId, queryByTestId } = renderResponseButton(panelContextValue); expect(getByTestId(RESPONSE_BUTTON_TEST_ID)).toBeInTheDocument(); - }); - - it('should not render response button when searchHit is undefined', () => { - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={mockFlyoutContextValue}> - <RightPanelContext.Provider value={mockContextValue}> - <ResponseButton /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> - ); - - expect(getByTestId(RESPONSE_EMPTY_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RESPONSE_BUTTON_TEST_ID)).toHaveTextContent('Response'); + expect(queryByTestId(RESPONSE_EMPTY_TEST_ID)).not.toBeInTheDocument(); }); it(`should not render investigation guide button when searchHit doesn't have correct data`, () => { - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={mockFlyoutContextValue}> - <RightPanelContext.Provider - value={{ ...mockContextValue, searchHit: mockInvalidSearchHit }} - > - <ResponseButton /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> - ); + const panelContextValue = { ...mockContextValue, searchHit: mockInvalidSearchHit }; + const { getByTestId, queryByTestId } = renderResponseButton(panelContextValue); expect(getByTestId(RESPONSE_EMPTY_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(RESPONSE_EMPTY_TEST_ID)).toHaveTextContent( + 'There are no response actions defined for this event.' + ); + expect(queryByTestId(RESPONSE_BUTTON_TEST_ID)).not.toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/response_button.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/response_button.tsx index b1e4e94296a46..fe6a9dd20d59a 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/response_button.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/response_button.tsx @@ -7,6 +7,7 @@ import React, { useCallback } from 'react'; import { EuiButton } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { expandDottedObject } from '../../../../common/utils/expand_dotted'; import type { ExpandedEventFieldsObject, @@ -15,7 +16,6 @@ import type { import { useRightPanelContext } from '../context'; import { LeftPanelKey, LeftPanelResponseTab } from '../../left'; import { RESPONSE_BUTTON_TEST_ID, RESPONSE_EMPTY_TEST_ID } from './test_ids'; -import { RESPONSE_EMPTY, RESPONSE_TITLE } from './translations'; /** * Response button that opens Response section in the left panel @@ -45,14 +45,22 @@ export const ResponseButton: React.FC = () => { return ( <> {!responseActions ? ( - <div data-test-subj={RESPONSE_EMPTY_TEST_ID}>{RESPONSE_EMPTY}</div> + <p data-test-subj={RESPONSE_EMPTY_TEST_ID}> + <FormattedMessage + id="xpack.securitySolution.flyout.right.response.noDataDescription" + defaultMessage="There are no response actions defined for this event." + /> + </p> ) : ( <EuiButton onClick={goToResponseTab} iconType="documentation" data-test-subj={RESPONSE_BUTTON_TEST_ID} > - {RESPONSE_TITLE} + <FormattedMessage + id="xpack.securitySolution.flyout.right.response.responseButtonLabel" + defaultMessage="Response" + /> </EuiButton> )} </> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/response_section.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/response_section.test.tsx index d15ad34790ea6..ebff6c0e704fe 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/response_section.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/response_section.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { RESPONSE_SECTION_CONTENT_TEST_ID, RESPONSE_SECTION_HEADER_TEST_ID } from './test_ids'; import { RightPanelContext } from '../context'; @@ -15,40 +16,33 @@ import { ResponseSection } from './response_section'; const flyoutContextValue = {} as unknown as ExpandableFlyoutContext; const panelContextValue = {} as unknown as RightPanelContext; -describe('<ResponseSection />', () => { - it('should render the component collapsed', () => { - const { getByTestId } = render( +const renderResponseSection = () => + render( + <IntlProvider locale="en"> <ExpandableFlyoutContext.Provider value={flyoutContextValue}> <RightPanelContext.Provider value={panelContextValue}> <ResponseSection /> </RightPanelContext.Provider> </ExpandableFlyoutContext.Provider> - ); + </IntlProvider> + ); + +describe('<ResponseSection />', () => { + it('should render the component collapsed', () => { + const { getByTestId } = renderResponseSection(); expect(getByTestId(RESPONSE_SECTION_HEADER_TEST_ID)).toBeInTheDocument(); }); it('should render the component expanded', () => { - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContextValue}> - <ResponseSection expanded={true} /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> - ); + const { getByTestId } = renderResponseSection(); expect(getByTestId(RESPONSE_SECTION_HEADER_TEST_ID)).toBeInTheDocument(); expect(getByTestId(RESPONSE_SECTION_CONTENT_TEST_ID)).toBeInTheDocument(); }); it('should expand the component when clicking on the arrow on header', () => { - const { getByTestId } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={panelContextValue}> - <ResponseSection /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> - ); + const { getByTestId } = renderResponseSection(); getByTestId(RESPONSE_SECTION_HEADER_TEST_ID).click(); expect(getByTestId(RESPONSE_SECTION_CONTENT_TEST_ID)).toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/response_section.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/response_section.tsx index 18480dde09dde..96a0b070020e2 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/response_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/response_section.tsx @@ -7,10 +7,10 @@ import type { VFC } from 'react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ResponseButton } from './response_button'; import { ExpandableSection } from './expandable_section'; import { RESPONSE_SECTION_TEST_ID } from './test_ids'; -import { RESPONSE_TITLE } from './translations'; export interface ResponseSectionProps { /** * Boolean to allow the component to be expanded or collapsed on first render @@ -25,7 +25,12 @@ export const ResponseSection: VFC<ResponseSectionProps> = ({ expanded = false }) return ( <ExpandableSection expanded={expanded} - title={RESPONSE_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.response.sectionTitle" + defaultMessage="Response" + /> + } data-test-subj={RESPONSE_SECTION_TEST_ID} > <ResponseButton /> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.test.tsx index 554b6c90db32a..04e399fc55281 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { RightPanelContext } from '../context'; import { @@ -15,17 +16,22 @@ import { import { RiskScore } from './risk_score'; import { mockGetFieldsData } from '../mocks/mock_context'; +const renderRiskScore = (contextValue: RightPanelContext) => + render( + <IntlProvider locale="en"> + <RightPanelContext.Provider value={contextValue}> + <RiskScore /> + </RightPanelContext.Provider> + </IntlProvider> + ); + describe('<RiskScore />', () => { it('should render risk score information', () => { const contextValue = { getFieldsData: jest.fn().mockImplementation(mockGetFieldsData), } as unknown as RightPanelContext; - const { getByTestId } = render( - <RightPanelContext.Provider value={contextValue}> - <RiskScore /> - </RightPanelContext.Provider> - ); + const { getByTestId } = renderRiskScore(contextValue); expect(getByTestId(FLYOUT_HEADER_RISK_SCORE_TITLE_TEST_ID)).toBeInTheDocument(); const riskScore = getByTestId(FLYOUT_HEADER_RISK_SCORE_VALUE_TEST_ID); @@ -38,11 +44,7 @@ describe('<RiskScore />', () => { getFieldsData: jest.fn(), } as unknown as RightPanelContext; - const { container } = render( - <RightPanelContext.Provider value={contextValue}> - <RiskScore /> - </RightPanelContext.Provider> - ); + const { container } = renderRiskScore(contextValue); expect(container).toBeEmptyDOMElement(); }); @@ -52,11 +54,7 @@ describe('<RiskScore />', () => { getFieldsData: jest.fn().mockImplementation(() => 123), } as unknown as RightPanelContext; - const { container } = render( - <RightPanelContext.Provider value={contextValue}> - <RiskScore /> - </RightPanelContext.Provider> - ); + const { container } = renderRiskScore(contextValue); expect(container).toBeEmptyDOMElement(); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.tsx index b14aa88f91d0e..fe15151e467cf 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/risk_score.tsx @@ -9,11 +9,11 @@ import type { FC } from 'react'; import React, { memo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import { ALERT_RISK_SCORE } from '@kbn/rule-data-utils'; +import { FormattedMessage } from '@kbn/i18n-react'; import { FLYOUT_HEADER_RISK_SCORE_TITLE_TEST_ID, FLYOUT_HEADER_RISK_SCORE_VALUE_TEST_ID, } from './test_ids'; -import { RISK_SCORE_TITLE } from './translations'; import { useRightPanelContext } from '../context'; /** @@ -40,7 +40,12 @@ export const RiskScore: FC = memo(() => { <EuiFlexGroup alignItems="center" direction="row" gutterSize="xs"> <EuiFlexItem grow={false}> <EuiTitle size="xxs" data-test-subj={FLYOUT_HEADER_RISK_SCORE_TITLE_TEST_ID}> - <h5>{`${RISK_SCORE_TITLE}:`}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.riskScoreTitle" + defaultMessage="Risk score:" + /> + </h5> </EuiTitle> </EuiFlexItem> <EuiFlexItem grow={false}> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview.tsx index 9ad7e2bd05d75..1bfca23f84ffa 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview.tsx @@ -6,24 +6,20 @@ */ import { EuiCode, EuiIcon, useEuiTheme } from '@elastic/eui'; +import type { ReactElement } from 'react'; import React, { useMemo, type FC } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { SESSION_PREVIEW_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; import { SIGNAL_RULE_NAME_FIELD_NAME } from '../../../timelines/components/timeline/body/renderers/constants'; import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; import { useProcessData } from '../hooks/use_process_data'; -import { - SESSION_PREVIEW_COMMAND_TEXT, - SESSION_PREVIEW_PROCESS_TEXT, - SESSION_PREVIEW_RULE_TEXT, - SESSION_PREVIEW_TIME_TEXT, -} from './translations'; import { RenderRuleName } from '../../../timelines/components/timeline/body/renderers/formatted_field_helpers'; /** * One-off helper to make sure that inline values are rendered consistently */ -const ValueContainer: FC<{ text?: string }> = ({ text, children }) => ( +const ValueContainer: FC<{ text?: ReactElement }> = ({ text, children }) => ( <> {text && ( <> @@ -53,7 +49,14 @@ export const SessionPreview: FC = () => { const processNameFragment = useMemo(() => { return ( processName && ( - <ValueContainer text={SESSION_PREVIEW_PROCESS_TEXT}> + <ValueContainer + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.processDescription" + defaultMessage="started" + /> + } + > <span style={emphasisStyles}>{processName}</span> </ValueContainer> ) @@ -63,7 +66,14 @@ export const SessionPreview: FC = () => { const timeFragment = useMemo(() => { return ( startAt && ( - <ValueContainer text={SESSION_PREVIEW_TIME_TEXT}> + <ValueContainer + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.timeDescription" + defaultMessage="at" + /> + } + > <PreferenceFormattedDate value={new Date(startAt)} /> </ValueContainer> ) @@ -74,7 +84,14 @@ export const SessionPreview: FC = () => { return ( ruleName && ruleId && ( - <ValueContainer text={SESSION_PREVIEW_RULE_TEXT}> + <ValueContainer + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.ruleDescription" + defaultMessage="with rule" + /> + } + > <RenderRuleName contextId={scopeId} eventId={eventId} @@ -93,7 +110,14 @@ export const SessionPreview: FC = () => { const commandFragment = useMemo(() => { return ( command && ( - <ValueContainer text={SESSION_PREVIEW_COMMAND_TEXT}> + <ValueContainer + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.commandDescription" + defaultMessage="by" + /> + } + > <EuiCode> {workdir} {command} </EuiCode> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx index 0568c740f1de4..c7057827fa101 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.test.tsx @@ -12,7 +12,11 @@ import { RightPanelContext } from '../context'; import { SessionPreviewContainer } from './session_preview_container'; import { useSessionPreview } from '../hooks/use_session_preview'; import { useLicense } from '../../../common/hooks/use_license'; -import { SESSION_PREVIEW_TEST_ID } from './test_ids'; +import { + SESSION_PREVIEW_NO_DATA_TEST_ID, + SESSION_PREVIEW_TEST_ID, + SESSION_PREVIEW_UPSELL_TEST_ID, +} from './test_ids'; import { EXPANDABLE_PANEL_CONTENT_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, @@ -35,10 +39,6 @@ const sessionViewConfig = { sessionStartTime: 'sessionStartTime', }; -const TEST_ID = SESSION_PREVIEW_TEST_ID; -const ERROR_TEST_ID = `${SESSION_PREVIEW_TEST_ID}Error`; -const UPSELL_TEST_ID = `${SESSION_PREVIEW_TEST_ID}UpSell`; - const renderSessionPreview = () => render( <TestProviders> @@ -59,9 +59,9 @@ describe('SessionPreviewContainer', () => { const { getByTestId, queryByTestId } = renderSessionPreview(); - expect(getByTestId(TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(ERROR_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(UPSELL_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(SESSION_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).not.toBeInTheDocument(); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).toBeInTheDocument(); @@ -85,9 +85,12 @@ describe('SessionPreviewContainer', () => { const { getByTestId, queryByTestId } = renderSessionPreview(); - expect(queryByTestId(TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(ERROR_TEST_ID)).toBeInTheDocument(); - expect(queryByTestId(UPSELL_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).toHaveTextContent( + 'You can only view Linux session details if you’ve enabled the Include session data setting in your Elastic Defend integration policy. Refer to Enable Session View dataExternal link(opens in a new tab or window) for more information.' + ); + expect(queryByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).not.toBeInTheDocument(); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).toBeInTheDocument(); @@ -99,9 +102,12 @@ describe('SessionPreviewContainer', () => { const { getByTestId, queryByTestId } = renderSessionPreview(); - expect(queryByTestId(TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(ERROR_TEST_ID)).not.toBeInTheDocument(); - expect(getByTestId(UPSELL_TEST_ID)).toBeInTheDocument(); + expect(queryByTestId(SESSION_PREVIEW_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(SESSION_PREVIEW_NO_DATA_TEST_ID)).not.toBeInTheDocument(); + expect(getByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(SESSION_PREVIEW_UPSELL_TEST_ID)).toHaveTextContent( + 'This feature requires an Enterprise subscription' + ); expect( getByTestId(EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID(SESSION_PREVIEW_TEST_ID)) ).toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx index 49a90921e2998..e3fe9a191ebcb 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/session_preview_container.tsx @@ -18,8 +18,11 @@ import { useInvestigateInTimeline } from '../../../detections/components/alerts_ import { useRightPanelContext } from '../context'; import { ALERTS_ACTIONS } from '../../../common/lib/apm/user_actions'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; -import { SESSION_PREVIEW_TEST_ID } from './test_ids'; -import { SESSION_PREVIEW_TITLE } from './translations'; +import { + SESSION_PREVIEW_NO_DATA_TEST_ID, + SESSION_PREVIEW_TEST_ID, + SESSION_PREVIEW_UPSELL_TEST_ID, +} from './test_ids'; import { useStartTransaction } from '../../../common/lib/apm/use_start_transaction'; import { setActiveTabTimeline } from '../../../timelines/store/timeline/actions'; import { getScopedActions } from '../../../helpers'; @@ -67,15 +70,15 @@ export const SessionPreviewContainer: FC = () => { const { euiTheme } = useEuiTheme(); const noSessionMessage = !isEnterprisePlus ? ( - <div data-test-subj={`${SESSION_PREVIEW_TEST_ID}UpSell`}> + <div data-test-subj={SESSION_PREVIEW_UPSELL_TEST_ID}> <FormattedMessage - id="xpack.securitySolution.flyout.sessionPreviewUpsell" + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellDescription" defaultMessage="This feature requires an {subscription}" values={{ subscription: ( <EuiLink href="https://www.elastic.co/pricing/" target="_blank"> <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.sessionPreviewUpsellLink" + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellLinkText" defaultMessage="Enterprise subscription" /> </EuiLink> @@ -84,9 +87,9 @@ export const SessionPreviewContainer: FC = () => { /> </div> ) : !sessionViewConfig ? ( - <div data-test-subj={`${SESSION_PREVIEW_TEST_ID}Error`}> + <div data-test-subj={SESSION_PREVIEW_NO_DATA_TEST_ID}> <FormattedMessage - id="xpack.securitySolution.flyout.sessionPreviewError" + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.noDataDescription" defaultMessage="You can only view Linux session details if you’ve enabled the {setting} setting in your Elastic Defend integration policy. Refer to {link} for more information." values={{ setting: ( @@ -96,7 +99,7 @@ export const SessionPreviewContainer: FC = () => { `} > <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.sessionPreviewErrorSetting" + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.noDataSettingDescription" defaultMessage="Include session data" /> </span> @@ -107,7 +110,7 @@ export const SessionPreviewContainer: FC = () => { target="_blank" > <FormattedMessage - id="xpack.securitySolution.flyout.documentDetails.sessionPreviewErrorLink" + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.noDataLinkText" defaultMessage="Enable Session View data" /> </EuiLink> @@ -120,7 +123,12 @@ export const SessionPreviewContainer: FC = () => { return ( <ExpandablePanel header={{ - title: SESSION_PREVIEW_TITLE, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.visualizations.sessionPreview.sessionPreviewTitle" + defaultMessage="Session viewer preview" + /> + ), iconType: 'timeline', ...(isEnabled && { callback: goToSessionViewTab }), }} diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/severity.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/severity.tsx index c5f49400f088c..390f9997e0892 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/severity.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/severity.tsx @@ -11,10 +11,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import { ALERT_SEVERITY } from '@kbn/rule-data-utils'; import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; import { CellActionsMode } from '@kbn/cell-actions'; +import { FormattedMessage } from '@kbn/i18n-react'; import { getSourcererScopeId } from '../../../helpers'; import { SecurityCellActions } from '../../../common/components/cell_actions'; import { SecurityCellActionsTrigger } from '../../../actions/constants'; -import { SEVERITY_TITLE } from './translations'; import { useRightPanelContext } from '../context'; import { SeverityBadge } from '../../../detections/components/rules/severity_badge'; import { FLYOUT_HEADER_SEVERITY_TITLE_TEST_ID } from './test_ids'; @@ -46,7 +46,12 @@ export const DocumentSeverity: FC = memo(() => { <EuiFlexGroup alignItems="center" direction="row" gutterSize="xs"> <EuiFlexItem grow={false}> <EuiTitle size="xxs" data-test-subj={FLYOUT_HEADER_SEVERITY_TITLE_TEST_ID}> - <h5>{`${SEVERITY_TITLE}:`}</h5> + <h5> + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.severityTitle" + defaultMessage="Severity:" + /> + </h5> </EuiTitle> </EuiFlexItem> <EuiFlexItem grow={false}> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/share_button.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.test.tsx index 00b757541d587..718fd635b4bc4 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/share_button.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.test.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render, screen, fireEvent } from '@testing-library/react'; import { copyToClipboard } from '@elastic/eui'; import { ShareButton } from './share_button'; @@ -18,15 +19,22 @@ jest.mock('@elastic/eui', () => ({ EuiCopy: jest.fn(({ children: functionAsChild }) => functionAsChild(jest.fn())), })); -describe('ShareButton', () => { - const alertUrl = 'https://example.com/alert'; +const alertUrl = 'https://example.com/alert'; + +const renderShareButton = () => + render( + <IntlProvider locale="en"> + <ShareButton alertUrl={alertUrl} /> + </IntlProvider> + ); +describe('ShareButton', () => { beforeEach(() => { jest.clearAllMocks(); }); it('renders the share button', () => { - render(<ShareButton alertUrl={alertUrl} />); + renderShareButton(); expect(screen.getByTestId(FLYOUT_HEADER_SHARE_BUTTON_TEST_ID)).toBeInTheDocument(); }); @@ -41,7 +49,7 @@ describe('ShareButton', () => { }, }); - render(<ShareButton alertUrl={alertUrl} />); + renderShareButton(); fireEvent.click(screen.getByTestId(FLYOUT_HEADER_SHARE_BUTTON_TEST_ID)); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/share_button.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.tsx index 04405e9b7a31a..034ebd0aa102a 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/share_button.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.tsx @@ -8,9 +8,9 @@ import { copyToClipboard, EuiButtonEmpty, EuiCopy } from '@elastic/eui'; import type { FC } from 'react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { FLYOUT_URL_PARAM } from '../../shared/hooks/url/use_sync_flyout_state_with_url'; import { FLYOUT_HEADER_SHARE_BUTTON_TEST_ID } from './test_ids'; -import { SHARE } from './translations'; interface ShareButtonProps { /** @@ -41,7 +41,10 @@ export const ShareButton: FC<ShareButtonProps> = ({ alertUrl }) => { iconType="share" data-test-subj={FLYOUT_HEADER_SHARE_BUTTON_TEST_ID} > - {SHARE} + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.shareButtonLabel" + defaultMessage="Share Alert" + /> </EuiButtonEmpty> )} </EuiCopy> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.test.tsx index 585e8f02ace03..54ae69fba7c40 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.test.tsx @@ -6,49 +6,63 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { SUMMARY_ROW_ICON_TEST_ID, SUMMARY_ROW_VALUE_TEST_ID, INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, - SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, + INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, } from './test_ids'; import { SuppressedAlerts } from './suppressed_alerts'; const ICON_TEST_ID = SUMMARY_ROW_ICON_TEST_ID(INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); const VALUE_TEST_ID = SUMMARY_ROW_VALUE_TEST_ID(INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID); +const renderSuppressedAlerts = (alertSuppressionCount: number) => + render( + <IntlProvider locale="en"> + <SuppressedAlerts alertSuppressionCount={alertSuppressionCount} /> + </IntlProvider> + ); + describe('<SuppressedAlerts />', () => { it('should render zero suppressed alert correctly', () => { - const { getByTestId } = render(<SuppressedAlerts alertSuppressionCount={0} />); + const { getByTestId } = renderSuppressedAlerts(0); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); expect(value).toHaveTextContent('0 suppressed alert'); expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect( + getByTestId(INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) + ).toBeInTheDocument(); }); it('should render single suppressed alert correctly', () => { - const { getByTestId } = render(<SuppressedAlerts alertSuppressionCount={1} />); + const { getByTestId } = renderSuppressedAlerts(1); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); expect(value).toHaveTextContent('1 suppressed alert'); expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect( + getByTestId(INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) + ).toBeInTheDocument(); }); it('should render multiple suppressed alerts row correctly', () => { - const { getByTestId } = render(<SuppressedAlerts alertSuppressionCount={2} />); + const { getByTestId } = renderSuppressedAlerts(2); expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); const value = getByTestId(VALUE_TEST_ID); expect(value).toBeInTheDocument(); expect(value).toHaveTextContent('2 suppressed alerts'); expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID)).toBeInTheDocument(); + expect( + getByTestId(INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID) + ).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.tsx index 4732d43cadff9..9d02fdf859805 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/suppressed_alerts.tsx @@ -7,14 +7,13 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiBetaBadge } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID, - SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, + INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID, } from './test_ids'; -import { CORRELATIONS_SUPPRESSED_ALERTS } from '../../shared/translations'; import { InsightsSummaryRow } from './insights_summary_row'; import { SUPPRESSED_ALERTS_COUNT_TECHNICAL_PREVIEW } from '../../../common/components/event_details/insights/translations'; -import { TECHNICAL_PREVIEW_MESSAGE } from './translations'; export interface SuppressedAlertsProps { /** @@ -35,7 +34,13 @@ export const SuppressedAlerts: React.VFC<SuppressedAlertsProps> = ({ alertSuppre error={false} icon={'layers'} value={alertSuppressionCount} - text={CORRELATIONS_SUPPRESSED_ALERTS(alertSuppressionCount)} + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.correlations.suppressedAlertsLabel" + defaultMessage="suppressed {count, plural, =1 {alert} other {alerts}}" + values={{ count: alertSuppressionCount }} + /> + } data-test-subj={INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID} key={`correlation-row-suppressed-alerts`} /> @@ -45,9 +50,14 @@ export const SuppressedAlerts: React.VFC<SuppressedAlertsProps> = ({ alertSuppre label={SUPPRESSED_ALERTS_COUNT_TECHNICAL_PREVIEW} size="s" iconType="beaker" - tooltipContent={TECHNICAL_PREVIEW_MESSAGE} + tooltipContent={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.entities.suppressedAlertTechnicalPreviewTooltip" + defaultMessage="This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but features in technical preview are not subject to the support SLA of official GA features." + /> + } tooltipPosition="bottom" - data-test-subj={SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID} + data-test-subj={INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID} /> </EuiFlexItem> </EuiFlexGroup> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts index 6f0ee15d7db01..8145b8e5fb258 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts @@ -109,23 +109,19 @@ export const INSIGHTS_THREAT_INTELLIGENCE_CONTAINER_TEST_ID = `${INSIGHTS_THREAT export const INSIGHTS_CORRELATIONS_TEST_ID = 'securitySolutionDocumentDetailsFlyoutInsightsCorrelations'; -export const INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID = - 'securitySolutionDocumentDetailsFlyoutInsightsCorrelationsSupressedAlerts'; -export const SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID = - 'securitySolutionDocumentDetailsFlyoutSupressedAlertsTechnicalPreview'; -export const INSIGHTS_CORRELATIONS_RELATED_CASES_TEST_ID = - 'securitySolutionDocumentDetailsFlyoutInsightsCorrelationsRelatedCases'; -export const INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID = - 'securitySolutionDocumentDetailsFlyoutInsightsCorrelationsRelatedAlertsBySession'; -export const INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID = - 'securitySolutionDocumentDetailsFlyoutInsightsCorrelationsRelatedAlertsBySameSourceEvent'; -export const INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID = - 'securitySolutionDocumentDetailsFlyoutInsightsCorrelationsRelatedAlertsByAncestry'; +export const INSIGHTS_CORRELATIONS_NO_DATA_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}NoData`; +export const INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}SuppressedAlerts`; +export const INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TECHNICAL_PREVIEW_TEST_ID = `${INSIGHTS_CORRELATIONS_SUPPRESSED_ALERTS_TEST_ID}TechnicalPreview`; +export const INSIGHTS_CORRELATIONS_RELATED_CASES_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}RelatedCases`; +export const INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SESSION_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}RelatedAlertsBySession`; +export const INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}RelatedAlertsBySameSourceEvent`; +export const INSIGHTS_CORRELATIONS_RELATED_ALERTS_BY_ANCESTRY_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}RelatedAlertsByAncestry`; /* Insights Prevalence */ export const INSIGHTS_PREVALENCE_TEST_ID = 'securitySolutionDocumentDetailsFlyoutInsightsPrevalence'; +export const INSIGHTS_PREVALENCE_NO_DATA_TEST_ID = `${INSIGHTS_PREVALENCE_TEST_ID}NoData`; /* Visualizations section */ @@ -133,7 +129,10 @@ export const VISUALIZATIONS_SECTION_TEST_ID = 'securitySolutionDocumentDetailsVi export const VISUALIZATIONS_SECTION_HEADER_TEST_ID = 'securitySolutionDocumentDetailsVisualizationsTitleHeader'; export const ANALYZER_PREVIEW_TEST_ID = 'securitySolutionDocumentDetailsAnalyzerPreview'; +export const ANALYZER_PREVIEW_NO_DATA_TEST_ID = `${ANALYZER_PREVIEW_TEST_ID}NoData`; export const SESSION_PREVIEW_TEST_ID = 'securitySolutionDocumentDetailsSessionPreview'; +export const SESSION_PREVIEW_UPSELL_TEST_ID = `${SESSION_PREVIEW_TEST_ID}UpSell`; +export const SESSION_PREVIEW_NO_DATA_TEST_ID = `${SESSION_PREVIEW_TEST_ID}NoData`; /* Response section */ diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx index 4d3d3334862ba..a111e5469e614 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx @@ -103,7 +103,7 @@ describe('<ThreatIntelligenceOverview />', () => { ); }); - it('should render 0 field enriched', () => { + it('should render 0 fields enriched', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, threatMatchesCount: 1, @@ -113,11 +113,11 @@ describe('<ThreatIntelligenceOverview />', () => { const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent( - '0 field enriched with threat intelligence' + '0 fields enriched with threat intelligence' ); }); - it('should render 0 match detected', () => { + it('should render 0 matches detected', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, threatMatchesCount: 0, @@ -126,7 +126,7 @@ describe('<ThreatIntelligenceOverview />', () => { const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); - expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('0 threat match detected'); + expect(getByTestId(CONTENT_TEST_ID)).toHaveTextContent('0 threat matches detected'); }); it('should render loading', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx index 42253e61effe2..0175d44e4f4bd 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx @@ -9,18 +9,12 @@ import type { FC } from 'react'; import React, { useCallback } from 'react'; import { EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { ExpandablePanel } from '../../shared/components/expandable_panel'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { InsightsSummaryRow } from './insights_summary_row'; import { useRightPanelContext } from '../context'; import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; -import { - THREAT_INTELLIGENCE_TITLE, - THREAT_MATCH_DETECTED, - THREAT_ENRICHMENT, - THREAT_MATCHES_DETECTED, - THREAT_ENRICHMENTS, -} from './translations'; import { LeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { THREAT_INTELLIGENCE_TAB_ID } from '../../left/components/threat_intelligence_details'; @@ -55,7 +49,12 @@ export const ThreatIntelligenceOverview: FC = () => { return ( <ExpandablePanel header={{ - title: THREAT_INTELLIGENCE_TITLE, + title: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.threatIntelligence.threatIntelligenceTitle" + defaultMessage="Threat intelligence" + /> + ), callback: goToThreatIntelligenceTab, iconType: 'arrowStart', }} @@ -70,14 +69,26 @@ export const ThreatIntelligenceOverview: FC = () => { loading={loading} icon={'warning'} value={threatMatchesCount} - text={threatMatchesCount <= 1 ? THREAT_MATCH_DETECTED : THREAT_MATCHES_DETECTED} + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.threatIntelligence.threatMatchDescription" + defaultMessage="threat {count, plural, one {match} other {matches}} detected" + values={{ count: threatMatchesCount }} + /> + } data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} /> <InsightsSummaryRow loading={loading} icon={'warning'} value={threatEnrichmentsCount} - text={threatEnrichmentsCount <= 1 ? THREAT_ENRICHMENT : THREAT_ENRICHMENTS} + text={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.threatIntelligence.threatEnrichmentDescription" + defaultMessage="{count, plural, one {field} other {fields}} enriched with threat intelligence" + values={{ count: threatEnrichmentsCount }} + /> + } data-test-subj={INSIGHTS_THREAT_INTELLIGENCE_TEST_ID} /> </EuiFlexGroup> diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/translations.ts b/x-pack/plugins/security_solution/public/flyout/right/components/translations.ts deleted file mode 100644 index ea83a8f3a1a23..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/translations.ts +++ /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 { i18n } from '@kbn/i18n'; - -/* Header */ - -export const EXPAND_DETAILS_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.expandDetailButton', - { defaultMessage: 'Expand details' } -); - -export const COLLAPSE_DETAILS_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.collapseDetailButton', - { defaultMessage: 'Collapse details' } -); - -export const EVENT_DETAILS = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.headerTitle', - { defaultMessage: 'Event details' } -); - -export const SEVERITY_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.severityTitle', - { - defaultMessage: 'Severity', - } -); - -export const RISK_SCORE_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.riskScoreTitle', - { - defaultMessage: 'Risk score', - } -); - -export const RULE_SUMMARY_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.ruleSummaryText', - { - defaultMessage: 'Show rule summary', - } -); - -export const ALERT_REASON_DETAILS_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.alertReasonDetailsText', - { - defaultMessage: 'Show full reason', - } -); - -/* About section */ - -export const ABOUT_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.aboutTitle', - { - defaultMessage: 'About', - } -); - -export const RULE_DESCRIPTION_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.ruleDescriptionTitle', - { - defaultMessage: 'Rule description', - } -); - -export const PREVIEW_RULE_DETAILS = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.previewRuleDetailsText', - { defaultMessage: 'Preview rule details' } -); - -export const PREVIEW_ALERT_REASON_DETAILS = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.previewAlertReasonDetailsText', - { defaultMessage: 'Preview alert reason' } -); - -export const DOCUMENT_DESCRIPTION_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.documentDescriptionTitle', - { - defaultMessage: 'Document description', - } -); - -export const ALERT_REASON_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.alertReasonTitle', - { - defaultMessage: 'Alert reason', - } -); - -export const DOCUMENT_REASON_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.documentReasonTitle', - { - defaultMessage: 'Document reason', - } -); - -/* Investigation section */ - -export const INVESTIGATION_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.investigationSectionTitle', - { - defaultMessage: 'Investigation', - } -); - -export const HIGHLIGHTED_FIELDS_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.highlightedFieldsTitle', - { defaultMessage: 'Highlighted fields' } -); - -export const HIGHLIGHTED_FIELDS_FIELD_COLUMN = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.highlightedFields.fieldColumn', - { defaultMessage: 'Field' } -); - -export const HIGHLIGHTED_FIELDS_VALUE_COLUMN = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.highlightedFields.valueColumn', - { defaultMessage: 'Value' } -); - -/* Insights section */ - -export const ENTITIES_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.entitiesTitle', - { defaultMessage: 'Entities' } -); - -export const ENTITIES_NO_DATA_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.entitiesNoDataMessage', - { - defaultMessage: 'Host and user information are unavailable for this alert', - } -); - -export const THREAT_INTELLIGENCE_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.threatIntelligenceTitle', - { defaultMessage: 'Threat intelligence' } -); - -export const INSIGHTS_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.insightsTitle', - { defaultMessage: 'Insights' } -); - -export const CORRELATIONS_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.correlationsTitle', - { defaultMessage: 'Correlations' } -); - -export const CORRELATIONS_ERROR = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.correlations.error', - { - defaultMessage: 'No correlations data available', - } -); - -export const PREVALENCE_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.prevalenceTitle', - { defaultMessage: 'Prevalence' } -); - -export const PREVALENCE_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.prevalenceNoData', - { - defaultMessage: 'No prevalence data available.', - } -); - -export const THREAT_MATCH_DETECTED = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatch', - { - defaultMessage: `threat match detected`, - } -); - -export const THREAT_MATCHES_DETECTED = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatches', - { - defaultMessage: `threat matches detected`, - } -); - -export const THREAT_ENRICHMENT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichment', - { - defaultMessage: `field enriched with threat intelligence`, - } -); - -export const THREAT_ENRICHMENTS = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichments', - { - defaultMessage: `fields enriched with threat intelligence`, - } -); - -export const PREVALENCE_ROW_UNCOMMON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.overviewTab.prevalenceRowText', - { - defaultMessage: 'is uncommon', - } -); - -export const VISUALIZATIONS_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.visualizationsTitle', - { defaultMessage: 'Visualizations' } -); - -export const ANALYZER_PREVIEW_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.analyzerPreviewTitle', - { defaultMessage: 'Analyzer preview' } -); - -export const SHARE = i18n.translate('xpack.securitySolution.flyout.documentDetails.share', { - defaultMessage: 'Share Alert', -}); - -export const INVESTIGATION_GUIDE_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.investigationGuideTitle', - { - defaultMessage: 'Investigation guide', - } -); - -export const INVESTIGATION_GUIDE_BUTTON = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.investigationGuideButton', - { - defaultMessage: 'Show investigation guide', - } -); - -export const INVESTIGATION_GUIDE_NO_DATA = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.investigationGuideNoData', - { - defaultMessage: 'There’s no investigation guide for this rule.', - } -); - -export const SESSION_PREVIEW_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.sessionPreview.title', - { - defaultMessage: 'Session viewer preview', - } -); - -export const SESSION_PREVIEW_PROCESS_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.sessionPreview.processText', - { - defaultMessage: 'started', - } -); - -export const SESSION_PREVIEW_TIME_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.sessionPreview.timeText', - { - defaultMessage: 'at', - } -); - -export const SESSION_PREVIEW_RULE_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.sessionPreview.ruleText', - { - defaultMessage: 'with rule', - } -); - -export const SESSION_PREVIEW_COMMAND_TEXT = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.sessionPreview.commandText', - { - defaultMessage: 'by', - } -); - -export const RESPONSE_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.responseSectionTitle', - { - defaultMessage: 'Response', - } -); - -export const RESPONSE_EMPTY = i18n.translate('xpack.securitySolution.flyout.response.empty', { - defaultMessage: 'There are no response actions defined for this event.', -}); - -export const TECHNICAL_PREVIEW_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.technicalPreviewTitle', - { defaultMessage: 'Technical preview' } -); - -export const TECHNICAL_PREVIEW_MESSAGE = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.technicalPreviewMessage', - { - defaultMessage: - 'This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.', - } -); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx index 998f6f71b02a7..941a5c299ffbe 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/user_entity_overview.tsx @@ -18,6 +18,7 @@ import { import { css } from '@emotion/css'; import { getOr } from 'lodash/fp'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { FormattedMessage } from '@kbn/i18n-react'; import { LeftPanelInsightsTab, LeftPanelKey } from '../../left'; import { ENTITIES_TAB_ID } from '../../left/components/entities_details'; import { useRightPanelContext } from '../context'; @@ -44,7 +45,6 @@ import { ENTITIES_USER_OVERVIEW_LINK_TEST_ID, TECHNICAL_PREVIEW_ICON_TEST_ID, } from './test_ids'; -import { TECHNICAL_PREVIEW_TITLE, TECHNICAL_PREVIEW_MESSAGE } from './translations'; import { useObservedUserDetails } from '../../../explore/users/containers/users/observed_details'; const USER_ICON = 'user'; @@ -149,10 +149,20 @@ export const UserEntityOverview: React.FC<UserEntityOverviewProps> = ({ userName <> {i18n.USER_RISK_CLASSIFICATION} <EuiIconTip - title={TECHNICAL_PREVIEW_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.entities.userTechnicalPreviewButtonLabel" + defaultMessage="Technical preview" + /> + } size="m" type="iInCircle" - content={TECHNICAL_PREVIEW_MESSAGE} + content={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.insights.entities.userTechnicalPreviewTooltip" + defaultMessage="This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but features in technical preview are not subject to the support SLA of official GA features." + /> + } position="bottom" iconProps={{ className: 'eui-alignTop', diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.test.tsx index a427cdf04bce9..2d66833843331 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { VISUALIZATIONS_SECTION_HEADER_TEST_ID } from './test_ids'; import { TestProviders } from '../../../common/mock'; @@ -42,11 +43,13 @@ describe('<VisualizationsSection />', () => { } as unknown as ExpandableFlyoutContext; const { getByTestId, getAllByRole } = render( - <ExpandableFlyoutContext.Provider value={flyoutContextValue}> - <RightPanelContext.Provider value={contextValue}> - <VisualizationsSection /> - </RightPanelContext.Provider> - </ExpandableFlyoutContext.Provider> + <IntlProvider locale="en"> + <ExpandableFlyoutContext.Provider value={flyoutContextValue}> + <RightPanelContext.Provider value={contextValue}> + <VisualizationsSection /> + </RightPanelContext.Provider> + </ExpandableFlyoutContext.Provider> + </IntlProvider> ); expect(getByTestId(VISUALIZATIONS_SECTION_HEADER_TEST_ID)).toBeInTheDocument(); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.tsx index b2cc0d2969c7e..4b53911bea590 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/visualizations_section.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { AnalyzerPreviewContainer } from './analyzer_preview_container'; import { SessionPreviewContainer } from './session_preview_container'; import { ExpandableSection } from './expandable_section'; import { VISUALIZATIONS_SECTION_TEST_ID } from './test_ids'; -import { VISUALIZATIONS_TITLE } from './translations'; export interface VisualizationsSectionProps { /** @@ -29,7 +29,12 @@ export const VisualizationsSection: React.FC<VisualizationsSectionProps> = ({ return ( <ExpandableSection expanded={expanded} - title={VISUALIZATIONS_TITLE} + title={ + <FormattedMessage + id="xpack.securitySolution.flyout.right.visualizations.sectionTitle" + defaultMessage="Visualizations" + /> + } data-test-subj={VISUALIZATIONS_SECTION_TEST_ID} > <SessionPreviewContainer /> diff --git a/x-pack/plugins/security_solution/public/flyout/right/tabs.tsx b/x-pack/plugins/security_solution/public/flyout/right/tabs.tsx index 89802787283fe..1cdc25f36c01b 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/tabs.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/tabs.tsx @@ -5,17 +5,18 @@ * 2.0. */ +import type { ReactElement } from 'react'; import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; import { JSON_TAB_TEST_ID, OVERVIEW_TAB_TEST_ID, TABLE_TAB_TEST_ID } from './test_ids'; import type { RightPanelPaths } from '.'; import { JsonTab } from './tabs/json_tab'; import { OverviewTab } from './tabs/overview_tab'; import { TableTab } from './tabs/table_tab'; -import { JSON_TAB, OVERVIEW_TAB, TABLE_TAB } from './translations'; export type RightPanelTabsType = Array<{ id: RightPanelPaths; - name: string; + name: ReactElement; content: React.ReactElement; 'data-test-subj': string; }>; @@ -27,19 +28,34 @@ export const tabs: RightPanelTabsType = [ { id: 'overview', 'data-test-subj': OVERVIEW_TAB_TEST_ID, - name: OVERVIEW_TAB, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.overviewTabLabel" + defaultMessage="Overview" + /> + ), content: <OverviewTab />, }, { id: 'table', 'data-test-subj': TABLE_TAB_TEST_ID, - name: TABLE_TAB, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.tableTabLabel" + defaultMessage="Table" + /> + ), content: <TableTab />, }, { id: 'json', 'data-test-subj': JSON_TAB_TEST_ID, - name: JSON_TAB, + name: ( + <FormattedMessage + id="xpack.securitySolution.flyout.right.header.jsonTabLabel" + defaultMessage="JSON" + /> + ), content: <JsonTab />, }, ]; diff --git a/x-pack/plugins/security_solution/public/flyout/right/tabs/translations.ts b/x-pack/plugins/security_solution/public/flyout/right/tabs/translations.ts deleted file mode 100644 index 741a12676a094..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/tabs/translations.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const DOCUMENT_ERROR_TITLE = i18n.translate( - 'xpack.securitySolution.flyout.documentErrorTitle', - { - defaultMessage: 'document information', - } -); - -export const DOCUMENT_ERROR_DETAILS = i18n.translate( - 'xpack.securitySolution.flyout.documentErrorMessage', - { - defaultMessage: 'the document fields and values', - } -); diff --git a/x-pack/plugins/security_solution/public/flyout/right/translations.ts b/x-pack/plugins/security_solution/public/flyout/right/translations.ts deleted file mode 100644 index fe4b31c2aef64..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/translations.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const OVERVIEW_TAB = i18n.translate( - 'xpack.securitySolution.flyout.documentDetails.overviewTab', - { defaultMessage: 'Overview' } -); - -export const TABLE_TAB = i18n.translate('xpack.securitySolution.flyout.documentDetails.tableTab', { - defaultMessage: 'Table', -}); - -export const JSON_TAB = i18n.translate('xpack.securitySolution.flyout.documentDetails.jsonTab', { - defaultMessage: 'JSON', -}); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.test.tsx index e3db86494b481..f0565fe1df43f 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.test.tsx @@ -6,16 +6,22 @@ */ import React from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { FlyoutError } from './flyout_error'; -import { ERROR_MESSAGE, ERROR_TITLE, FLYOUT_ERROR } from '../translations'; import { FLYOUT_ERROR_TEST_ID } from '../test_ids'; describe('<FlyoutError />', () => { it('should render error title and body', () => { - const { getByTestId } = render(<FlyoutError />); + const { getByTestId } = render( + <IntlProvider locale="en"> + <FlyoutError /> + </IntlProvider> + ); expect(getByTestId(FLYOUT_ERROR_TEST_ID)).toBeInTheDocument(); - expect(getByTestId(FLYOUT_ERROR_TEST_ID)).toHaveTextContent(ERROR_TITLE(FLYOUT_ERROR)); - expect(getByTestId(FLYOUT_ERROR_TEST_ID)).toHaveTextContent(ERROR_MESSAGE(FLYOUT_ERROR)); + expect(getByTestId(FLYOUT_ERROR_TEST_ID)).toHaveTextContent('Unable to display data'); + expect(getByTestId(FLYOUT_ERROR_TEST_ID)).toHaveTextContent( + 'There was an error displaying data.' + ); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.tsx index 700ba9850b75d..bda4e581e164b 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { EuiEmptyPrompt, EuiFlexItem } from '@elastic/eui'; -import { ERROR_MESSAGE, ERROR_TITLE, FLYOUT_ERROR } from '../translations'; +import { FormattedMessage } from '@kbn/i18n-react'; import { FLYOUT_ERROR_TEST_ID } from '../test_ids'; /** @@ -18,8 +18,24 @@ export const FlyoutError: React.VFC = () => ( <EuiEmptyPrompt iconType="error" color="danger" - title={<h2>{ERROR_TITLE(FLYOUT_ERROR)}</h2>} - body={<p>{ERROR_MESSAGE(FLYOUT_ERROR)}</p>} + title={ + <h2> + <FormattedMessage + id="xpack.securitySolution.flyout.shared.errorTitle" + defaultMessage="Unable to display {title}." + values={{ title: 'data' }} + /> + </h2> + } + body={ + <p> + <FormattedMessage + id="xpack.securitySolution.flyout.shared.errorDescription" + defaultMessage="There was an error displaying {message}." + values={{ message: 'data' }} + /> + </p> + } data-test-subj={FLYOUT_ERROR_TEST_ID} /> </EuiFlexItem> diff --git a/x-pack/plugins/security_solution/public/flyout/shared/translations.ts b/x-pack/plugins/security_solution/public/flyout/shared/translations.ts deleted file mode 100644 index 5ecf772c5c0c0..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/shared/translations.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const FLYOUT_ERROR = i18n.translate('xpack.securitySolution.flyout.documentDetails.error', { - defaultMessage: 'data', -}); - -export const ERROR_TITLE = (title: string) => - i18n.translate('xpack.securitySolution.flyout.errorTitle', { - values: { title }, - defaultMessage: 'Unable to display {title}', - }); - -export const ERROR_MESSAGE = (message: string) => - i18n.translate('xpack.securitySolution.flyout.errorMessage', { - values: { message }, - defaultMessage: 'There was an error displaying {message}', - }); - -export const CORRELATIONS_SUPPRESSED_ALERTS = (count: number) => - i18n.translate('xpack.securitySolution.flyout.documentDetails.correlations.suppressedAlerts', { - defaultMessage: 'suppressed {count, plural, =1 {alert} other {alerts}}', - values: { count }, - }); - -export const CORRELATIONS_ANCESTRY_ALERTS = (count: number) => - i18n.translate('xpack.securitySolution.flyout.documentDetails.correlations.ancestryAlerts', { - defaultMessage: '{count, plural, one {alert} other {alerts}} related by ancestry', - values: { count }, - }); - -export const CORRELATIONS_SAME_SOURCE_ALERTS = (count: number) => - i18n.translate('xpack.securitySolution.flyout.documentDetails.correlations.sourceAlerts', { - defaultMessage: '{count, plural, one {alert} other {alerts}} related by source event', - values: { count }, - }); - -export const CORRELATIONS_SESSION_ALERTS = (count: number) => - i18n.translate('xpack.securitySolution.flyout.documentDetails.correlations.sessionAlerts', { - defaultMessage: '{count, plural, one {alert} other {alerts}} related by session', - values: { count }, - }); - -export const CORRELATIONS_RELATED_CASES = (count: number) => - i18n.translate('xpack.securitySolution.flyout.documentDetails.correlations.relatedCases', { - defaultMessage: 'related {count, plural, one {case} other {cases}}', - values: { count }, - }); diff --git a/x-pack/plugins/security_solution/public/management/cypress.config.ts b/x-pack/plugins/security_solution/public/management/cypress.config.ts index b02724cb8eec8..34e7ae02cb626 100644 --- a/x-pack/plugins/security_solution/public/management/cypress.config.ts +++ b/x-pack/plugins/security_solution/public/management/cypress.config.ts @@ -37,7 +37,7 @@ export default defineCypressConfig({ ELASTICSEARCH_URL: 'http://localhost:9200', FLEET_SERVER_URL: 'https://localhost:8220', // Username/password used for both elastic and kibana - KIBANA_USERNAME: 'elastic', + KIBANA_USERNAME: 'system_indices_superuser', KIBANA_PASSWORD: 'changeme', ELASTICSEARCH_USERNAME: 'system_indices_superuser', ELASTICSEARCH_PASSWORD: 'changeme', diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_details.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_details.cy.ts index 577164ff4d893..49bb33cbc3267 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_details.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_details.cy.ts @@ -26,7 +26,7 @@ describe('Policy Details', () => { describe('Renders and saves protection updates', () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; - const today = moment(); + const today = moment.utc(); const formattedToday = today.format('MMMM DD, YYYY'); beforeEach(() => { @@ -99,7 +99,7 @@ describe('Policy Details', () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; - const twoMonthsAgo = moment().subtract(2, 'months').format('YYYY-MM-DD'); + const twoMonthsAgo = moment.utc().subtract(2, 'months').format('YYYY-MM-DD'); beforeEach(() => { login(); @@ -143,7 +143,7 @@ describe('Policy Details', () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; - const twoMonthsAgo = moment().subtract(2, 'months').format('YYYY-MM-DD'); + const twoMonthsAgo = moment.utc().subtract(2, 'months').format('YYYY-MM-DD'); beforeEach(() => { login(); @@ -186,7 +186,7 @@ describe('Policy Details', () => { describe('Renders read only protection updates for user without write permissions', () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; - const twoMonthsAgo = moment().subtract(2, 'months'); + const twoMonthsAgo = moment.utc().subtract(2, 'months'); beforeEach(() => { login(ROLE.endpoint_security_policy_management_read); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_list.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_list.cy.ts index aca3a8b68a81a..1b70ecba0882e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_list.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/policy_list.cy.ts @@ -8,7 +8,6 @@ import moment from 'moment'; import { setCustomProtectionUpdatesManifestVersion } from '../../tasks/endpoint_policy'; import { disableExpandableFlyoutAdvancedSettings, loadPage } from '../../tasks/common'; -import type { PolicyData } from '../../../../../common/endpoint/types'; import type { IndexedFleetEndpointPolicyResponse } from '../../../../../common/endpoint/data_loaders/index_fleet_endpoint_policy'; import { login } from '../../tasks/login'; @@ -17,13 +16,16 @@ import { createAgentPolicyTask, getEndpointIntegrationVersion } from '../../task describe('Policy List', () => { describe('Renders policy list with outdated policies', () => { const indexedPolicies: IndexedFleetEndpointPolicyResponse[] = []; - const policies: PolicyData[] = []; - const monthAgo = moment().subtract(1, 'months').format('YYYY-MM-DD'); - const threeDaysAgo = moment().subtract(3, 'days').format('YYYY-MM-DD'); - const nineteenMonthsAgo = moment().subtract(19, 'months').format('YYYY-MM-DD'); + const monthAgo = moment.utc().subtract(1, 'months').format('YYYY-MM-DD'); + const threeDaysAgo = moment.utc().subtract(3, 'days').format('YYYY-MM-DD'); + const eighteenMonthsAgo = moment + .utc() + .subtract(18, 'months') + .add(1, 'day') + .format('YYYY-MM-DD'); - const dates = [monthAgo, threeDaysAgo, nineteenMonthsAgo]; + const dates = [monthAgo, threeDaysAgo, eighteenMonthsAgo]; beforeEach(() => { login(); @@ -35,7 +37,6 @@ describe('Policy List', () => { for (let i = 0; i < 4; i++) { createAgentPolicyTask(version).then((data) => { indexedPolicies.push(data); - policies.push(data.integrationPolicies[0]); if (dates[i]) { setCustomProtectionUpdatesManifestVersion(data.integrationPolicies[0].id, dates[i]); } @@ -56,7 +57,7 @@ describe('Policy List', () => { loadPage('/app/security/administration/policy'); cy.getByTestSubj('policy-list-outdated-manifests-call-out').should('contain', '2 policies'); dates.forEach((date) => { - cy.contains(moment(date, 'YYYY-MM-DD').format('MMMM DD, YYYY')); + cy.contains(moment.utc(date, 'YYYY-MM-DD').format('MMMM DD, YYYY')); }); cy.getByTestSubj('policyDeployedVersion').should('have.length', 4); }); @@ -64,7 +65,6 @@ describe('Policy List', () => { describe('Renders policy list with no outdated policies', () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; - let policy: PolicyData; beforeEach(() => { login(); @@ -75,7 +75,6 @@ describe('Policy List', () => { getEndpointIntegrationVersion().then((version) => { createAgentPolicyTask(version).then((data) => { indexedPolicy = data; - policy = indexedPolicy.integrationPolicies[0]; }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.ts b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.ts index 73f260d63b4b9..cd1a4c506bc38 100644 --- a/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.ts +++ b/x-pack/plugins/security_solution/public/management/cypress_endpoint.config.ts @@ -39,6 +39,10 @@ export default defineCypressConfig({ 'cypress-react-selector': { root: '#security-solution-app', }, + KIBANA_USERNAME: 'system_indices_superuser', + KIBANA_PASSWORD: 'changeme', + ELASTICSEARCH_USERNAME: 'system_indices_superuser', + ELASTICSEARCH_PASSWORD: 'changeme', }, e2e: { diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx index 57ca95fd59de8..1a1a76ddcf198 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_list.tsx @@ -172,9 +172,9 @@ export const PolicyList = memo(() => { ]; } - const parsedDate = moment(version, 'YYYY-MM-DD'); + const parsedDate = moment.utc(version, 'YYYY-MM-DD'); - if (parsedDate < moment().subtract(18, 'months')) { + if (parsedDate < moment.utc().subtract(18, 'months')) { return [ 'danger', parsedDate.format('MMMM DD, YYYY'), @@ -184,7 +184,7 @@ export const PolicyList = memo(() => { ]; } - if (parsedDate > moment().subtract(1, 'month')) { + if (parsedDate > moment.utc().subtract(1, 'month')) { return ['success', parsedDate.format('MMMM DD, YYYY')]; } diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/protection_updates/protection_updates_layout.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/protection_updates/protection_updates_layout.tsx index 499be2cf31284..eaac2595c931b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/protection_updates/protection_updates_layout.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/protection_updates/protection_updates_layout.tsx @@ -68,7 +68,7 @@ export const ProtectionUpdatesLayout = React.memo<ProtectionUpdatesLayoutProps>( const deployedVersion = policy.inputs[0].config.policy.value.global_manifest_version; const [manifestVersion, setManifestVersion] = useState(deployedVersion); - const today = moment(); + const today = moment.utc(); const [selectedDate, setSelectedDate] = useState<Moment>(today); const { data: fetchedNote, isLoading: getNoteInProgress } = useGetProtectionUpdatesNote({ @@ -88,8 +88,8 @@ export const ProtectionUpdatesLayout = React.memo<ProtectionUpdatesLayoutProps>( const automaticUpdatesEnabled = manifestVersion === 'latest'; const internalDateFormat = 'YYYY-MM-DD'; const displayDateFormat = 'MMMM DD, YYYY'; - const formattedDate = moment(deployedVersion, internalDateFormat).format(displayDateFormat); - const cutoffDate = moment().subtract(18, 'months'); // Earliest selectable date + const formattedDate = moment.utc(deployedVersion, internalDateFormat).format(displayDateFormat); + const cutoffDate = moment.utc().subtract(18, 'months').add(1, 'day'); // Earliest selectable date const viewModeSwitchLabel = automaticUpdatesEnabled ? AUTOMATIC_UPDATES_CHECKBOX_LABEL @@ -226,7 +226,7 @@ export const ProtectionUpdatesLayout = React.memo<ProtectionUpdatesLayoutProps>( return null; } - const deployedVersionDate = moment(deployedVersion).format(internalDateFormat); + const deployedVersionDate = moment.utc(deployedVersion).format(internalDateFormat); const daysSinceLastUpdate = today.diff(deployedVersionDate, 'days'); if (daysSinceLastUpdate < 30) { diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts index aff700948b344..db3fe4b32f1e4 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts @@ -37,6 +37,10 @@ import type { import nodeFetch from 'node-fetch'; import semver from 'semver'; import axios from 'axios'; +import { + RETRYABLE_TRANSIENT_ERRORS, + retryOnError, +} from '../../../common/endpoint/data_loaders/utils'; import { fetchKibanaStatus } from './stack_services'; import { catchAxiosErrorFormatAndThrow } from './format_axios_error'; import { FleetAgentGenerator } from '../../../common/endpoint/data_generators/fleet_agent_generator'; @@ -137,11 +141,15 @@ export const waitForHostToEnroll = async ( let found: Agent | undefined; while (!found && !hasTimedOut()) { - found = await fetchFleetAgents(kbnClient, { - perPage: 1, - kuery: `(local_metadata.host.hostname.keyword : "${hostname}") and (status:online)`, - showInactive: false, - }).then((response) => response.items[0]); + found = await retryOnError( + async () => + fetchFleetAgents(kbnClient, { + perPage: 1, + kuery: `(local_metadata.host.hostname.keyword : "${hostname}") and (status:online)`, + showInactive: false, + }).then((response) => response.items[0]), + RETRYABLE_TRANSIENT_ERRORS + ); if (!found) { // sleep and check again diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/format_axios_error.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/format_axios_error.ts index f1b69c8665fc6..1f0c7da3bbad6 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/format_axios_error.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/format_axios_error.ts @@ -22,7 +22,11 @@ export class FormattedAxiosError extends Error { }; constructor(axiosError: AxiosError) { - super(axiosError.message); + super( + `${axiosError.message}${ + axiosError?.response?.data ? `: ${JSON.stringify(axiosError?.response?.data)}` : '' + }` + ); this.request = { method: axiosError.config?.method ?? '?', diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts index 366b2a81cefcb..7e5d9a95efe76 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/stack_services.ts @@ -15,11 +15,15 @@ import nodeFetch from 'node-fetch'; import type { ReqOptions } from '@kbn/test/src/kbn_client/kbn_client_requester'; import { type AxiosResponse } from 'axios'; import type { ClientOptions } from '@elastic/elasticsearch/lib/client'; +import fs from 'fs'; +import { CA_CERT_PATH } from '@kbn/dev-utils'; import { catchAxiosErrorFormatAndThrow } from './format_axios_error'; import { isLocalhost } from './is_localhost'; import { getLocalhostRealIp } from './localhost_services'; import { createSecuritySuperuser } from './security_user_services'; +const CA_CERTIFICATE: Buffer = fs.readFileSync(CA_CERT_PATH); + export interface RuntimeServices { kbnClient: KbnClient; esClient: Client; @@ -64,6 +68,8 @@ interface CreateRuntimeServicesOptions { esPassword?: string; log?: ToolingLog; asSuperuser?: boolean; + /** If true, then a certificate will not be used when creating the Kbn/Es clients when url is `https` */ + noCertForSsl?: boolean; } class KbnClientExtended extends KbnClient { @@ -105,26 +111,39 @@ export const createRuntimeServices = async ({ esPassword, log = new ToolingLog({ level: 'info', writeTo: process.stdout }), asSuperuser = false, + noCertForSsl, }: CreateRuntimeServicesOptions): Promise<RuntimeServices> => { let username = _username; let password = _password; if (asSuperuser) { await waitForKibana(kibanaUrl); + const tmpEsClient = createEsClient({ + url: elasticsearchUrl, + username, + password, + log, + noCertForSsl, + }); - const superuserResponse = await createSecuritySuperuser( - createEsClient({ - url: elasticsearchUrl, - username, - password, - log, - }) - ); + const isServerlessEs = (await tmpEsClient.info()).version.build_flavor === 'serverless'; + + if (isServerlessEs) { + log?.warning( + 'Creating Security Superuser is not supported in current environment. ES is running in serverless mode. ' + + 'Will use username [system_indices_superuser] instead.' + ); + + username = 'system_indices_superuser'; + password = 'changeme'; + } else { + const superuserResponse = await createSecuritySuperuser(tmpEsClient); - ({ username, password } = superuserResponse); + ({ username, password } = superuserResponse); - if (superuserResponse.created) { - log.info(`Kibana user [${username}] was crated with password [${password}]`); + if (superuserResponse.created) { + log.info(`Kibana user [${username}] was crated with password [${password}]`); + } } } @@ -133,16 +152,17 @@ export const createRuntimeServices = async ({ const fleetURL = new URL(fleetServerUrl); return { - kbnClient: createKbnClient({ log, url: kibanaUrl, username, password, apiKey }), + kbnClient: createKbnClient({ log, url: kibanaUrl, username, password, apiKey, noCertForSsl }), esClient: createEsClient({ log, url: elasticsearchUrl, username: esUsername ?? username, password: esPassword ?? password, apiKey, + noCertForSsl, }), log, - localhostRealIp: await getLocalhostRealIp(), + localhostRealIp: getLocalhostRealIp(), apiKey: apiKey ?? '', user: { username, @@ -188,6 +208,7 @@ export const createEsClient = ({ password, apiKey, log, + noCertForSsl, }: { url: string; username: string; @@ -195,11 +216,19 @@ export const createEsClient = ({ /** If defined, both `username` and `password` will be ignored */ apiKey?: string; log?: ToolingLog; + noCertForSsl?: boolean; }): Client => { + const isHttps = new URL(url).protocol.startsWith('https'); const clientOptions: ClientOptions = { node: buildUrlWithCredentials(url, apiKey ? '' : username, apiKey ? '' : password), }; + if (isHttps && !noCertForSsl) { + clientOptions.tls = { + ca: [CA_CERTIFICATE], + }; + } + if (apiKey) { clientOptions.auth = { apiKey }; } @@ -217,6 +246,7 @@ export const createKbnClient = ({ password, apiKey, log = new ToolingLog(), + noCertForSsl, }: { url: string; username: string; @@ -224,16 +254,28 @@ export const createKbnClient = ({ /** If defined, both `username` and `password` will be ignored */ apiKey?: string; log?: ToolingLog; + noCertForSsl?: boolean; }): KbnClient => { - const kbnUrl = buildUrlWithCredentials(url, username, password); + const isHttps = new URL(url).protocol.startsWith('https'); + const clientOptions: ConstructorParameters<typeof KbnClientExtended>[0] = { + log, + apiKey, + url: buildUrlWithCredentials(url, username, password), + }; + + if (isHttps && !noCertForSsl) { + clientOptions.certificateAuthorities = [CA_CERTIFICATE]; + } if (log) { log.verbose( - `Creating Kibana client with URL: ${kbnUrl} ${apiKey ? ` + ApiKey: ${apiKey}` : ''}` + `Creating Kibana client with URL: ${clientOptions.url} ${ + apiKey ? ` + ApiKey: ${apiKey}` : '' + }` ); } - return new KbnClientExtended({ log, url: kbnUrl, apiKey }); + return new KbnClientExtended(clientOptions); }; /** @@ -287,3 +329,18 @@ export const waitForKibana = async (kbnUrl: string): Promise<void> => { { maxTimeout: 10000 } ); }; + +export const isServerlessKibanaFlavor = async (kbnClient: KbnClient): Promise<boolean> => { + const kbnStatus = await fetchKibanaStatus(kbnClient); + + // If we don't have status for plugins, then error + // the Status API will always return something (its an open API), but if auth was successful, + // it will also return more data. + if (!kbnStatus.status.plugins) { + throw new Error( + `Unable to retrieve Kibana plugins status (likely an auth issue with the username being used for kibana)` + ); + } + + return kbnStatus.status.plugins?.serverless?.level === 'available'; +}; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts b/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts index c0be16370ddcc..c1c38dcf8b30a 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/resolver_generator_script.ts @@ -19,7 +19,7 @@ import { METADATA_DATASTREAM } from '../../common/endpoint/constants'; import { EndpointMetadataGenerator } from '../../common/endpoint/data_generators/endpoint_metadata_generator'; import { indexHostsAndAlerts } from '../../common/endpoint/index_data'; import { ANCESTRY_LIMIT, EndpointDocGenerator } from '../../common/endpoint/generate_data'; -import { fetchStackVersion } from './common/stack_services'; +import { fetchStackVersion, isServerlessKibanaFlavor } from './common/stack_services'; import { ENDPOINT_ALERTS_INDEX, ENDPOINT_EVENTS_INDEX } from './common/constants'; import { getWithResponseActionsRole } from './common/roles_users/with_response_actions_role'; import { getNoResponseActionsRole } from './common/roles_users/without_response_actions_role'; @@ -161,6 +161,8 @@ function updateURL({ } async function main() { + const startTime = new Date().getTime(); + const argv = yargs.help().options({ seed: { alias: 's', @@ -318,17 +320,16 @@ async function main() { default: false, }, }).argv; - let ca: Buffer; + let ca: Buffer; let clientOptions: ClientOptions; let url: string; let node: string; - const toolingLogOptions = { - log: new ToolingLog({ - level: 'info', - writeTo: process.stdout, - }), - }; + const logger = new ToolingLog({ + level: 'info', + writeTo: process.stdout, + }); + const toolingLogOptions = { log: logger }; let kbnClientOptions: KbnClientOptions = { ...toolingLogOptions, @@ -350,38 +351,62 @@ async function main() { clientOptions = { node: argv.node }; } let client = new Client(clientOptions); + let kbnClient = new KbnClient({ ...kbnClientOptions }); let user: UserInfo | undefined; - // if fleet flag is used - if (argv.fleet) { - // add endpoint user if --withNewUser flag has values as username:password - const newUserCreds = - argv.withNewUser.indexOf(':') !== -1 ? argv.withNewUser.split(':') : undefined; - user = await addUser( - client, - newUserCreds - ? { - username: newUserCreds[0], - password: newUserCreds[1], - } - : undefined + const isServerless = await isServerlessKibanaFlavor(kbnClient); + + logger.info(`Build flavor: ${isServerless ? 'serverless' : 'non-serverless'}`); + + if (argv.fleet && !argv.withNewUser && !isServerless) { + // warn and exit when using fleet flag + logger.error( + 'Please use the --withNewUser=username:password flag to add a custom user with required roles when --fleet is enabled!' ); + // eslint-disable-next-line no-process-exit + process.exit(0); + } - // update client and kibana options before instantiating - if (user) { - // use endpoint user for Es and Kibana URLs + // if fleet flag is used + if (argv.fleet) { + if (!isServerless) { + // add endpoint user if --withNewUser flag has values as username:password + const newUserCreds = + argv.withNewUser.indexOf(':') !== -1 ? argv.withNewUser.split(':') : undefined; + user = await addUser( + client, + newUserCreds + ? { + username: newUserCreds[0], + password: newUserCreds[1], + } + : undefined + ); + + // update client and kibana options before instantiating + if (user) { + // use endpoint user for Es and Kibana URLs + + url = updateURL({ url: argv.kibana, user }); + node = updateURL({ url: argv.node, user }); + + kbnClientOptions = { + ...kbnClientOptions, + url, + }; - url = updateURL({ url: argv.kibana, user }); - node = updateURL({ url: argv.node, user }); + client = new Client({ ...clientOptions, node }); + kbnClient = new KbnClient({ ...kbnClientOptions }); - kbnClientOptions = { - ...kbnClientOptions, - url, - }; - client = new Client({ ...clientOptions, node }); + logger.verbose(`ES/KBN clients updated to login using: ${JSON.stringify(user)}`); + } + } else { + logger.warning( + 'Option `--withNewUser` not supported in serverless.\n' + + 'Ensure that `--kibana` and `--node` options are defined with username/password of ' + + '`system_indices_superuser:changeme`' + ); } } - // instantiate kibana client - const kbnClient = new KbnClient({ ...kbnClientOptions }); if (argv.delete) { await deleteIndices( @@ -391,6 +416,12 @@ async function main() { } if (argv.rbacUser) { + if (isServerless) { + // FIXME:PT create users in serverless when that capability is available + + throw new Error(`Can not use '--rbacUser' option against serverless deployment`); + } + // Add roles and users with response actions kibana privileges for (const role of Object.keys(rolesMapping)) { const addedRole = await addRole(kbnClient, { @@ -398,32 +429,15 @@ async function main() { ...rolesMapping[role], }); if (addedRole) { - console.log(`Successfully added ${role} role`); + logger.info(`Successfully added ${role} role`); await addUser(client, { username: role, password: 'changeme', roles: [role] }); } else { - console.log(`Failed to add role, ${role}`); + logger.warning(`Failed to add role, ${role}`); } } } - let seed = argv.seed; - - if (!seed) { - seed = Math.random().toString(); - console.log(`No seed supplied, using random seed: ${seed}`); - } - - const startTime = new Date().getTime(); - - if (argv.fleet && !argv.withNewUser) { - // warn and exit when using fleet flag - console.log( - 'Please use the --withNewUser=username:password flag to add a custom user with required roles when --fleet is enabled!' - ); - // eslint-disable-next-line no-process-exit - process.exit(0); - } - + const seed = argv.seed || Math.random().toString(); let DocGenerator: typeof EndpointDocGenerator = EndpointDocGenerator; // If `--randomVersions` is NOT set, then use custom generator that ensures all data generated @@ -446,6 +460,7 @@ async function main() { }; } + logger.info('Indexing host and alerts...'); await indexHostsAndAlerts( client, kbnClient, @@ -475,11 +490,12 @@ async function main() { ); // delete endpoint_user after - if (user) { + if (user && !isServerless) { const deleted = await deleteUser(client, user.username); if (deleted.found) { - console.log(`User ${user.username} deleted successfully!`); + logger.info(`User ${user.username} deleted successfully!`); } } - console.log(`Creating and indexing documents took: ${new Date().getTime() - startTime}ms`); + + logger.info(`Creating and indexing documents took: ${new Date().getTime() - startTime}ms`); } diff --git a/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts b/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts index f1b131fc63721..4cb94c1dc814f 100644 --- a/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts +++ b/x-pack/plugins/security_solution/scripts/run_cypress/parallel.ts @@ -128,7 +128,7 @@ ${JSON.stringify(cypressConfigFile, null, 2)} const isGrepReturnedFilePaths = _.isArray(grepSpecPattern); const isGrepReturnedSpecPattern = !isGrepReturnedFilePaths && grepSpecPattern === specPattern; - const { grepFilterSpecs } = cypressConfigFile.env; + const grepFilterSpecs = cypressConfigFile.env?.grepFilterSpecs; // IMPORTANT! // When grep returns the same spec pattern as it gets in its arguments, we treat it as diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts index 43292c8436fdc..b91bfae4eb405 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts @@ -437,6 +437,66 @@ describe('ingest_integration tests ', () => { licenseEmitter.next(Platinum); // set license level to platinum }); + it.each([ + { + date: 'invalid', + message: 'Invalid date format. Use "latest" or "YYYY-MM-DD" format. UTC time.', + }, + { + date: '2023-10-1', + message: 'Invalid date format. Use "latest" or "YYYY-MM-DD" format. UTC time.', + }, + { + date: '2020-10-31', + message: + 'Global manifest version is too far in the past. Use "latest" or a date within the last 18 months. UTC time.', + }, + { + date: '2100-10-01', + message: 'Global manifest version cannot be in the future. UTC time.', + }, + { + date: 'latest', + }, + ])( + 'should return bad request for invalid endpoint package policy global manifest values', + async ({ date, message }) => { + const mockPolicy = policyFactory(); // defaults with paid features on + const logger = loggingSystemMock.create().get('ingest_integration.test'); + const callback = getPackagePolicyUpdateCallback( + logger, + licenseService, + endpointAppContextMock.featureUsageService, + endpointAppContextMock.endpointMetadataService, + cloudService, + esClient, + appFeaturesService + ); + const policyConfig = generator.generatePolicyPackagePolicy(); + policyConfig.inputs[0]!.config!.policy.value = { + ...mockPolicy, + global_manifest_version: date, + }; + if (!message) { + const updatedPolicyConfig = await callback( + policyConfig, + soClient, + esClient, + requestContextMock.convertContext(ctx), + req + ); + expect(updatedPolicyConfig.inputs[0]!.config!.policy.value).toEqual({ + ...mockPolicy, + global_manifest_version: date, + }); + } else { + await expect(() => + callback(policyConfig, soClient, esClient, requestContextMock.convertContext(ctx), req) + ).rejects.toThrow(message); + } + } + ); + it('updates successfully when paid features are turned on', async () => { const mockPolicy = policyFactory(); mockPolicy.windows.popup.malware.message = 'paid feature'; diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts index c2775f3f4794a..ce6ff450a6869 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts @@ -23,6 +23,7 @@ import type { import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { InfoResponse } from '@elastic/elasticsearch/lib/api/types'; import { AppFeatureSecurityKey } from '@kbn/security-solution-features/keys'; +import { validateEndpointPackagePolicy } from './handlers/validate_endpoint_package_policy'; import { isPolicySetToEventCollectionOnly, ensureOnlyEventCollectionIsAllowed, @@ -102,6 +103,9 @@ export const getPackagePolicyCreateCallback = ( return newPackagePolicy; } + if (newPackagePolicy?.inputs) { + validateEndpointPackagePolicy(newPackagePolicy.inputs); + } // Optional endpoint integration configuration let endpointIntegrationConfig; @@ -205,6 +209,8 @@ export const getPackagePolicyUpdateCallback = ( logger ); + validateEndpointPackagePolicy(endpointIntegrationData.inputs); + notifyProtectionFeatureUsage( endpointIntegrationData, featureUsageService, diff --git a/x-pack/plugins/security_solution/server/fleet_integration/handlers/validate_endpoint_package_policy.ts b/x-pack/plugins/security_solution/server/fleet_integration/handlers/validate_endpoint_package_policy.ts new file mode 100644 index 0000000000000..11033f6cc6989 --- /dev/null +++ b/x-pack/plugins/security_solution/server/fleet_integration/handlers/validate_endpoint_package_policy.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment'; + +import type { NewPackagePolicyInput } from '@kbn/fleet-plugin/common'; + +export const validateEndpointPackagePolicy = (inputs: NewPackagePolicyInput[]) => { + const input = inputs.find((i) => i.type === 'endpoint'); + if (input?.config?.policy?.value?.global_manifest_version) { + const globalManifestVersion = input.config.policy.value.global_manifest_version; + + if (globalManifestVersion !== 'latest') { + const parsedDate = moment.utc(globalManifestVersion, 'YYYY-MM-DD', true); + if (!parsedDate.isValid()) { + throw createManifestVersionError( + 'Invalid date format. Use "latest" or "YYYY-MM-DD" format. UTC time.' + ); + } + + const maxAllowedDate = moment.utc().subtract(18, 'months'); + if (parsedDate.isBefore(maxAllowedDate)) { + throw createManifestVersionError( + 'Global manifest version is too far in the past. Use "latest" or a date within the last 18 months. UTC time.' + ); + } + if (parsedDate.isAfter(moment.utc())) { + throw createManifestVersionError( + 'Global manifest version cannot be in the future. UTC time.' + ); + } + } + } +}; + +const createManifestVersionError = ( + message: string +): Error & { statusCode?: number; apiPassThrough?: boolean } => { + const manifestVersionError: Error & { statusCode?: number; apiPassThrough?: boolean } = new Error( + message + ); + manifestVersionError.statusCode = 400; + manifestVersionError.apiPassThrough = true; + return manifestVersionError; +}; diff --git a/x-pack/plugins/security_solution/server/fleet_integration/handlers/validate_policy_against_license.ts b/x-pack/plugins/security_solution/server/fleet_integration/handlers/validate_policy_against_license.ts index 4b19654b93ad4..35e8fea91346e 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/handlers/validate_policy_against_license.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/handlers/validate_policy_against_license.ts @@ -18,8 +18,12 @@ export const validatePolicyAgainstLicense = ( if (!isEndpointPolicyValidForLicense(policyConfig, licenseService.getLicenseInformation())) { logger.warn('Incorrect license tier for paid policy fields'); // The `statusCode` below is used by Fleet API handler to ensure that the proper HTTP code is used in the API response - const licenseError: Error & { statusCode?: number } = new Error('Requires Platinum license'); + const licenseError: Error & { statusCode?: number; passThroughApi?: boolean } = new Error( + 'Requires Platinum license' + ); licenseError.statusCode = 403; + licenseError.passThroughApi = true; + throw licenseError; } }; diff --git a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.test.ts b/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.test.ts index 889b01b1ea6cd..ca941bcacce3a 100644 --- a/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.test.ts +++ b/x-pack/plugins/security_solution/server/lib/risk_engine/risk_engine_data_client.test.ts @@ -175,6 +175,7 @@ describe('RiskEngineDataClient', () => { "dynamic": "strict", "properties": Object { "@timestamp": Object { + "ignore_malformed": false, "type": "date", }, "host": Object { @@ -360,6 +361,7 @@ describe('RiskEngineDataClient', () => { dynamic: 'strict', properties: { '@timestamp': { + ignore_malformed: false, type: 'date', }, host: { diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 778ff52c2d692..2998854f484e4 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -17,11 +17,16 @@ import { Dataset } from '@kbn/rule-registry-plugin/server'; import type { ListPluginSetup } from '@kbn/lists-plugin/server'; import type { ILicense } from '@kbn/licensing-plugin/server'; +import { i18n } from '@kbn/i18n'; import { endpointPackagePoliciesStatsSearchStrategyProvider } from './search_strategy/endpoint_package_policies_stats'; import { turnOffPolicyProtectionsIfNotSupported } from './endpoint/migrations/turn_off_policy_protections'; import { endpointSearchStrategyProvider } from './search_strategy/endpoint'; import { getScheduleNotificationResponseActionsService } from './lib/detection_engine/rule_response_actions/schedule_notification_response_actions'; -import { siemGuideConfig, siemGuideId } from '../common/guided_onboarding/siem_guide_config'; +import { + siemGuideId, + getSiemGuideConfig, + defaultGuideTranslations, +} from '../common/guided_onboarding/siem_guide_config'; import { createEqlAlertType, createIndicatorMatchAlertType, @@ -389,6 +394,32 @@ export class Plugin implements ISecuritySolutionPlugin { ); plugins.data.search.registerSearchStrategy(ENDPOINT_SEARCH_STRATEGY, endpointSearchStrategy); + + /** + * Register a config for the security guide + */ + if (depsStart.cloudExperiments && i18n.getLocale() === 'en') { + try { + depsStart.cloudExperiments + .getVariation('security-solutions.guided-onboarding-content', defaultGuideTranslations) + .then((variation) => { + plugins.guidedOnboarding.registerGuideConfig( + siemGuideId, + getSiemGuideConfig(variation) + ); + }); + } catch { + plugins.guidedOnboarding.registerGuideConfig( + siemGuideId, + getSiemGuideConfig(defaultGuideTranslations) + ); + } + } else { + plugins.guidedOnboarding.registerGuideConfig( + siemGuideId, + getSiemGuideConfig(defaultGuideTranslations) + ); + } }); setIsElasticCloudDeployment(plugins.cloud.isCloudEnabled ?? false); @@ -409,11 +440,6 @@ export class Plugin implements ISecuritySolutionPlugin { featureUsageService.setup(plugins.licensing); - /** - * Register a config for the security guide - */ - plugins.guidedOnboarding.registerGuideConfig(siemGuideId, siemGuideConfig); - return { setAppFeaturesConfigurator: appFeaturesService.setAppFeaturesConfigurator.bind(appFeaturesService), diff --git a/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.test.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.test.ts index 0806b38628c9a..1d3e92592cb8e 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.test.ts @@ -91,8 +91,8 @@ describe('Endpoint package policies stats', () => { 'latest', '2020-01-01', 'latest', - moment().subtract(1, 'week').format('YYYY-MM-DD'), - moment().subtract(2, 'week').format('YYYY-MM-DD'), + moment.utc().subtract(1, 'week').format('YYYY-MM-DD'), + moment.utc().subtract(2, 'week').format('YYYY-MM-DD'), ]) ); const response = await requestEndpointPackagePoliciesStatsSearch( diff --git a/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.ts b/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.ts index ce7f172cac642..99b64cf1ed193 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/endpoint_package_policies_stats/index.ts @@ -42,7 +42,10 @@ export const requestEndpointPackagePoliciesStatsSearch = async ( }); const outdatedManifestsCount = rawResponse.items.reduce((acc, item) => { - const endpointInput = item.inputs[0]; + const endpointInput = item.inputs.find((input) => input.type === 'endpoint'); + if (!endpointInput) { + return acc; + } const manifestVersion = endpointInput.config?.policy?.value?.global_manifest_version; if (!manifestVersion) { return acc; @@ -50,7 +53,7 @@ export const requestEndpointPackagePoliciesStatsSearch = async ( if (manifestVersion === 'latest') { return acc; } - if (moment(manifestVersion, 'YYYY-MM-DD').isBefore(moment().subtract(1, 'month'))) { + if (moment.utc(manifestVersion, 'YYYY-MM-DD').isBefore(moment.utc().subtract(1, 'month'))) { return acc + 1; } diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/auditbeat.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/auditbeat.tsx deleted file mode 100644 index a8ee074b135dd..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/auditbeat.tsx +++ /dev/null @@ -1,29 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconAuditbeat: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g> - <g id="Group"> - <path id="Stroke 1" d="M15 1H17V31H15V1Z" fill="#00BFB3" /> - <path id="Stroke 3" d="M13 29V31H1V1H13V3H3V29H13Z" fill="#535766" /> - <path id="Stroke 5" d="M29 3H19V1H31V31H19V29H29V3Z" fill="#535766" /> - </g> - </g> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconAuditbeat; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/chart_arrow.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/chart_arrow.tsx new file mode 100644 index 0000000000000..a47515435fa86 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/chart_arrow.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 type { SVGProps } from 'react'; +import React from 'react'; +export const IconChartArrow: React.FC<SVGProps<SVGSVGElement>> = (props) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M31.4185 4.11481L20.4558 15.0775L12.5084 7.13003L1.61832 18.0201L0.204102 16.6059L12.5084 4.3016L20.4558 12.249L30.0043 2.7006L31.4185 4.11481Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M3.01855 31V22H5.01855V31H3.01855Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M19.0186 31V22H21.0186V31H19.0186Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M11.0186 31V15H13.0186V31H11.0186Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M27.0186 31V15H29.0186V31H27.0186Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M29.9998 4.05764L24.9883 3.99993L25.0113 2.00006L31.9998 2.08054V9H29.9998V4.05764Z" + fill="#535966" + /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconChartArrow; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/dashboard.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/dashboard.tsx new file mode 100644 index 0000000000000..5ca7002cfaba0 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/dashboard.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 type { SVGProps } from 'react'; +import React from 'react'; +export const IconDashboard: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <g clipPath="url(#clip0_4044_22930)"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M3 2C2.44828 2 2 2.44828 2 3V29C2 29.5517 2.44828 30 3 30H29C29.5517 30 30 29.5517 30 29V3C30 2.44828 29.5517 2 29 2H3ZM0 3C0 1.34372 1.34372 0 3 0H29C30.6563 0 32 1.34372 32 3V29C32 30.6563 30.6563 32 29 32H3C1.34372 32 0 30.6563 0 29V3Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M8 6H5V4H8V6Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M14 6H11V4H14V6Z" fill="#535966" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M11.3333 30V8H13.2V30H11.3333Z" + fill="#00BFB3" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M30 9.91304H2V8H30V9.91304Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M5 13H8V15H5V13Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M5 18H8V20H5V18Z" fill="#00BFB3" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M23.8277 15.1715C22.2663 13.6095 19.7337 13.6095 18.1723 15.1715C16.6095 16.7342 16.6097 19.2668 18.1716 20.8277L18.1723 20.8285C19.7337 22.3905 22.2663 22.3905 23.8277 20.8285L23.8284 20.8277C25.3903 19.2668 25.3905 16.7342 23.8277 15.1715ZM25.2422 13.7576C22.8997 11.4141 19.1003 11.4141 16.7578 13.7576C14.4141 16.1011 14.4141 19.9001 16.7578 22.2424C19.1003 24.5859 22.8997 24.5859 25.2422 22.2424C27.5859 19.9001 27.5859 16.1011 25.2422 13.7576Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M27.6572 26.0708L24.8282 23.2428L26.2422 21.8284L29.0712 24.6564L27.6572 26.0708Z" + fill="#535966" + /> + </g> + <defs> + <clipPath id="clip0_4044_22930"> + <rect width="32" height="32" fill="white" /> + </clipPath> + </defs> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconDashboard; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/data_connector.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/data_connector.tsx deleted file mode 100644 index 26a4ca9ea24c9..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/data_connector.tsx +++ /dev/null @@ -1,36 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconDataConnector: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g> - <path - id="Union" - d="M13.4119 25.6592L6.34092 18.5879L8.57159 17.9904L14.0097 23.4285L21.4382 21.438L23.4287 14.0094L17.9907 8.57145L18.5884 6.34074L25.6594 13.4117L23.3701 21.9555L28.32 26.9053L28.0212 28.0206L26.9057 28.3195L21.956 23.3698L13.4119 25.6592Z" - fill="#535766" - /> - <path - id="Union_2" - fillRule="evenodd" - clipRule="evenodd" - d="M19.5352 19.5357L14.7056 20.8298L11.17 17.2942L12.1653 13.5799L3.68008 5.0947L3.97898 3.9792L5.0942 3.68038L13.5796 12.1657L17.2938 11.1705L20.8293 14.706L19.5352 19.5357ZM18.5986 15.3038L17.9022 17.9027L15.3033 18.5991L13.4008 16.6965L14.0971 14.0976L16.696 13.4012L18.5986 15.3038Z" - fill="#00BFB3" - /> - </g> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconDataConnector; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/data_view.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/data_view.tsx new file mode 100644 index 0000000000000..85461e05bd66d --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/data_view.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const IconDataView: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M0.470703 11.6253H7.72125V30.5882H0.470703V11.6253ZM2.14391 13.2985V28.915H6.04805V13.2985H2.14391Z" + fill="#535766" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M9.95221 0.470581H17.2028V30.5882H9.95221V0.470581ZM11.6254 2.14378V28.915H15.5295V2.14378H11.6254Z" + fill="#535766" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M21.1069 8.27887V15.2505H19.4337V6.60566H26.6843V13.2231H25.0111V8.27887H21.1069Z" + fill="#535766" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M19.4336 22.2222C19.4336 19.1419 21.9307 16.6449 25.0109 16.6449C28.0912 16.6449 30.5883 19.1419 30.5883 22.2222C30.5883 25.3025 28.0912 27.7996 25.0109 27.7996C21.9307 27.7996 19.4336 25.3025 19.4336 22.2222ZM25.0109 18.3181C22.8547 18.3181 21.1068 20.066 21.1068 22.2222C21.1068 24.3784 22.8547 26.1264 25.0109 26.1264C27.1671 26.1264 28.9151 24.3784 28.9151 22.2222C28.9151 20.066 27.1671 18.3181 25.0109 18.3181Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M30.1504 29.1025L27.5016 26.4537L28.6847 25.2706L31.3335 27.9193L30.1504 29.1025Z" + fill="#00BFB3" + /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconDataView; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/dev_tools.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/dev_tools.tsx deleted file mode 100644 index 49f2c129e4a79..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/dev_tools.tsx +++ /dev/null @@ -1,45 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconDevTools: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g clipPath="url(#clip0_2634_421128)"> - <g id="Group"> - <path - id="Fill 1" - fillRule="evenodd" - clipRule="evenodd" - d="M21 28H19V19.508L19.6 19.246C22.88 17.812 25 14.575 25 11C25 7.963 23.471 5.171 21 3.521V11H11V3.521C8.529 5.171 7 7.963 7 11C7 14.575 9.12 17.812 12.4 19.246L13 19.508V28H11V20.795C7.334 18.924 5 15.148 5 11C5 6.63 7.591 2.674 11.6 0.921998L13 0.309998V9H19V0.309998L20.4 0.921998C24.409 2.674 27 6.63 27 11C27 15.148 24.666 18.924 21 20.795V28Z" - fill="#535766" - /> - <path - id="Fill 3" - fillRule="evenodd" - clipRule="evenodd" - d="M11 32H21V30H11V32Z" - fill="#00BFB3" - /> - </g> - </g> - <defs> - <clipPath id="clip0_2634_421128"> - <rect width="32" height="32" fill="white" /> - </clipPath> - </defs> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconDevTools; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/filebeat.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/filebeat.tsx new file mode 100644 index 0000000000000..0859cdb3329ab --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/filebeat.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const IconFilebeat: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M5 2C4.44828 2 4 2.44828 4 3V29C4 29.5517 4.44828 30 5 30H27C27.5517 30 28 29.5517 28 29V9.41421L20.5858 2H5ZM2 3C2 1.34372 3.34372 0 5 0H21.4142L30 8.58579V29C30 30.6563 28.6563 32 27 32H5C3.34372 32 2 30.6563 2 29V3Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M20 1H22V8H29V10H20V1Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M24 20H8V18H24V20Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M17 15H8V13H17V15Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M24 25H8V23H24V25Z" fill="#00BFB3" /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconFilebeat; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/filebeat_chart.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/filebeat_chart.tsx new file mode 100644 index 0000000000000..df3243ba8d043 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/filebeat_chart.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const IconFilebeatChart: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M5 2C4.44828 2 4 2.44828 4 3V29C4 29.5517 4.44828 30 5 30H27C27.5517 30 28 29.5517 28 29V9.41421L20.5858 2H5ZM2 3C2 1.34372 3.34372 0 5 0H21.4142L30 8.58579V29C30 30.6563 28.6563 32 27 32H5C3.34372 32 2 30.6563 2 29V3Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M20 1H22V8H29V10H20V1Z" fill="#535966" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M16.5 10L16.5 26H14.5L14.5 10L16.5 10Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M11.5 16L11.5 26H9.5L9.5 16H11.5Z" + fill="#00BFB3" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M21.5 20V26H19.5V20H21.5Z" fill="#00BFB3" /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconFilebeatChart; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/graph.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/graph.tsx deleted file mode 100644 index 9223de9461975..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/graph.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { SVGProps } from 'react'; -import React from 'react'; -export const IconGraph: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <path - fillRule="evenodd" - clipRule="evenodd" - d="M24 14C22.897 14 22 14.897 22 16C22 17.103 22.897 18 24 18C25.103 18 26 17.103 26 16C26 14.897 25.103 14 24 14ZM24 20C21.794 20 20 18.206 20 16C20 13.794 21.794 12 24 12C26.206 12 28 13.794 28 16C28 18.206 26.206 20 24 20Z" - fill="#00BFB3" - /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M15.8105 2.37989C15.1655 2.37989 14.5335 2.69089 14.1475 3.26389C13.5335 4.17889 13.7775 5.42389 14.6925 6.03889C15.1375 6.33789 15.6705 6.44489 16.1935 6.34189C16.7165 6.23889 17.1695 5.93889 17.4675 5.49489C17.7655 5.05189 17.8735 4.51889 17.7705 3.99389C17.6675 3.46989 17.3675 3.01789 16.9235 2.71989C16.5815 2.48989 16.1945 2.37989 15.8105 2.37989ZM15.7995 8.38089C15.0125 8.38089 14.2445 8.14789 13.5775 7.69889C11.7475 6.46989 11.2575 3.97989 12.4875 2.14889C13.7175 0.317889 16.2075 -0.172111 18.0395 1.05989C18.9255 1.65489 19.5275 2.56089 19.7335 3.60889C19.9385 4.65789 19.7235 5.72389 19.1275 6.60989C18.5325 7.49689 17.6265 8.09889 16.5785 8.30489C16.3185 8.35589 16.0585 8.38089 15.7995 8.38089Z" - fill="#00BFB3" - /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M15.8037 25.6201C15.4107 25.6201 15.0267 25.7361 14.6927 25.9611C13.7777 26.5761 13.5327 27.8211 14.1477 28.7361C14.7627 29.6511 16.0097 29.8941 16.9237 29.2801C17.3667 28.9821 17.6677 28.5301 17.7707 28.0061C17.8727 27.4811 17.7657 26.9481 17.4677 26.5051C17.1697 26.0611 16.7167 25.7611 16.1937 25.6581C16.0637 25.6331 15.9327 25.6201 15.8037 25.6201ZM15.8147 31.6191C14.5257 31.6191 13.2587 30.9991 12.4877 29.8511C11.2577 28.0201 11.7467 25.5301 13.5767 24.3011C14.4627 23.7051 15.5277 23.4891 16.5777 23.6951C17.6267 23.9011 18.5327 24.5031 19.1277 25.3901C19.7237 26.2761 19.9387 27.3421 19.7337 28.3911C19.5277 29.4391 18.9257 30.3451 18.0387 30.9401C17.3567 31.3991 16.5807 31.6191 15.8147 31.6191Z" - fill="#00BFB3" - /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M6 16C6 14.897 6.897 14 8 14C9.103 14 10 14.897 10 16C10 17.103 9.103 18 8 18C6.897 18 6 17.103 6 16ZM18 17V15H11.858C11.697 14.38 11.393 13.823 10.98 13.357L13.292 9.917L11.632 8.802L9.32 12.241C8.905 12.095 8.465 12 8 12C5.794 12 4 13.794 4 16C4 18.206 5.794 20 8 20C8.465 20 8.905 19.905 9.32 19.759L11.632 23.198L13.292 22.083L10.98 18.643C11.393 18.177 11.697 17.62 11.858 17H18Z" - fill="#535766" - /> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconGraph; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/infra.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/infra.tsx new file mode 100644 index 0000000000000..5e4e1070d5f9e --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/infra.tsx @@ -0,0 +1,44 @@ +/* + * 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 { SVGProps } from 'react'; +import React from 'react'; +export const IconInfra: React.FC<SVGProps<SVGSVGElement>> = (props) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <g clipPath="url(#clip0_4044_22869)"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M9 14H32V32H9V14ZM11 16V30H30V16H11Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M31 24H10V22H31V24Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M17 20H13V18H17V20Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M17 28H13V26H17V28Z" fill="#00BFB3" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M5.62311 7.96014C6.26408 3.46188 10.1221 0 14.8 0C19.4791 0 23.3361 3.46211 23.9778 7.96028C25.9375 8.72369 27.5578 10.1658 28.5476 11.9999H26.1676C25.3118 10.9 24.1262 10.0685 22.7605 9.65388L22.1015 9.45383L22.0534 8.76683C21.7887 4.98508 18.6462 2 14.8 2C10.9547 2 7.8114 4.98516 7.54758 8.7666L7.49962 9.45401L6.84019 9.65397C4.03728 10.5039 2 13.1044 2 16.18C2 19.3164 4.11694 21.9582 7 22.7545V24.812C3.00198 23.9734 0 20.4274 0 16.18C0 12.435 2.33352 9.24079 5.62311 7.96014ZM27.2444 13.9999C27.275 14.0908 27.3038 14.1825 27.3307 14.275L28.2775 13.9999H27.2444Z" + fill="#535966" + /> + </g> + <defs> + <clipPath id="clip0_4044_22869"> + <rect width="32" height="32" fill="white" /> + </clipPath> + </defs> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconInfra; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/intuitive.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/intuitive.tsx new file mode 100644 index 0000000000000..cacf9dc7be11f --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/intuitive.tsx @@ -0,0 +1,64 @@ +/* + * 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 { SVGProps } from 'react'; +import React from 'react'; +export const IconIntuitive: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M13 10C12.4477 10 12 10.4477 12 11V21H10V11C10 9.34315 11.3431 8 13 8C14.6569 8 16 9.34315 16 11V21H14V11C14 10.4477 13.5523 10 13 10Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M17 16C16.4477 16 16 16.4477 16 17V21H14V17C14 15.3431 15.3431 14 17 14C18.6569 14 20 15.3431 20 17V21H18V17C18 16.4477 17.5523 16 17 16Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M21 18C20.4477 18 20 18.4477 20 19V21H18V19C18 17.3431 19.3431 16 21 16C22.6569 16 24 17.3431 24 19V21H22V19C22 18.4477 21.5523 18 21 18Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M25 19C24.4477 19 24 19.4477 24 20V22.3607H22V20C22 18.3431 23.3431 17 25 17C26.6569 17 28 18.3431 28 20V23.8524C28 24.6992 27.7849 25.5321 27.375 26.2731L24.8909 30.7628C24.6813 31.1415 24.5714 31.5672 24.5714 32H22.5714C22.5714 31.2285 22.7674 30.4696 23.1409 29.7946L25.625 25.3048C25.871 24.8603 26 24.3605 26 23.8524V20C26 19.4477 25.5523 19 25 19Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M8.90532 18.7152L10.8096 17.2146L12.0475 18.7854L10.1432 20.2861C9.4213 20.8549 9 21.7233 9 22.6424V24.6827C9 25.3728 9.23793 26.0418 9.67369 26.577L12.1551 29.6243C12.7016 30.2954 13 31.1345 13 32H11C11 31.5946 10.8602 31.2015 10.6042 30.8871L8.12282 27.8398C7.39655 26.9479 7 25.8329 7 24.6827V22.6424C7 21.1106 7.70217 19.6633 8.90532 18.7152Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M12.5 0C6.70101 0 2 4.70101 2 10.5C2 14.218 3.93245 17.4847 6.84774 19.3504C7.17452 18.8632 7.58858 18.4312 8.07723 18.0791L8.321 17.9035C5.74124 16.4442 4 13.6754 4 10.5C4 5.80558 7.80558 2 12.5 2C17.1944 2 21 5.80558 21 10.5C21 11.831 20.6941 13.0905 20.1487 14.2121C20.3579 14.454 20.5344 14.7248 20.6716 15.0178C20.7794 15.006 20.889 15 21 15C21.3209 15 21.6301 15.0504 21.9199 15.1437C22.6114 13.7436 23 12.1672 23 10.5C23 4.70101 18.299 0 12.5 0Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M6 10.5C6 6.91015 8.91015 4 12.5 4C16.0899 4 19 6.91015 19 10.5C19 11.4358 18.8022 12.3255 18.4462 13.1294C18.1452 13.0451 17.8279 13 17.5 13C17.3302 13 17.1633 13.0121 17 13.0354V11C17 10.9185 16.9976 10.8376 16.9928 10.7574C16.9976 10.6722 17 10.5864 17 10.5C17 8.01472 14.9853 6 12.5 6C10.0147 6 8 8.01472 8 10.5C8 11.5716 8.3746 12.5558 9 13.3287V15.9782C7.19584 14.8231 6 12.8012 6 10.5Z" + fill="#00BFB3" + /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconIntuitive; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/jobs.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/jobs.tsx new file mode 100644 index 0000000000000..a6eb6c20d446a --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/jobs.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const IconJobs: React.FC<SVGProps<SVGSVGElement>> = (props) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <g clipPath="url(#clip0_4044_22880)"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M25.9995 17C24.8948 17 23.9995 17.8953 23.9995 19C23.9995 20.1047 24.8948 21 25.9995 21C27.1043 21 27.9995 20.1047 27.9995 19C27.9995 17.8953 27.1043 17 25.9995 17ZM21.9995 19C21.9995 16.7907 23.7903 15 25.9995 15C28.2088 15 29.9995 16.7907 29.9995 19C29.9995 21.2093 28.2088 23 25.9995 23C23.7903 23 21.9995 21.2093 21.9995 19Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M29.9995 27C29.9995 24.7903 28.2093 23 25.9995 23V21C29.3138 21 31.9995 23.6857 31.9995 27V32H29.9995V27Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M22.4278 25.1954C22.1541 25.7366 21.9995 26.3483 21.9995 27V32H19.9995V27C19.9995 26.0277 20.231 25.1074 20.6432 24.2926L22.4278 25.1954Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M19.9504 19.0408C20.8348 20.2317 22.2483 21 23.8425 21L25.9995 21V23L23.8425 23C21.5888 23 19.5903 21.9103 18.3447 20.2332L19.9504 19.0408Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M0 0H22V11H20V2H2V20H14V22H0V0Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M15 8H5V6H15V8Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M12 12H5V10H12V12Z" fill="#535966" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M15.8575 12.4855L18.8575 17.4855L17.1425 18.5145L14.1425 13.5145L15.8575 12.4855Z" + fill="#535966" + /> + </g> + <defs> + <clipPath id="clip0_4044_22880"> + <rect width="32" height="32" fill="white" /> + </clipPath> + </defs> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconJobs; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/keyword.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/keyword.tsx new file mode 100644 index 0000000000000..f25d5c4d9b3f8 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/keyword.tsx @@ -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 type { SVGProps } from 'react'; +import React from 'react'; +export const IconKeyword: React.FC<SVGProps<SVGSVGElement>> = (props) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M16 1C7.71573 1 1 7.71573 1 16C1 24.2843 7.71573 31 16 31C24.2843 31 31 24.2843 31 16C31 7.71573 24.2843 1 16 1ZM15 3.03789C8.61759 3.52341 3.52341 8.61759 3.03789 15H6V17H3.03789C3.52341 23.3824 8.61759 28.4766 15 28.9621V26H17V28.9621C23.3824 28.4766 28.4766 23.3824 28.9621 17H26V15H28.9621C28.4766 8.61759 23.3824 3.52341 17 3.03789V6H15V3.03789Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M15.3408 9H16.6596L22.6596 23H20.4837L19.1979 20L12.8025 20L11.5168 23H9.34082L15.3408 9ZM16.0002 12.5386L18.3408 18L13.6596 18L16.0002 12.5386Z" + fill="#00BFB3" + /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconKeyword; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/logging.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/logging.tsx deleted file mode 100644 index baab149c29412..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/logging.tsx +++ /dev/null @@ -1,31 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconLogging: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <path fillRule="evenodd" clipRule="evenodd" d="M9 20H21V18H9V20Z" fill="#00BFB3" /> - <path fillRule="evenodd" clipRule="evenodd" d="M9 15H21V13H9V15Z" fill="#00BFB3" /> - <path fillRule="evenodd" clipRule="evenodd" d="M9 10H21V8H9V10Z" fill="#00BFB3" /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M30 6H26V5C26 3.897 26.897 3 28 3C29.103 3 30 3.897 30 5V6ZM22 29C20.897 29 20 28.103 20 27V24H6V5C6 3.897 6.897 3 8 3H24.556C24.212 3.591 24 4.269 24 5V27C24 28.103 23.103 29 22 29ZM4 29C2.897 29 2 28.103 2 27V26H18V27C18 27.728 18.195 28.411 18.537 29H4ZM28 1H8C5.794 1 4 2.794 4 5V24H0V27C0 29.206 1.794 31 4 31H22C24.206 31 26 29.206 26 27V8H32V5C32 2.794 30.206 1 28 1Z" - fill="#535766" - /> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconLogging; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/manager.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/manager.tsx new file mode 100644 index 0000000000000..e5646c378b7a6 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/manager.tsx @@ -0,0 +1,61 @@ +/* + * 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 { SVGProps } from 'react'; +import React from 'react'; +export const IconManager: React.FC<SVGProps<SVGSVGElement>> = (props) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <g clipPath="url(#clip0_4044_22953)"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M0 24H8V32H0V24ZM2 26V30H6V26H2Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M24 24H32V32H24V24ZM26 26V30H30V26H26Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M12 24H20V32H12V24ZM14 26V30H18V26H14Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M4 17H28V22H26V19H6V22H4V17Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M17 14V22H15V14H17Z" fill="#00BFB3" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M10 12.1698C10 8.79382 12.6553 6 16 6C19.3447 6 22 8.79382 22 12.1698V13H20V12.1698C20 9.83501 18.1778 8 16 8C13.8222 8 12 9.83501 12 12.1698V13H10V12.1698Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M16 2C14.8955 2 14 2.8955 14 4C14 5.1045 14.8955 6 16 6C17.1045 6 18 5.1045 18 4C18 2.8955 17.1045 2 16 2ZM12 4C12 1.79093 13.7909 0 16 0C18.2091 0 20 1.79093 20 4C20 6.20907 18.2091 8 16 8C13.7909 8 12 6.20907 12 4Z" + fill="#535966" + /> + </g> + <defs> + <clipPath id="clip0_4044_22953"> + <rect width="32" height="32" fill="white" /> + </clipPath> + </defs> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconManager; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/marketing.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/marketing.tsx new file mode 100644 index 0000000000000..6161e492b0edb --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/marketing.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const IconMarketing: React.FC<SVGProps<SVGSVGElement>> = (props) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <g clipPath="url(#clip0_4246_67063)"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M26 0.408508V28.581L10.014 21H6.44576C2.88586 21 0 18.1141 0 14.5542C0 10.9943 2.88586 8.10848 6.44576 8.10848H10.0109L26 0.408508ZM24 3.59149L10.4674 10.1085H6.44576C3.99043 10.1085 2 12.0989 2 14.5542C2 17.0096 3.99043 19 6.44576 19H10.4642L24 25.419V3.59149Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M8.3214 30L5.9747 19.7763L4.02539 20.2237L6.72846 32H15.3155L14.0842 27.5653L12.2335 26.5106L10.8668 19.8005L8.90704 20.1996L10.4548 27.799L12.3777 28.8948L12.6845 30H8.3214Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M8 17V12H10V17H8Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M18 21V8H20V21H18Z" fill="#00BFB3" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M28 19.8922C30.3504 19.3757 32 17.0722 32 14.5C32 11.9278 30.3504 9.62432 28 9.10779V11.2044C29.1207 11.6726 30 12.9063 30 14.5C30 16.0937 29.1207 17.3274 28 17.7956V19.8922Z" + fill="#00BFB3" + /> + </g> + <defs> + <clipPath id="clip0_4246_67063"> + <rect width="32" height="32" fill="white" /> + </clipPath> + </defs> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconMarketing; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/product_features_alerting.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/product_features_alerting.tsx deleted file mode 100644 index f856b7a7494f4..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/product_features_alerting.tsx +++ /dev/null @@ -1,59 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconProductFeaturesAlerting: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g clipPath="url(#clip0_4_11)"> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M8.2632 22.5957C6.1692 20.2217 5.0152 17.1687 5.0152 13.9997C5.0152 10.8337 6.1672 7.7827 8.2582 5.4097L9.7592 6.7327C7.9902 8.7407 7.0152 11.3217 7.0152 13.9997C7.0152 16.6817 7.9912 19.2647 9.7632 21.2737L8.2632 22.5957Z" - fill="#535766" - /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M4.8604 26.8652C1.7264 23.3102 0.000396729 18.7412 0.000396729 13.9982C0.000396729 9.2592 1.7234 4.6922 4.8524 1.1402L6.3774 2.4842C3.5744 5.6642 2.0314 9.7532 2.0314 13.9982C2.0314 18.2462 3.5774 22.3392 6.3834 25.5212L4.8604 26.8652Z" - fill="#535766" - /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M23.7681 22.5957L22.2681 21.2737C24.0401 19.2647 25.0161 16.6817 25.0161 13.9997C25.0161 11.3217 24.0411 8.7407 22.2721 6.7327L23.7731 5.4097C25.8641 7.7827 27.0161 10.8337 27.0161 13.9997C27.0161 17.1687 25.8621 20.2217 23.7681 22.5957Z" - fill="#535766" - /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M27.1709 26.8652L25.6479 25.5212C28.4539 22.3392 29.9999 18.2462 29.9999 13.9982C29.9999 9.7532 28.4569 5.6642 25.6539 2.4842L27.1789 1.1402C30.3079 4.6922 32.0309 9.2592 32.0309 13.9982C32.0309 18.7412 30.3049 23.3102 27.1709 26.8652Z" - fill="#535766" - /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M16.0156 17C14.3616 17 13.0156 15.654 13.0156 14C13.0156 12.346 14.3616 11 16.0156 11C17.6696 11 19.0156 12.346 19.0156 14C19.0156 15.654 17.6696 17 16.0156 17ZM21.0156 14C21.0156 11.243 18.7726 9 16.0156 9C13.2586 9 11.0156 11.243 11.0156 14C11.0156 16.414 12.7366 18.435 15.0156 18.898V30H17.0156V18.898C19.2946 18.435 21.0156 16.414 21.0156 14Z" - fill="#00BFB3" - /> - </g> - <defs> - <clipPath id="clip0_4_11"> - <rect width="32" height="32" fill="white" /> - </clipPath> - </defs> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconProductFeaturesAlerting; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/rapid_bar_graph.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/rapid_bar_graph.tsx new file mode 100644 index 0000000000000..3303b13e8183e --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/rapid_bar_graph.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const IconRapidBarGraph: React.FC<SVGProps<SVGSVGElement>> = (props) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + fillRule="evenodd" + clipRule="evenodd" + d="M3.5 2.5V26.5C3.5 27.6044 4.3953 28.5 5.5 28.5H29.5V30H5.5C3.5667 30 2 28.4326 2 26.5V2.5H3.5Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M8 25.5V18.5H9.5V25.5H8Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M14 25.5V12H15.5V25.5H14Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M20 25.5V16.5H21.5V25.5H20Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M26 25.5V19H27.5V25.5H26Z" fill="#535966" /> + <path fillRule="evenodd" clipRule="evenodd" d="M8 16.4974V12H9.5V16.4974H8Z" fill="#00BFB3" /> + <path fillRule="evenodd" clipRule="evenodd" d="M14 9.5V5H15.5V9.5H14Z" fill="#00BFB3" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M20 13.9827V8.5H21.5V13.9827H20Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M26 16.4827V13H27.5V16.4827H26Z" + fill="#00BFB3" + /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconRapidBarGraph; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/replication.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/replication.tsx new file mode 100644 index 0000000000000..18b4cf73d2adf --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/replication.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 type { SVGProps } from 'react'; +import React from 'react'; +export const IconReplication: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <g clipPath="url(#clip0_4044_23007)"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M0 0H14V10.0035L8.70081 16H0V0ZM2 2V14H7.79919L12 9.24646V2H2Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M6 8H12V10H8V14H6V8Z" fill="#535966" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M18 16H32V26.0035L26.7008 32H18V16ZM20 18V30H25.7992L30 25.2465V18H20Z" + fill="#535966" + /> + <path fillRule="evenodd" clipRule="evenodd" d="M24 24H30V26H26V30H24V24Z" fill="#535966" /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M14 29C7.92465 29 3 24.0742 3 18H5C5 22.9698 9.02935 27 14 27H16V29H14Z" + fill="#00BFB3" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M18 5H16V3H18C24.0753 3 29 7.92578 29 14H27C27 9.03022 22.9706 5 18 5Z" + fill="#00BFB3" + /> + </g> + <defs> + <clipPath id="clip0_4044_23007"> + <rect width="32" height="32" fill="white" /> + </clipPath> + </defs> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconReplication; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/reporting.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/reporting.tsx new file mode 100644 index 0000000000000..ba783401ef7e5 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/reporting.tsx @@ -0,0 +1,37 @@ +/* + * 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 { SVGProps } from 'react'; +import React from 'react'; +export const IconReporting: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + id="Stroke 1" + d="M20.833 7V5H21C22.6563 5 24 6.34372 24 8V28C24 29.6563 22.6563 31 21 31H3C1.34372 31 0 29.6563 0 28V8C0 6.34372 1.34372 5 3 5H3.167V7H3C2.44828 7 2 7.44828 2 8V28C2 28.5517 2.44828 29 3 29H21C21.5517 29 22 28.5517 22 28V8C22 7.44828 21.5517 7 21 7H20.833Z" + fill="#535766" + /> + <path + id="Stroke 3" + fillRule="evenodd" + clipRule="evenodd" + d="M19 9V3H15.874C15.4299 1.27477 13.8638 0 12 0C10.1362 0 8.57006 1.27477 8.12602 3H5V9H19ZM14 5H17V7H7V5H10V4C10 2.89543 10.8954 2 12 2C13.1046 2 14 2.89543 14 4V5Z" + fill="#535766" + /> + <path id="Stroke 5" d="M6 15V13H18V15H6Z" fill="#00BFB3" /> + <path id="Stroke 7" d="M6 20V18H18V20H6Z" fill="#00BFB3" /> + <path id="Stroke 9" d="M6 25V23H18V25H6Z" fill="#00BFB3" /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconReporting; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/searchable_snapshots.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/searchable_snapshots.tsx deleted file mode 100644 index 9b199309fdee9..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/searchable_snapshots.tsx +++ /dev/null @@ -1,73 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconSearchableSnapshots: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g> - <path - id="Ellipse 57 (Stroke)" - fillRule="evenodd" - clipRule="evenodd" - d="M5.04205 4C5.09852 4.0623 5.21554 4.16719 5.45185 4.30687C5.94037 4.59561 6.71383 4.89032 7.75725 5.15118C9.82872 5.66905 12.7434 6 16 6C19.2566 6 22.1713 5.66905 24.2427 5.15118C25.2862 4.89032 26.0596 4.59561 26.5482 4.30687C26.7845 4.1672 26.9015 4.06229 26.9579 4C26.9015 3.9377 26.7845 3.8328 26.5482 3.69313C26.0596 3.40439 25.2862 3.10968 24.2427 2.84882C22.1713 2.33095 19.2566 2 16 2C12.7434 2 9.82872 2.33095 7.75725 2.84882C6.71383 3.10968 5.94037 3.40439 5.45185 3.69313C5.21554 3.83281 5.09852 3.9377 5.04205 4ZM7.27218 0.908537C9.54386 0.340618 12.6292 0 16 0C19.3708 0 22.4561 0.340618 24.7278 0.908537C25.856 1.19057 26.8399 1.54231 27.5658 1.9714C28.2248 2.36091 29 3.01396 29 4C29 4.98604 28.2248 5.63909 27.5658 6.0286C26.8399 6.45769 25.856 6.80943 24.7278 7.09146C22.4561 7.65938 19.3708 8 16 8C12.6292 8 9.54386 7.65938 7.27218 7.09146C6.14404 6.80943 5.16014 6.45769 4.43419 6.0286C3.77518 5.63909 3 4.98604 3 4C3 3.01396 3.77518 2.36091 4.43419 1.9714C5.16014 1.54231 6.14404 1.19057 7.27218 0.908537Z" - fill="#00BFB3" - /> - <path - id="Rectangle (Stroke)" - fillRule="evenodd" - clipRule="evenodd" - d="M12.4563 12C12.1632 12 11.8848 12.1286 11.6948 12.3518L9.81185 14.5641C9.24186 15.2337 8.40675 15.6196 7.52736 15.6196H4C3.44772 15.6196 3 16.0673 3 16.6196V26C3 26.5523 3.44772 27 4 27H7.85455V29H4C2.34315 29 1 27.6569 1 26V16.6196C1 14.9627 2.34315 13.6196 4 13.6196H7.52736C7.82049 13.6196 8.09886 13.491 8.28885 13.2677L10.1718 11.0555C10.7418 10.3858 11.577 10 12.4563 10H19.3418C20.2212 10 21.0563 10.3858 21.6263 11.0555L23.5093 13.2677C23.6993 13.491 23.9776 13.6196 24.2708 13.6196H28C29.6569 13.6196 31 14.9627 31 16.6196V26C31 27.6569 29.6569 29 28 29H24.6545V27H28C28.5523 27 29 26.5523 29 26V16.6196C29 16.0673 28.5523 15.6196 28 15.6196H24.2708C23.3914 15.6196 22.5563 15.2337 21.9863 14.5641L20.1033 12.3518C19.9133 12.1286 19.6349 12 19.3418 12H12.4563Z" - fill="#535766" - /> - <path - id="Stroke 14 (Stroke)" - fillRule="evenodd" - clipRule="evenodd" - d="M12.4643 26.5353C10.5119 24.5824 10.5119 21.4171 12.4643 19.4647C14.4172 17.5118 17.5824 17.5118 19.5353 19.4647C21.4882 21.4171 21.4882 24.5824 19.5353 26.5353C17.5824 28.4882 14.4172 28.4882 12.4643 26.5353ZM20.9495 18.0505C20.9495 18.0504 20.9494 18.0504 20.9493 18.0503L20.9495 18.0505ZM20.9495 18.0505C23.6837 20.7841 23.6833 25.2157 20.9495 27.9495C18.2156 30.6835 13.784 30.6835 11.05 27.9495L11.0498 27.9493C8.31683 25.2155 8.31654 20.784 11.05 18.0505C13.7839 15.3166 18.2154 15.3165 20.9493 18.0503" - fill="#535766" - /> - <path - id="Stroke 18 (Stroke)" - fillRule="evenodd" - clipRule="evenodd" - d="M13.8075 20.8077C14.8845 19.7308 16.6302 19.7308 17.7071 20.8077L16.2929 22.2219C15.997 21.926 15.5177 21.926 15.2218 22.2219C14.9261 22.5176 14.926 22.997 15.2219 23.293L13.8074 24.707C12.7309 23.6301 12.7308 21.8845 13.8075 20.8077Z" - fill="#00BFB3" - /> - <path - id="Stroke 16 (Stroke)" - fillRule="evenodd" - clipRule="evenodd" - d="M23.293 31.7071L19.293 27.7071L20.7072 26.2929L24.7072 30.2929L23.293 31.7071Z" - fill="#535766" - /> - <path - id="Stroke 2 (Stroke)" - fillRule="evenodd" - clipRule="evenodd" - d="M27 12V4H29V12H27Z" - fill="#00BFB3" - /> - <path - id="Stroke 17 (Stroke)" - fillRule="evenodd" - clipRule="evenodd" - d="M3 12V4H5V12H3Z" - fill="#00BFB3" - /> - </g> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconSearchableSnapshots; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/security_shield.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/security_shield.tsx deleted file mode 100644 index 355718d77d1a0..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/security_shield.tsx +++ /dev/null @@ -1,42 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconSecurityShield: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - xmlns="http://www.w3.org/2000/svg" - width={16} - height={16} - fill="none" - viewBox="0 0 32 32" - {...props} - > - <path - fillRule="evenodd" - clipRule="evenodd" - d="M4 6.81635V12.0713C4 19.9353 8.697 26.8694 16 29.8403C23.303 26.8694 28 19.9353 28 12.0713V6.81635L16 2.20135L4 6.81635ZM16 31.9874L15.641 31.8493C7.354 28.6623 2 20.8983 2 12.0713V5.44335L16 0.0583496L30 5.44335V12.0713C30 20.8983 24.646 28.6623 16.359 31.8493L16 31.9874Z" - fill="#535766" - /> - <path fillRule="evenodd" clipRule="evenodd" d="M11 23H13V18H11V23Z" fill="#00BFB3" /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M12 14C11.448 14 11 13.552 11 13C11 12.448 11.448 12 12 12C12.552 12 13 12.448 13 13C13 13.552 12.552 14 12 14ZM13 10.185V7H11V10.185C9.839 10.599 9 11.698 9 13C9 14.654 10.346 16 12 16C13.654 16 15 14.654 15 13C15 11.698 14.161 10.599 13 10.185Z" - fill="#00BFB3" - /> - <path fillRule="evenodd" clipRule="evenodd" d="M19 12H21V7H19V12Z" fill="#00BFB3" /> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M20 18C19.448 18 19 17.552 19 17C19 16.448 19.448 16 20 16C20.552 16 21 16.448 21 17C21 17.552 20.552 18 20 18ZM23 17C23 15.346 21.654 14 20 14C18.346 14 17 15.346 17 17C17 18.302 17.839 19.401 19 19.815V23H21V19.815C22.161 19.401 23 18.302 23 17Z" - fill="#00BFB3" - /> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconSecurityShield; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/settings.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/settings.tsx new file mode 100644 index 0000000000000..dbf362deea340 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/settings.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SVGProps } from 'react'; +import React from 'react'; +export const IconSettings: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <g clipPath="url(#clip0_4044_22923)"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M26.8384 20.479C27.1552 19.7077 27.9008 19.2 28.736 19.2H32V12.8H28.736C27.9008 12.8 27.1552 12.2923 26.8384 11.5211C26.8352 11.5125 26.832 11.504 26.8277 11.4955C26.5109 10.7264 26.6795 9.84533 27.2683 9.2576L29.5765 6.94933L25.0507 2.42347L22.7424 4.73173C22.1547 5.31947 21.2736 5.48907 20.5045 5.17227C20.5008 5.17088 20.4974 5.1693 20.4938 5.16769C20.4891 5.16558 20.4844 5.16342 20.4789 5.1616C19.7077 4.8448 19.2 4.0992 19.2 3.26507V0H12.8V3.26507C12.8 4.0992 12.2923 4.8448 11.5211 5.1616C11.5156 5.16342 11.5109 5.16558 11.5062 5.16769C11.5027 5.1693 11.4992 5.17088 11.4955 5.17227C10.7264 5.48907 9.84533 5.31947 9.2576 4.73173L6.94933 2.42347L2.42347 6.94933L4.73173 9.2576C5.32053 9.84533 5.48907 10.7264 5.17227 11.4955C5.168 11.504 5.1648 11.5125 5.1616 11.5211C4.8448 12.2923 4.0992 12.8 3.264 12.8H0V19.2H3.264C4.0992 19.2 4.8448 19.7077 5.1616 20.4789C5.1648 20.4875 5.168 20.496 5.17227 20.5045C5.48907 21.2736 5.32053 22.1547 4.73173 22.7424L2.42347 25.0507L6.94933 29.5765L9.2576 27.2683C9.84533 26.6805 10.7264 26.5109 11.4955 26.8277C11.4992 26.8291 11.5027 26.8307 11.5062 26.8323C11.5109 26.8344 11.5156 26.8366 11.5211 26.8384C12.2923 27.1552 12.8 27.9008 12.8 28.7349V32H19.2V28.7349C19.2 27.9008 19.7077 27.1552 20.4789 26.8384C20.4844 26.8366 20.4891 26.8344 20.4938 26.8323C20.4974 26.8307 20.5008 26.8291 20.5045 26.8277C21.2736 26.5109 22.1547 26.6805 22.7424 27.2683L25.0507 29.5765L29.5765 25.0507L27.2683 22.7424C26.6795 22.1547 26.5109 21.2736 26.8277 20.5045C26.832 20.496 26.8352 20.4875 26.8384 20.479ZM25.7611 24.2523C24.5504 23.0437 24.2165 21.2425 24.8552 19.692L24.8848 19.6201L24.8877 19.6144C25.5407 18.0852 27.0422 17.0667 28.736 17.0667H29.8667V14.9333H28.736C27.0422 14.9333 25.5407 13.9148 24.8877 12.3856L24.8848 12.3799L24.8552 12.308C24.2166 10.7578 24.5502 8.95696 25.7605 7.74837C25.7607 7.74816 25.7603 7.74859 25.7605 7.74837L26.5595 6.94933L25.0507 5.44046L24.2509 6.24023C23.0557 7.43543 21.2788 7.77771 19.7367 7.16293L19.7355 7.1625L19.7277 7.15931C19.7205 7.15643 19.7133 7.15353 19.7062 7.15061C19.6901 7.14415 19.6759 7.1382 19.6639 7.13309C18.1078 6.49182 17.0667 4.9766 17.0667 3.26507V2.13333H14.9333V3.26507C14.9333 4.97661 13.8922 6.49182 12.3361 7.13309C12.3242 7.1382 12.31 7.14412 12.2939 7.15057C12.2867 7.15352 12.2795 7.15645 12.2722 7.15936L12.2645 7.1625L12.2633 7.16292C10.7212 7.77771 8.94431 7.43544 7.74911 6.24023L6.94933 5.44046L5.44046 6.94933L6.23886 7.74774C6.23921 7.74809 6.23956 7.74843 6.2399 7.74878C6.24001 7.74889 6.23979 7.74867 6.2399 7.74878C7.44957 8.95736 7.78325 10.7581 7.1448 12.308L7.11517 12.3799L7.11234 12.3856C6.45935 13.9148 4.95778 14.9333 3.264 14.9333H2.13333V17.0667H3.264C4.95778 17.0667 6.45935 18.0852 7.11235 19.6144L7.11517 19.6201L7.1448 19.692C7.78325 21.2419 7.4499 23.0423 6.24023 24.2509C6.24012 24.251 6.24034 24.2508 6.24023 24.2509C6.23988 24.2512 6.23921 24.2519 6.23886 24.2523L5.44046 25.0507L6.94933 26.5595L7.74911 25.7598C8.94432 24.5646 10.7212 24.2223 12.2633 24.8371L12.2645 24.8375L12.2721 24.8406C12.2795 24.8436 12.2868 24.8465 12.2942 24.8495C12.3101 24.8559 12.3243 24.8618 12.3362 24.8669C13.8922 25.5082 14.9333 27.0234 14.9333 28.7349V29.8667H17.0667V28.7349C17.0667 27.0234 18.1078 25.5082 19.6638 24.8669C19.6758 24.8618 19.6899 24.8559 19.7058 24.8495C19.7131 24.8466 19.7204 24.8436 19.7277 24.8407L19.7355 24.8375L19.7367 24.8371C21.2788 24.2223 23.0557 24.5646 24.2509 25.7598L25.0507 26.5595L26.5595 25.0507L25.7611 24.2523ZM7.1591 19.7299L7.15841 19.728ZM7.1591 12.2701C7.16029 12.267 7.15989 12.2681 7.15836 12.2721L7.1591 12.2701ZM24.8409 12.2701L24.8417 12.2722ZM24.8409 19.7299C24.8397 19.733 24.8401 19.7319 24.8416 19.7279L24.8409 19.7299Z" + fill="#535966" + /> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M16 13C14.3433 13 13 14.3433 13 16C13 17.6567 14.3433 19 16 19C17.6567 19 19 17.6567 19 16C19 14.3433 17.6567 13 16 13ZM11 16C11 13.2387 13.2387 11 16 11C18.7613 11 21 13.2387 21 16C21 18.7613 18.7613 21 16 21C13.2387 21 11 18.7613 11 16Z" + fill="#00BFB3" + /> + </g> + <defs> + <clipPath id="clip0_4044_22923"> + <rect width="32" height="32" fill="white" /> + </clipPath> + </defs> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconSettings; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/siem.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/siem.tsx deleted file mode 100644 index 00b775af8fa36..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/siem.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { SVGProps } from 'react'; -import React from 'react'; -export const IconSiem: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g clipPath="url(#clip0_2634_421176)"> - <path - id="Shape" - fillRule="evenodd" - clipRule="evenodd" - d="M10 12C15.4292 12 19.8479 16.3267 19.9962 21.7201L20 22V23H11V32H10C4.47715 32 0 27.5228 0 22C0 16.4772 4.47715 12 10 12ZM9 21L9.00005 14.0619C5.05371 14.554 2 17.9204 2 22C2 25.9928 4.92513 29.3024 8.74934 29.9028L9 29.9381V21ZM11 21L11.0009 14.062L11.258 14.0983C14.7544 14.6506 17.4976 17.4677 17.9381 21H11Z" - fill="#535766" - /> - <path - id="Path" - d="M26 22C26 13.1634 18.8366 6 10 6V8C17.732 8 24 14.268 24 22H26Z" - fill="#00BFB3" - /> - <path - id="Path_2" - d="M32 22C32 9.84974 22.1503 0 10 0V2C21.0457 2 30 10.9543 30 22H32Z" - fill="#00BFB3" - /> - </g> - <defs> - <clipPath id="clip0_2634_421176"> - <rect width="32" height="32" fill="white" /> - </clipPath> - </defs> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconSiem; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/spaces.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/spaces.tsx deleted file mode 100644 index 1a5e6300b1b9f..0000000000000 --- a/x-pack/plugins/security_solution_serverless/public/common/icons/spaces.tsx +++ /dev/null @@ -1,56 +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 { SVGProps } from 'react'; -import React from 'react'; -export const IconSpaces: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( - <svg - width="32" - height="32" - viewBox="0 0 32 32" - fill="none" - xmlns="http://www.w3.org/2000/svg" - {...props} - > - <g id="Group"> - <path - id="Stroke 1" - fillRule="evenodd" - clipRule="evenodd" - d="M1 1V15H15V1H1ZM13 13H3V3H13V13Z" - fill="#535766" - /> - <path id="Stroke 3" d="M5 7V5H11V7H5Z" fill="#00BFB3" /> - <path - id="Stroke 4" - fillRule="evenodd" - clipRule="evenodd" - d="M17 1V15H31V1H17ZM29 13H19V3H29V13Z" - fill="#535766" - /> - <path id="Stroke 6" d="M21 7V5H27V7H21Z" fill="#00BFB3" /> - <path - id="Stroke 7" - fillRule="evenodd" - clipRule="evenodd" - d="M1 17V31H15V17H1ZM13 29H3V19H13V29Z" - fill="#535766" - /> - <path id="Stroke 9" d="M5 23V21H11V23H5Z" fill="#00BFB3" /> - <path - id="Stroke 10" - fillRule="evenodd" - clipRule="evenodd" - d="M17 17V31H31V17H17ZM29 29H19V19H29V29Z" - fill="#535766" - /> - <path id="Stroke 12" d="M21 23V21H27V23H21Z" fill="#00BFB3" /> - </g> - </svg> -); - -// eslint-disable-next-line import/no-default-export -export default IconSpaces; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/users_roles.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/users_roles.tsx new file mode 100644 index 0000000000000..3eb961f783f67 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/users_roles.tsx @@ -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 type { SVGProps } from 'react'; +import React from 'react'; +export const IconUsersRoles: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + id="Fill 1" + fillRule="evenodd" + clipRule="evenodd" + d="M16 4C15.448 4 15 3.552 15 3C15 2.448 15.448 2 16 2C16.552 2 17 2.448 17 3C17 3.552 16.552 4 16 4ZM18.911 2.308C18.597 0.987 17.415 0 16 0C14.346 0 13 1.346 13 3C13 4.654 14.346 6 16 6C17.176 6 18.186 5.313 18.677 4.326C22.501 5.203 25.711 7.91 27.166 11.597L29.027 10.862C27.302 6.491 23.47 3.274 18.911 2.308Z" + fill="#535766" + /> + <path + id="Fill 3" + fillRule="evenodd" + clipRule="evenodd" + d="M3 17C2.448 17 2 16.552 2 16C2 15.448 2.448 15 3 15C3.552 15 4 15.448 4 16C4 16.552 3.552 17 3 17ZM11.597 4.83402L10.862 2.97302C6.491 4.69802 3.274 8.53002 2.308 13.089C0.987 13.403 0 14.585 0 16C0 17.654 1.346 19 3 19C4.654 19 6 17.654 6 16C6 14.824 5.313 13.814 4.326 13.323C5.203 9.49902 7.91 6.28902 11.597 4.83402Z" + fill="#535766" + /> + <path + id="Fill 5" + fillRule="evenodd" + clipRule="evenodd" + d="M16.0001 30C15.4481 30 15.0001 29.552 15.0001 29C15.0001 28.448 15.4481 28 16.0001 28C16.5521 28 17.0001 28.448 17.0001 29C17.0001 29.552 16.5521 30 16.0001 30ZM16.0001 26C14.8241 26 13.8141 26.687 13.3231 27.674C9.49915 26.797 6.28914 24.09 4.83414 20.403L2.97314 21.138C4.69814 25.509 8.53014 28.726 13.0891 29.692C13.4031 31.013 14.5851 32 16.0001 32C17.6541 32 19.0001 30.654 19.0001 29C19.0001 27.346 17.6541 26 16.0001 26Z" + fill="#535766" + /> + <path + id="Fill 7" + fillRule="evenodd" + clipRule="evenodd" + d="M28.9998 17C28.4478 17 27.9998 16.552 27.9998 16C27.9998 15.448 28.4478 15 28.9998 15C29.5518 15 29.9998 15.448 29.9998 16C29.9998 16.552 29.5518 17 28.9998 17ZM31.9998 16C31.9998 14.346 30.6538 13 28.9998 13C27.3458 13 25.9998 14.346 25.9998 16C25.9998 17.176 26.6868 18.186 27.6738 18.677C26.7978 22.501 24.0898 25.711 20.4028 27.166L21.1378 29.027C25.5088 27.302 28.7258 23.47 29.6918 18.911C31.0128 18.597 31.9998 17.415 31.9998 16Z" + fill="#535766" + /> + <path + id="Fill 9" + fillRule="evenodd" + clipRule="evenodd" + d="M13 20C13 18.346 14.346 17 16 17C17.654 17 19 18.346 19 20H13ZM14 13C14 11.897 14.897 11 16 11C17.103 11 18 11.897 18 13C18 14.103 17.103 15 16 15C14.897 15 14 14.103 14 13ZM18.794 15.855C19.536 15.129 20 14.119 20 13C20 10.794 18.206 9 16 9C13.794 9 12 10.794 12 13C12 14.119 12.464 15.129 13.206 15.855C11.876 16.755 11 18.277 11 20V22H21V20C21 18.277 20.124 16.755 18.794 15.855Z" + fill="#00BFB3" + /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconUsersRoles; diff --git a/x-pack/plugins/security_solution_serverless/public/common/icons/visualization.tsx b/x-pack/plugins/security_solution_serverless/public/common/icons/visualization.tsx new file mode 100644 index 0000000000000..983dcec736015 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/common/icons/visualization.tsx @@ -0,0 +1,39 @@ +/* + * 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 { SVGProps } from 'react'; +import React from 'react'; +export const IconVisualization: React.FC<SVGProps<SVGSVGElement>> = ({ ...props }) => ( + <svg + width="32" + height="32" + viewBox="0 0 32 32" + fill="none" + xmlns="http://www.w3.org/2000/svg" + {...props} + > + <path + id="Path" + fillRule="evenodd" + clipRule="evenodd" + d="M30 30H4C1.79086 30 0 28.2091 0 26V0H2V26C2 27.1046 2.89543 28 4 28H30V30Z" + fill="#535766" + /> + <rect id="Rectangle" x="6" y="19" width="2" height="7" fill="#535766" /> + <rect id="Rectangle_2" x="16" y="11" width="2" height="15" fill="#535766" /> + <rect id="Rectangle_3" x="26" y="16" width="2" height="10" fill="#535766" /> + <path + id="Shape" + fillRule="evenodd" + clipRule="evenodd" + d="M24.92 5.84C25.4786 5.30157 26.2241 5.0005 27 5C28.6569 5 30 6.34315 30 8C30 9.65685 28.6569 11 27 11C25.3431 11 24 9.65685 24 8C24.0165 7.87797 24.0433 7.75755 24.08 7.64L19.08 5.16C18.5214 5.69843 17.7759 5.9995 17 6C16.4388 5.99095 15.8914 5.82465 15.42 5.52L9.82 10C9.93778 10.3203 9.9987 10.6587 10 11C10 12.6569 8.65685 14 7 14C5.34315 14 4 12.6569 4 11C4 9.34315 5.34315 8 7 8C7.55925 8.00307 8.1065 8.16239 8.58 8.46L14.18 4C14.0622 3.67969 14.0013 3.34127 14 3C14 1.34315 15.3431 0 17 0C18.6569 0 20 1.34315 20 3C20.0098 3.1198 20.0098 3.2402 20 3.36L24.92 5.84ZM6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11ZM17 4C16.4477 4 16 3.55228 16 3C16 2.44772 16.4477 2 17 2C17.5523 2 18 2.44772 18 3C18 3.26522 17.8946 3.51957 17.7071 3.70711C17.5196 3.89464 17.2652 4 17 4ZM26 8C26 8.55229 26.4477 9 27 9C27.5523 9 28 8.55229 28 8C28 7.44772 27.5523 7 27 7C26.4477 7 26 7.44772 26 8Z" + fill="#00BFB3" + /> + </svg> +); + +// eslint-disable-next-line import/no-default-export +export default IconVisualization; diff --git a/x-pack/plugins/security_solution_serverless/public/common/lazy_icons.tsx b/x-pack/plugins/security_solution_serverless/public/common/lazy_icons.tsx index 2143eee79ebe9..f7e016d75c969 100644 --- a/x-pack/plugins/security_solution_serverless/public/common/lazy_icons.tsx +++ b/x-pack/plugins/security_solution_serverless/public/common/lazy_icons.tsx @@ -19,28 +19,38 @@ const withSuspenseIcon = <T extends object = {}>(Component: React.ComponentType< export const IconLensLazy = withSuspenseIcon(React.lazy(() => import('./icons/lens'))); export const IconEndpointLazy = withSuspenseIcon(React.lazy(() => import('./icons/endpoint'))); -export const IconDataConnectorLazy = withSuspenseIcon( - React.lazy(() => import('./icons/data_connector')) -); export const IconIndexManagementLazy = withSuspenseIcon( React.lazy(() => import('./icons/index_management')) ); -export const IconSpacesLazy = withSuspenseIcon(React.lazy(() => import('./icons/spaces'))); -export const IconDevToolsLazy = withSuspenseIcon(React.lazy(() => import('./icons/dev_tools'))); export const IconFleetLazy = withSuspenseIcon(React.lazy(() => import('./icons/fleet'))); -export const IconAuditbeatLazy = withSuspenseIcon(React.lazy(() => import('./icons/auditbeat'))); -export const IconSiemLazy = withSuspenseIcon(React.lazy(() => import('./icons/siem'))); export const IconEcctlLazy = withSuspenseIcon(React.lazy(() => import('./icons/ecctl'))); -export const IconGraphLazy = withSuspenseIcon(React.lazy(() => import('./icons/graph'))); -export const IconLoggingLazy = withSuspenseIcon(React.lazy(() => import('./icons/logging'))); export const IconMapServicesLazy = withSuspenseIcon( React.lazy(() => import('./icons/map_services')) ); -export const IconSecurityShieldLazy = withSuspenseIcon( - React.lazy(() => import('./icons/security_shield')) -); -export const IconProductFeaturesAlertingLazy = withSuspenseIcon( - React.lazy(() => import('./icons/product_features_alerting')) -); export const IconTimelineLazy = withSuspenseIcon(React.lazy(() => import('./icons/timeline'))); export const IconOsqueryLazy = withSuspenseIcon(React.lazy(() => import('./icons/osquery'))); +export const IconUsersRolesLazy = withSuspenseIcon(React.lazy(() => import('./icons/users_roles'))); +export const IconReportingLazy = withSuspenseIcon(React.lazy(() => import('./icons/reporting'))); +export const IconVisualizationLazy = withSuspenseIcon( + React.lazy(() => import('./icons/visualization')) +); +export const IconMarketingLazy = withSuspenseIcon(React.lazy(() => import('./icons/marketing'))); +export const IconInfraLazy = withSuspenseIcon(React.lazy(() => import('./icons/infra'))); +export const IconKeywordLazy = withSuspenseIcon(React.lazy(() => import('./icons/keyword'))); +export const IconJobsLazy = withSuspenseIcon(React.lazy(() => import('./icons/jobs'))); +export const IconSettingsLazy = withSuspenseIcon(React.lazy(() => import('./icons/settings'))); +export const IconDashboardLazy = withSuspenseIcon(React.lazy(() => import('./icons/dashboard'))); +export const IconChartArrowLazy = withSuspenseIcon(React.lazy(() => import('./icons/chart_arrow'))); +export const IconManagerLazy = withSuspenseIcon(React.lazy(() => import('./icons/manager'))); +export const IconFilebeatLazy = withSuspenseIcon(React.lazy(() => import('./icons/filebeat'))); +export const IconDataViewLazy = withSuspenseIcon(React.lazy(() => import('./icons/data_view'))); +export const IconReplicationLazy = withSuspenseIcon( + React.lazy(() => import('./icons/replication')) +); +export const IconIntuitiveLazy = withSuspenseIcon(React.lazy(() => import('./icons/intuitive'))); +export const IconRapidBarGraphLazy = withSuspenseIcon( + React.lazy(() => import('./icons/rapid_bar_graph')) +); +export const IconFilebeatChartLazy = withSuspenseIcon( + React.lazy(() => import('./icons/filebeat_chart')) +); diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts b/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts index 9c6073c028731..520cbdd192ae4 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts @@ -39,6 +39,7 @@ export enum ExternalPageName { // Ref: packages/default-nav/ml/default_navigation.ts mlOverview = 'ml:overview', mlNotifications = 'ml:notifications', + mlMemoryUsage = 'ml:memoryUsage', mlAnomalyDetection = 'ml:anomalyDetection', mlAnomalyExplorer = 'ml:anomalyExplorer', mlSingleMetricViewer = 'ml:singleMetricViewer', @@ -50,7 +51,8 @@ export enum ExternalPageName { mlNodes = 'ml:nodes', mlFileUpload = 'ml:fileUpload', mlIndexDataVisualizer = 'ml:indexDataVisualizer', - mlExplainLogRateSpikes = 'ml:explainLogRateSpikes', + mlDataComparison = 'ml:dataComparison', + mlExplainLogRateSpikes = 'ml:logRateAnalysis', mlLogPatternAnalysis = 'ml:logPatternAnalysis', mlChangePointDetections = 'ml:changePointDetections', // Dev Tools diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_links.ts b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_links.ts index ed324cfb6f52c..32c7587097616 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_links.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_links.ts @@ -13,14 +13,21 @@ import type { ProjectLinkCategory, ProjectNavigationLink } from '../types'; import * as i18n from './ml_translations'; import { IconLensLazy, - IconEndpointLazy, - IconSpacesLazy, - IconIndexManagementLazy, - IconDataConnectorLazy, - IconDevToolsLazy, - IconFleetLazy, - IconAuditbeatLazy, - IconSiemLazy, + IconMarketingLazy, + IconInfraLazy, + IconFilebeatChartLazy, + IconJobsLazy, + IconKeywordLazy, + IconDashboardLazy, + IconVisualizationLazy, + IconSettingsLazy, + IconChartArrowLazy, + IconManagerLazy, + IconFilebeatLazy, + IconReplicationLazy, + IconDataViewLazy, + IconIntuitiveLazy, + IconRapidBarGraphLazy, } from '../../../common/lazy_icons'; // appLinks configures the Security Solution pages links @@ -38,7 +45,11 @@ export const mlAppLink: LinkItem = { export const mlNavCategories: ProjectLinkCategory[] = [ { type: LinkCategoryType.separator, - linkIds: [ExternalPageName.mlOverview, ExternalPageName.mlNotifications], + linkIds: [ + ExternalPageName.mlOverview, + ExternalPageName.mlNotifications, + ExternalPageName.mlMemoryUsage, + ], }, { type: LinkCategoryType.title, @@ -62,12 +73,16 @@ export const mlNavCategories: ProjectLinkCategory[] = [ { type: LinkCategoryType.title, label: i18n.MODEL_MANAGEMENT_CATEGORY, - linkIds: [ExternalPageName.mlNodesOverview, ExternalPageName.mlNodes], + linkIds: [ExternalPageName.mlNodesOverview], }, { type: LinkCategoryType.title, label: i18n.DATA_VISUALIZER_CATEGORY, - linkIds: [ExternalPageName.mlFileUpload, ExternalPageName.mlIndexDataVisualizer], + linkIds: [ + ExternalPageName.mlFileUpload, + ExternalPageName.mlIndexDataVisualizer, + ExternalPageName.mlDataComparison, + ], }, { type: LinkCategoryType.title, @@ -91,91 +106,97 @@ export const mlNavLinks: ProjectNavigationLink[] = [ { id: ExternalPageName.mlNotifications, title: i18n.NOTIFICATIONS_TITLE, - landingIcon: IconEndpointLazy, + landingIcon: IconMarketingLazy, description: i18n.NOTIFICATIONS_DESC, }, + { + id: ExternalPageName.mlMemoryUsage, + title: i18n.MEMORY_USAGE_TITLE, + landingIcon: IconInfraLazy, + description: i18n.MEMORY_USAGE_DESC, + }, { id: ExternalPageName.mlAnomalyDetection, title: i18n.ANOMALY_DETECTION_TITLE, - landingIcon: IconSpacesLazy, + landingIcon: IconJobsLazy, description: i18n.ANOMALY_DETECTION_DESC, }, { id: ExternalPageName.mlAnomalyExplorer, title: i18n.ANOMALY_EXPLORER_TITLE, - landingIcon: IconIndexManagementLazy, + landingIcon: IconKeywordLazy, description: i18n.ANOMALY_EXPLORER_DESC, }, { id: ExternalPageName.mlSingleMetricViewer, title: i18n.SINGLE_METRIC_VIEWER_TITLE, - landingIcon: IconDataConnectorLazy, + landingIcon: IconVisualizationLazy, description: i18n.SINGLE_METRIC_VIEWER_DESC, }, { id: ExternalPageName.mlSettings, title: i18n.SETTINGS_TITLE, - landingIcon: IconDevToolsLazy, + landingIcon: IconSettingsLazy, description: i18n.SETTINGS_DESC, }, { id: ExternalPageName.mlDataFrameAnalytics, title: i18n.DATA_FRAME_ANALYTICS_TITLE, - landingIcon: IconIndexManagementLazy, + landingIcon: IconJobsLazy, description: i18n.DATA_FRAME_ANALYTICS_DESC, }, { id: ExternalPageName.mlResultExplorer, title: i18n.RESULT_EXPLORER_TITLE, - landingIcon: IconFleetLazy, + landingIcon: IconDashboardLazy, description: i18n.RESULT_EXPLORER_DESC, }, { id: ExternalPageName.mlAnalyticsMap, title: i18n.ANALYTICS_MAP_TITLE, - landingIcon: IconAuditbeatLazy, + landingIcon: IconChartArrowLazy, description: i18n.ANALYTICS_MAP_DESC, }, { id: ExternalPageName.mlNodesOverview, title: i18n.NODES_OVERVIEW_TITLE, - landingIcon: IconSiemLazy, + landingIcon: IconManagerLazy, description: i18n.NODES_OVERVIEW_DESC, }, - { - id: ExternalPageName.mlNodes, - title: i18n.NODES_TITLE, - landingIcon: IconEndpointLazy, - description: i18n.NODES_DESC, - }, { id: ExternalPageName.mlFileUpload, title: i18n.FILE_UPLOAD_TITLE, - landingIcon: IconEndpointLazy, + landingIcon: IconFilebeatLazy, description: i18n.FILE_UPLOAD_DESC, }, { id: ExternalPageName.mlIndexDataVisualizer, title: i18n.INDEX_DATA_VISUALIZER_TITLE, - landingIcon: IconEndpointLazy, + landingIcon: IconDataViewLazy, description: i18n.INDEX_DATA_VISUALIZER_DESC, }, + { + id: ExternalPageName.mlDataComparison, + title: i18n.DATA_COMPARISON_TITLE, + landingIcon: IconRapidBarGraphLazy, + description: i18n.DATA_COMPARISON_DESC, + }, { id: ExternalPageName.mlExplainLogRateSpikes, - title: i18n.EXPLAIN_LOG_RATE_SPIKES_TITLE, - landingIcon: IconEndpointLazy, - description: i18n.EXPLAIN_LOG_RATE_SPIKES_DESC, + title: i18n.LOG_RATE_ANALYSIS_TITLE, + landingIcon: IconFilebeatChartLazy, + description: i18n.LOG_RATE_ANALYSIS_DESC, }, { id: ExternalPageName.mlLogPatternAnalysis, title: i18n.LOG_PATTERN_ANALYSIS_TITLE, - landingIcon: IconEndpointLazy, + landingIcon: IconReplicationLazy, description: i18n.LOG_PATTERN_ANALYSIS_DESC, }, { id: ExternalPageName.mlChangePointDetections, title: i18n.CHANGE_POINT_DETECTIONS_TITLE, - landingIcon: IconEndpointLazy, + landingIcon: IconIntuitiveLazy, description: i18n.CHANGE_POINT_DETECTIONS_DESC, }, ]; diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_translations.ts b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_translations.ts index 301e5b05bfa67..36a28d561bda5 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_translations.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/ml_translations.ts @@ -69,6 +69,18 @@ export const NOTIFICATIONS_DESC = i18n.translate( defaultMessage: 'Notifications page', } ); +export const MEMORY_USAGE_TITLE = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.ml.memoryUsage.title', + { + defaultMessage: 'Memory usage', + } +); +export const MEMORY_USAGE_DESC = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.ml.memoryUsage.desc', + { + defaultMessage: 'Memory usage page', + } +); export const ANOMALY_DETECTION_TITLE = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.anomalyDetection.title', { @@ -90,7 +102,7 @@ export const ANOMALY_EXPLORER_TITLE = i18n.translate( export const ANOMALY_EXPLORER_DESC = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.anomalyExplorer.desc', { - defaultMessage: 'Anomaly explorer Page', + defaultMessage: 'Anomaly explorer page', } ); export const SINGLE_METRIC_VIEWER_TITLE = i18n.translate( @@ -156,13 +168,13 @@ export const ANALYTICS_MAP_DESC = i18n.translate( export const NODES_OVERVIEW_TITLE = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.nodesOverview.title', { - defaultMessage: 'Nodes overview', + defaultMessage: 'Trained models', } ); export const NODES_OVERVIEW_DESC = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.nodesOverview.desc', { - defaultMessage: 'Nodes overview page', + defaultMessage: 'Trained models page', } ); export const NODES_TITLE = i18n.translate( @@ -180,37 +192,49 @@ export const NODES_DESC = i18n.translate( export const FILE_UPLOAD_TITLE = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.fileUpload.title', { - defaultMessage: 'File', + defaultMessage: 'File data visualizer', } ); export const FILE_UPLOAD_DESC = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.fileUpload.desc', { - defaultMessage: 'File page', + defaultMessage: 'File data visualizer page', } ); export const INDEX_DATA_VISUALIZER_TITLE = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.indexDataVisualizer.title', { - defaultMessage: 'Data view', + defaultMessage: 'Data view data visualizer', } ); export const INDEX_DATA_VISUALIZER_DESC = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.indexDataVisualizer.desc', { - defaultMessage: 'Data view page', + defaultMessage: 'Data view data visualizer page', + } +); +export const DATA_COMPARISON_TITLE = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.ml.datComparison.title', + { + defaultMessage: 'Data comparison', + } +); +export const DATA_COMPARISON_DESC = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.ml.datComparison.desc', + { + defaultMessage: 'Data comparison page', } ); -export const EXPLAIN_LOG_RATE_SPIKES_TITLE = i18n.translate( +export const LOG_RATE_ANALYSIS_TITLE = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.explainLogRateSpikes.title', { - defaultMessage: 'Explain log rate spikes', + defaultMessage: 'Log Rate Analysis', } ); -export const EXPLAIN_LOG_RATE_SPIKES_DESC = i18n.translate( +export const LOG_RATE_ANALYSIS_DESC = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.explainLogRateSpikes.desc', { - defaultMessage: 'Explain log rate spikes page', + defaultMessage: 'Log Rate Analysis Page', } ); export const LOG_PATTERN_ANALYSIS_TITLE = i18n.translate( @@ -228,12 +252,12 @@ export const LOG_PATTERN_ANALYSIS_DESC = i18n.translate( export const CHANGE_POINT_DETECTIONS_TITLE = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.changePointDetections.title', { - defaultMessage: 'Change point detections', + defaultMessage: 'Change point detection', } ); export const CHANGE_POINT_DETECTIONS_DESC = i18n.translate( 'xpack.securitySolutionServerless.navLinks.ml.changePointDetections.desc', { - defaultMessage: 'Change point detections page', + defaultMessage: 'Change point detection page', } ); diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts index 643ec2e905298..69e560a929c09 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts @@ -11,12 +11,11 @@ import type { LinkItem } from '@kbn/security-solution-plugin/public'; import { ExternalPageName, SecurityPagePath } from '../constants'; import type { ProjectLinkCategory, ProjectNavigationLink } from '../types'; import { - IconGraphLazy, - IconLoggingLazy, - IconIndexManagementLazy, - IconSecurityShieldLazy, IconMapServicesLazy, - IconProductFeaturesAlertingLazy, + IconIndexManagementLazy, + IconUsersRolesLazy, + IconReportingLazy, + IconVisualizationLazy, } from '../../../common/lazy_icons'; import * as i18n from './project_settings_translations'; @@ -43,7 +42,7 @@ export const createProjectSettingsLinkFromManage = (manageLink: LinkItem): LinkI return { ...projectSettingsAppLink, - links: projectSettingsSubLinks, // cloudDefend and endpoints links are added in the projectAppLinksSwitcher on runtime + links: projectSettingsSubLinks, }; }; @@ -70,7 +69,6 @@ export const projectSettingsNavCategories: ProjectLinkCategory[] = [ categories: [ { label: i18n.DATA_CATEGORY_TITLE, - iconType: IconIndexManagementLazy, linkIds: [ ExternalPageName.managementIndexManagement, ExternalPageName.managementTransforms, @@ -82,7 +80,6 @@ export const projectSettingsNavCategories: ProjectLinkCategory[] = [ }, { label: i18n.ALERTS_INSIGHTS_CATEGORY_TITLE, - iconType: IconProductFeaturesAlertingLazy, linkIds: [ ExternalPageName.managementCases, ExternalPageName.managementTriggersActionsConnectors, @@ -91,7 +88,6 @@ export const projectSettingsNavCategories: ProjectLinkCategory[] = [ }, { label: i18n.CONTENT_CATEGORY_TITLE, - iconType: IconSecurityShieldLazy, linkIds: [ ExternalPageName.managementObjects, ExternalPageName.managementFiles, @@ -101,7 +97,6 @@ export const projectSettingsNavCategories: ProjectLinkCategory[] = [ }, { label: i18n.OTHER_CATEGORY_TITLE, - iconType: IconMapServicesLazy, linkIds: [ExternalPageName.managementApiKeys, ExternalPageName.managementSettings], }, ], @@ -114,13 +109,13 @@ export const projectSettingsNavLinks: ProjectNavigationLink[] = [ id: ExternalPageName.cloudUsersAndRoles, title: i18n.CLOUD_USERS_ROLES_TITLE, description: i18n.CLOUD_USERS_ROLES_DESCRIPTION, - landingIcon: IconGraphLazy, + landingIcon: IconUsersRolesLazy, }, { id: ExternalPageName.cloudBilling, title: i18n.CLOUD_BILLING_TITLE, description: i18n.CLOUD_BILLING_DESCRIPTION, - landingIcon: IconLoggingLazy, + landingIcon: IconReportingLazy, }, { id: ExternalPageName.integrationsSecurity, @@ -128,6 +123,18 @@ export const projectSettingsNavLinks: ProjectNavigationLink[] = [ description: i18n.INTEGRATIONS_DESCRIPTION, landingIcon: IconIndexManagementLazy, }, + { + id: ExternalPageName.maps, + title: i18n.MAPS_TITLE, + description: i18n.MAPS_DESCRIPTION, + landingIcon: IconMapServicesLazy, + }, + { + id: ExternalPageName.visualize, + title: i18n.VISUALIZE_TITLE, + description: i18n.VISUALIZE_DESCRIPTION, + landingIcon: IconVisualizationLazy, + }, { id: ExternalPageName.managementIndexManagement, title: i18n.MANAGEMENT_INDEX_MANAGEMENT_TITLE, @@ -188,16 +195,4 @@ export const projectSettingsNavLinks: ProjectNavigationLink[] = [ id: ExternalPageName.managementSettings, title: i18n.MANAGEMENT_SETTINGS_TITLE, }, - { - id: ExternalPageName.maps, - title: i18n.MAPS_TITLE, - description: i18n.MAPS_DESCRIPTION, - landingIcon: IconGraphLazy, - }, - { - id: ExternalPageName.visualize, - title: i18n.VISUALIZE_TITLE, - description: i18n.VISUALIZE_DESCRIPTION, - landingIcon: IconGraphLazy, - }, ]; diff --git a/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task_config.ts b/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task_config.ts index aa35b9e870c2c..c9b0ccd7672e3 100644 --- a/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task_config.ts +++ b/x-pack/plugins/security_solution_serverless/server/cloud_security/cloud_security_metering_task_config.ts @@ -8,7 +8,7 @@ import { cloudSecurityMetringCallback } from './cloud_security_metering'; import type { MetringTaskProperties } from '../types'; -const TASK_INTERVAL = 3600; // 1 hour +const TASK_INTERVAL = 1800; // 30 minutes export const cloudSecurityMetringTaskProperties: MetringTaskProperties = { taskType: 'cloud-security-usage-reporting-task', diff --git a/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts b/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts index 9203a7fdff287..43cf1f06c47f8 100644 --- a/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts +++ b/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts @@ -17,7 +17,7 @@ import { INTEGRATION_PACKAGE_NAME } from '@kbn/cloud-defend-plugin/common/consta const CLOUD_DEFEND_HEARTBEAT_INDEX = 'metrics-cloud_defend.heartbeat'; export const CLOUD_SECURITY_TASK_TYPE = 'cloud_security'; export const AGGREGATION_PRECISION_THRESHOLD = 40000; -export const ASSETS_SAMPLE_GRANULARITY = '124h'; +export const ASSETS_SAMPLE_GRANULARITY = '24h'; export const THRESHOLD_MINUTES = 30; export const CSPM = CSPM_POLICY_TEMPLATE; diff --git a/x-pack/plugins/security_solution_serverless/server/endpoint/constants/metering.ts b/x-pack/plugins/security_solution_serverless/server/endpoint/constants/metering.ts index bcb41d5d0d553..c4647e9bb8b10 100644 --- a/x-pack/plugins/security_solution_serverless/server/endpoint/constants/metering.ts +++ b/x-pack/plugins/security_solution_serverless/server/endpoint/constants/metering.ts @@ -10,4 +10,9 @@ export const METERING_TASK = { TYPE: 'serverless-security:endpoint-usage-reporting-task', VERSION: '1.0.0', INTERVAL: '5m', + // 1 hour + SAMPLE_PERIOD_SECONDS: 3600, + THRESHOLD_MINUTES: 30, + USAGE_TYPE_PREFIX: 'security_solution_', + MISSING_PROJECT_ID: 'missing_project_id', }; diff --git a/x-pack/plugins/security_solution_serverless/server/endpoint/services/metering_service.test.ts b/x-pack/plugins/security_solution_serverless/server/endpoint/services/metering_service.test.ts new file mode 100644 index 0000000000000..e459fdcff3bde --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/server/endpoint/services/metering_service.test.ts @@ -0,0 +1,161 @@ +/* + * 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 { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { type ElasticsearchClientMock, elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import type { AggregationsAggregate, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; +import type { CloudSetup } from '@kbn/cloud-plugin/server'; +import type { EndpointHeartbeat } from '@kbn/security-solution-plugin/common/endpoint/types'; +import { ENDPOINT_HEARTBEAT_INDEX } from '@kbn/security-solution-plugin/common/endpoint/constants'; + +import { ProductLine, ProductTier } from '../../../common/product'; + +import type { ServerlessSecurityConfig } from '../../config'; +import { METERING_TASK } from '../constants/metering'; + +import { EndpointMeteringService } from './metering_service'; + +describe('EndpointMeteringService', () => { + function buildDefaultUsageRecordArgs() { + return { + logger: loggingSystemMock.createLogger(), + taskId: 'test-task-id', + cloudSetup: { + serverless: { + projectId: 'test-project-id', + }, + } as CloudSetup, + esClient: elasticsearchServiceMock.createElasticsearchClient(), + abortController: new AbortController(), + lastSuccessfulReport: new Date(), + config: { + productTypes: [ + { + product_line: ProductLine.endpoint, + product_tier: ProductTier.essentials, + }, + ], + } as ServerlessSecurityConfig, + }; + } + + function buildEsSearchResponse( + { + agentId, + timestamp, + }: { + agentId: string; + timestamp: Date; + } = { + agentId: 'test-agent-id', + timestamp: new Date(), + } + ): SearchResponse<EndpointHeartbeat, Record<string, AggregationsAggregate>> { + return { + hits: { + hits: [ + { + _index: ENDPOINT_HEARTBEAT_INDEX, + _id: 'test-heartbeat-doc-id', + _source: { + agent: { + id: agentId, + }, + event: { + ingested: timestamp.toISOString(), + }, + }, + }, + ], + }, + } as SearchResponse<EndpointHeartbeat, Record<string, AggregationsAggregate>>; + } + + it.each(Object.values(ProductTier))( + 'can correctly getUsageRecords for %s tier', + async (tier: ProductTier) => { + const esSearchResponse = buildEsSearchResponse(); + const heartbeatDocSrc = esSearchResponse.hits.hits[0]._source; + const agentId = heartbeatDocSrc!.agent.id; + const timestamp = new Date(heartbeatDocSrc!.event.ingested); + timestamp.setMinutes(0); + timestamp.setSeconds(0); + timestamp.setMilliseconds(0); + + const args = buildDefaultUsageRecordArgs(); + args.config.productTypes[0] = { + ...args.config.productTypes[0], + product_tier: tier, + }; + (args.esClient as ElasticsearchClientMock).search.mockResolvedValueOnce(esSearchResponse); + const endpointMeteringService = new EndpointMeteringService(); + const usageRecords = await endpointMeteringService.getUsageRecords(args); + + expect(usageRecords[0]).toEqual({ + id: `endpoint-${agentId}-${timestamp.toISOString()}`, + usage_timestamp: heartbeatDocSrc!.event.ingested, + creation_timestamp: heartbeatDocSrc!.event.ingested, + usage: { + type: `${METERING_TASK.USAGE_TYPE_PREFIX}endpoint`, + period_seconds: METERING_TASK.SAMPLE_PERIOD_SECONDS, + quantity: 1, + }, + source: { + id: args.taskId, + instance_group_id: args.cloudSetup.serverless.projectId, + metadata: { + tier, + }, + }, + }); + } + ); + + it.each([ProductLine.endpoint, ProductLine.cloud])( + 'can correctly getUsageRecords for %s product line', + async (productLine: ProductLine) => { + const esSearchResponse = buildEsSearchResponse(); + const heartbeatDocSrc = esSearchResponse.hits.hits[0]._source; + const agentId = heartbeatDocSrc!.agent.id; + const timestamp = new Date(heartbeatDocSrc!.event.ingested); + timestamp.setMinutes(0); + timestamp.setSeconds(0); + timestamp.setMilliseconds(0); + + const args = buildDefaultUsageRecordArgs(); + args.config.productTypes[0] = { + ...args.config.productTypes[0], + product_line: productLine, + }; + (args.esClient as ElasticsearchClientMock).search.mockResolvedValueOnce(esSearchResponse); + const endpointMeteringService = new EndpointMeteringService(); + const usageRecords = await endpointMeteringService.getUsageRecords(args); + const usageTypePostfix = + productLine === ProductLine.endpoint + ? productLine + : `${ProductLine.cloud}_${ProductLine.endpoint}`; + + expect(usageRecords[0]).toEqual({ + id: `endpoint-${agentId}-${timestamp.toISOString()}`, + usage_timestamp: heartbeatDocSrc!.event.ingested, + creation_timestamp: heartbeatDocSrc!.event.ingested, + usage: { + type: `${METERING_TASK.USAGE_TYPE_PREFIX}${usageTypePostfix}`, + period_seconds: METERING_TASK.SAMPLE_PERIOD_SECONDS, + quantity: 1, + }, + source: { + id: args.taskId, + instance_group_id: args.cloudSetup.serverless.projectId, + metadata: { + tier: args.config.productTypes[0].product_tier, + }, + }, + }); + } + ); +}); diff --git a/x-pack/plugins/security_solution_serverless/server/endpoint/services/metering_service.ts b/x-pack/plugins/security_solution_serverless/server/endpoint/services/metering_service.ts index 307ba5714e0f4..765ffcfeb76a4 100644 --- a/x-pack/plugins/security_solution_serverless/server/endpoint/services/metering_service.ts +++ b/x-pack/plugins/security_solution_serverless/server/endpoint/services/metering_service.ts @@ -6,7 +6,7 @@ */ import type { AggregationsAggregate, SearchResponse } from '@elastic/elasticsearch/lib/api/types'; -import type { ElasticsearchClient } from '@kbn/core/server'; +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { ENDPOINT_HEARTBEAT_INDEX } from '@kbn/security-solution-plugin/common/endpoint/constants'; import type { EndpointHeartbeat } from '@kbn/security-solution-plugin/common/endpoint/types'; @@ -15,9 +15,7 @@ import { ProductLine, ProductTier } from '../../../common/product'; import type { UsageRecord, MeteringCallbackInput } from '../../types'; import type { ServerlessSecurityConfig } from '../../config'; -// 1 hour -const SAMPLE_PERIOD_SECONDS = 3600; -const THRESHOLD_MINUTES = 30; +import { METERING_TASK } from '../constants/metering'; export class EndpointMeteringService { private type: ProductLine.endpoint | `${ProductLine.cloud}_${ProductLine.endpoint}` | undefined; @@ -30,6 +28,7 @@ export class EndpointMeteringService { abortController, lastSuccessfulReport, config, + logger, }: MeteringCallbackInput): Promise<UsageRecord[]> => { this.setType(config); if (!this.type) { @@ -55,6 +54,7 @@ export class EndpointMeteringService { const { agent, event } = _source; const record = this.buildMeteringRecord({ + logger, agentId: agent.id, timestampStr: event.ingested, taskId, @@ -70,7 +70,7 @@ export class EndpointMeteringService { abortController: AbortController, since?: Date ): Promise<SearchResponse<EndpointHeartbeat, Record<string, AggregationsAggregate>>> { - const thresholdDate = new Date(Date.now() - THRESHOLD_MINUTES * 60 * 1000); + const thresholdDate = new Date(Date.now() - METERING_TASK.THRESHOLD_MINUTES * 60 * 1000); const searchFrom = since && since > thresholdDate ? since : thresholdDate; return esClient.search<EndpointHeartbeat>( @@ -90,11 +90,13 @@ export class EndpointMeteringService { } private buildMeteringRecord({ + logger, agentId, timestampStr, taskId, - projectId = '', + projectId, }: { + logger: Logger; agentId: string; timestampStr: string; taskId: string; @@ -105,26 +107,32 @@ export class EndpointMeteringService { timestamp.setSeconds(0); timestamp.setMilliseconds(0); - return { + const usageRecord = { // keep endpoint instead of this.type as id prefix so // we don't double count in the event of add-on changes - id: `endpoint-${agentId}-${timestamp}`, + id: `endpoint-${agentId}-${timestamp.toISOString()}`, usage_timestamp: timestampStr, creation_timestamp: timestampStr, usage: { // type postfix is used to determine the PLI to bill - type: `security_solution_${this.type}`, - period_seconds: SAMPLE_PERIOD_SECONDS, + type: `${METERING_TASK.USAGE_TYPE_PREFIX}${this.type}`, + period_seconds: METERING_TASK.SAMPLE_PERIOD_SECONDS, quantity: 1, }, source: { id: taskId, - instance_group_id: projectId, + instance_group_id: projectId || METERING_TASK.MISSING_PROJECT_ID, metadata: { tier: this.tier, }, }, }; + + if (!projectId) { + logger.error(`project id missing for record: ${JSON.stringify(usageRecord)}`); + } + + return usageRecord; } private setType(config: ServerlessSecurityConfig) { diff --git a/x-pack/plugins/security_solution_serverless/server/plugin.ts b/x-pack/plugins/security_solution_serverless/server/plugin.ts index e5696ce363617..5d85f31de8c16 100644 --- a/x-pack/plugins/security_solution_serverless/server/plugin.ts +++ b/x-pack/plugins/security_solution_serverless/server/plugin.ts @@ -42,7 +42,7 @@ export class SecuritySolutionServerlessPlugin > { private config: ServerlessSecurityConfig; - private cspmUsageReportingTask: SecurityUsageReportingTask | undefined; + private cloudSecurityUsageReportingTask: SecurityUsageReportingTask | undefined; private endpointUsageReportingTask: SecurityUsageReportingTask | undefined; private readonly logger: Logger; @@ -67,12 +67,12 @@ export class SecuritySolutionServerlessPlugin pluginsSetup.ml.setFeaturesEnabled({ ad: true, dfa: true, nlp: false }); - this.cspmUsageReportingTask = new SecurityUsageReportingTask({ + this.cloudSecurityUsageReportingTask = new SecurityUsageReportingTask({ core: coreSetup, logFactory: this.initializerContext.logger, config: this.config, taskManager: pluginsSetup.taskManager, - cloudSetup: pluginsSetup.cloudSetup, + cloudSetup: pluginsSetup.cloud, taskType: cloudSecurityMetringTaskProperties.taskType, taskTitle: cloudSecurityMetringTaskProperties.taskTitle, version: cloudSecurityMetringTaskProperties.version, @@ -88,7 +88,7 @@ export class SecuritySolutionServerlessPlugin version: ENDPOINT_METERING_TASK.VERSION, meteringCallback: endpointMeteringService.getUsageRecords, taskManager: pluginsSetup.taskManager, - cloudSetup: pluginsSetup.cloudSetup, + cloudSetup: pluginsSetup.cloud, }); pluginsSetup.serverless.setupProjectSettings(SECURITY_PROJECT_SETTINGS); @@ -100,7 +100,7 @@ export class SecuritySolutionServerlessPlugin const internalESClient = _coreStart.elasticsearch.client.asInternalUser; const internalSOClient = _coreStart.savedObjects.createInternalRepository(); - this.cspmUsageReportingTask?.start({ + this.cloudSecurityUsageReportingTask?.start({ taskManager: pluginsSetup.taskManager, interval: cloudSecurityMetringTaskProperties.interval, }); diff --git a/x-pack/plugins/security_solution_serverless/server/types.ts b/x-pack/plugins/security_solution_serverless/server/types.ts index 1beca2fc23b9d..5c2aa0818cfd2 100644 --- a/x-pack/plugins/security_solution_serverless/server/types.ts +++ b/x-pack/plugins/security_solution_serverless/server/types.ts @@ -38,7 +38,7 @@ export interface SecuritySolutionServerlessPluginSetupDeps { features: PluginSetupContract; ml: MlPluginSetup; taskManager: TaskManagerSetupContract; - cloudSetup: CloudSetup; + cloud: CloudSetup; } export interface SecuritySolutionServerlessPluginStartDeps { diff --git a/x-pack/plugins/security_solution_serverless/tsconfig.json b/x-pack/plugins/security_solution_serverless/tsconfig.json index 636642b2a68d5..00829caa2ffd4 100644 --- a/x-pack/plugins/security_solution_serverless/tsconfig.json +++ b/x-pack/plugins/security_solution_serverless/tsconfig.json @@ -43,6 +43,7 @@ "@kbn/serverless-security-settings", "@kbn/core-elasticsearch-server", "@kbn/usage-collection-plugin", - "@kbn/cloud-defend-plugin" + "@kbn/cloud-defend-plugin", + "@kbn/core-logging-server-mocks" ] } diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 3808a64e3baff..55cf3960ab0bd 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -66,14 +66,15 @@ const navigationTree: NavigationTreeDefinition = { defaultMessage: 'Log rate analysis', }), link: 'ml:logRateAnalysis', - icon: 'beaker', getIsActive: ({ pathNameSerialized, prepend }) => { return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); }, }, { + title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { + defaultMessage: 'Change point detection', + }), link: 'ml:changePointDetections', - icon: 'beaker', getIsActive: ({ pathNameSerialized, prepend }) => { return pathNameSerialized.includes( prepend('/app/ml/aiops/change_point_detection') diff --git a/x-pack/plugins/serverless_search/server/plugin.ts b/x-pack/plugins/serverless_search/server/plugin.ts index e43c5b0f18bbb..a77ff8dfd9cc3 100644 --- a/x-pack/plugins/serverless_search/server/plugin.ts +++ b/x-pack/plugins/serverless_search/server/plugin.ts @@ -71,7 +71,7 @@ export class ServerlessSearchPlugin registerIndicesRoutes(dependencies); }); - pluginsSetup.ml.setFeaturesEnabled({ ad: false, dfa: false, nlp: false }); + pluginsSetup.ml.setFeaturesEnabled({ ad: false, dfa: false, nlp: true }); pluginsSetup.serverless.setupProjectSettings(SEARCH_PROJECT_SETTINGS); return {}; } diff --git a/x-pack/plugins/spaces/public/mocks.ts b/x-pack/plugins/spaces/public/mocks.ts index 9146a0aa2c99b..66b916e459cc5 100644 --- a/x-pack/plugins/spaces/public/mocks.ts +++ b/x-pack/plugins/spaces/public/mocks.ts @@ -15,6 +15,7 @@ const createApiMock = (): jest.Mocked<SpacesApi> => ({ getActiveSpace$: jest.fn().mockReturnValue(of()), getActiveSpace: jest.fn(), ui: createApiUiMock(), + hasOnlyDefaultSpace: false, }); type SpacesApiUiMock = Omit<jest.Mocked<SpacesApiUi>, 'components'> & { diff --git a/x-pack/plugins/spaces/public/plugin.test.ts b/x-pack/plugins/spaces/public/plugin.test.ts index 2e81e6c039668..a3a09db311b9c 100644 --- a/x-pack/plugins/spaces/public/plugin.test.ts +++ b/x-pack/plugins/spaces/public/plugin.test.ts @@ -149,4 +149,28 @@ describe('Spaces plugin', () => { expect(coreStart.chrome.navControls.registerLeft).not.toHaveBeenCalled(); }); }); + + it('determines hasOnlyDefaultSpace correctly when maxSpaces=1', () => { + const coreSetup = coreMock.createSetup(); + const coreStart = coreMock.createStart(); + + const plugin = new SpacesPlugin(coreMock.createPluginInitializerContext({ maxSpaces: 1 })); + const spacesSetup = plugin.setup(coreSetup, {}); + const spacesStart = plugin.start(coreStart); + + expect(spacesSetup.hasOnlyDefaultSpace).toBe(true); + expect(spacesStart.hasOnlyDefaultSpace).toBe(true); + }); + + it('determines hasOnlyDefaultSpace correctly when maxSpaces=1000', () => { + const coreSetup = coreMock.createSetup(); + const coreStart = coreMock.createStart(); + + const plugin = new SpacesPlugin(coreMock.createPluginInitializerContext({ maxSpaces: 1000 })); + const spacesSetup = plugin.setup(coreSetup, {}); + const spacesStart = plugin.start(coreStart); + + expect(spacesSetup.hasOnlyDefaultSpace).toBe(false); + expect(spacesStart.hasOnlyDefaultSpace).toBe(false); + }); }); diff --git a/x-pack/plugins/spaces/public/plugin.tsx b/x-pack/plugins/spaces/public/plugin.tsx index 28a54e7768f3e..02aad20bee27b 100644 --- a/x-pack/plugins/spaces/public/plugin.tsx +++ b/x-pack/plugins/spaces/public/plugin.tsx @@ -53,6 +53,8 @@ export class SpacesPlugin implements Plugin<SpacesPluginSetup, SpacesPluginStart } public setup(core: CoreSetup<PluginsStart, SpacesPluginStart>, plugins: PluginsSetup) { + const hasOnlyDefaultSpace = this.config.maxSpaces === 1; + this.spacesManager = new SpacesManager(core.http); this.spacesApi = { ui: getUiApi({ @@ -61,6 +63,7 @@ export class SpacesPlugin implements Plugin<SpacesPluginSetup, SpacesPluginStart }), getActiveSpace$: () => this.spacesManager.onActiveSpaceChange$, getActiveSpace: () => this.spacesManager.getActiveSpace(), + hasOnlyDefaultSpace, }; if (!this.isServerless) { @@ -85,7 +88,7 @@ export class SpacesPlugin implements Plugin<SpacesPluginSetup, SpacesPluginStart }); } - return {}; + return { hasOnlyDefaultSpace }; } public start(core: CoreStart) { diff --git a/x-pack/plugins/spaces/public/types.ts b/x-pack/plugins/spaces/public/types.ts index edde4ad4c8662..1ab253262c3c1 100644 --- a/x-pack/plugins/spaces/public/types.ts +++ b/x-pack/plugins/spaces/public/types.ts @@ -49,6 +49,13 @@ export interface SpacesApi { */ getActiveSpace(): Promise<Space>; + /** + * Determines whether Kibana supports multiple spaces or only the default space. + * + * When `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden. + */ + hasOnlyDefaultSpace: boolean; + /** * UI components and services to add spaces capabilities to an application. */ diff --git a/x-pack/plugins/spaces/server/mocks.ts b/x-pack/plugins/spaces/server/mocks.ts index 1824fa352012a..f43a8e82a6408 100644 --- a/x-pack/plugins/spaces/server/mocks.ts +++ b/x-pack/plugins/spaces/server/mocks.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { of } from 'rxjs'; + import { spacesClientServiceMock } from './spaces_client/spaces_client_service.mock'; import { spacesServiceMock } from './spaces_service/spaces_service.mock'; @@ -12,12 +14,14 @@ function createSetupMock() { return { spacesService: spacesServiceMock.createSetupContract(), spacesClient: spacesClientServiceMock.createSetup(), + hasOnlyDefaultSpace$: of(false), }; } function createStartMock() { return { spacesService: spacesServiceMock.createStartContract(), + hasOnlyDefaultSpace$: of(false), }; } diff --git a/x-pack/plugins/spaces/server/plugin.test.ts b/x-pack/plugins/spaces/server/plugin.test.ts index de448e962ad68..3ac505c6e2e9a 100644 --- a/x-pack/plugins/spaces/server/plugin.test.ts +++ b/x-pack/plugins/spaces/server/plugin.test.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { lastValueFrom } from 'rxjs'; + import type { CoreSetup } from '@kbn/core/server'; import { coreMock } from '@kbn/core/server/mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; @@ -26,6 +28,12 @@ describe('Spaces plugin', () => { const spacesSetup = plugin.setup(core, { features, licensing }); expect(spacesSetup).toMatchInlineSnapshot(` Object { + "hasOnlyDefaultSpace$": Observable { + "operator": [Function], + "source": Observable { + "_subscribe": [Function], + }, + }, "spacesClient": Object { "registerClientWrapper": [Function], "setClientRepositoryFactory": [Function], @@ -85,6 +93,12 @@ describe('Spaces plugin', () => { const spacesStart = plugin.start(coreStart); expect(spacesStart).toMatchInlineSnapshot(` Object { + "hasOnlyDefaultSpace$": Observable { + "operator": [Function], + "source": Observable { + "_subscribe": [Function], + }, + }, "spacesService": Object { "createSpacesClient": [Function], "getActiveSpace": [Function], @@ -97,4 +111,40 @@ describe('Spaces plugin', () => { `); }); }); + + it('determines hasOnlyDefaultSpace$ correctly when maxSpaces=1', async () => { + const initializerContext = coreMock.createPluginInitializerContext({ maxSpaces: 1 }); + const core = coreMock.createSetup() as CoreSetup<PluginsStart>; + const features = featuresPluginMock.createSetup(); + const licensing = licensingMock.createSetup(); + + const usageCollection = usageCollectionPluginMock.createSetupContract(); + + const plugin = new SpacesPlugin(initializerContext); + + const spacesSetup = plugin.setup(core, { features, licensing, usageCollection }); + const coreStart = coreMock.createStart(); + const spacesStart = plugin.start(coreStart); + + await expect(lastValueFrom(spacesSetup.hasOnlyDefaultSpace$)).resolves.toEqual(true); + await expect(lastValueFrom(spacesStart.hasOnlyDefaultSpace$)).resolves.toEqual(true); + }); + + it('determines hasOnlyDefaultSpace$ correctly when maxSpaces=1000', async () => { + const initializerContext = coreMock.createPluginInitializerContext({ maxSpaces: 1000 }); + const core = coreMock.createSetup() as CoreSetup<PluginsStart>; + const features = featuresPluginMock.createSetup(); + const licensing = licensingMock.createSetup(); + + const usageCollection = usageCollectionPluginMock.createSetupContract(); + + const plugin = new SpacesPlugin(initializerContext); + + const spacesSetup = plugin.setup(core, { features, licensing, usageCollection }); + const coreStart = coreMock.createStart(); + const spacesStart = plugin.start(coreStart); + + await expect(lastValueFrom(spacesSetup.hasOnlyDefaultSpace$)).resolves.toEqual(false); + await expect(lastValueFrom(spacesStart.hasOnlyDefaultSpace$)).resolves.toEqual(false); + }); }); diff --git a/x-pack/plugins/spaces/server/plugin.ts b/x-pack/plugins/spaces/server/plugin.ts index 893d3db22d709..9084a74e24265 100644 --- a/x-pack/plugins/spaces/server/plugin.ts +++ b/x-pack/plugins/spaces/server/plugin.ts @@ -6,6 +6,7 @@ */ import type { Observable } from 'rxjs'; +import { map } from 'rxjs'; import type { CoreSetup, @@ -76,6 +77,13 @@ export interface SpacesPluginSetup { */ registerClientWrapper: (wrapper: SpacesClientWrapper) => void; }; + + /** + * Determines whether Kibana supports multiple spaces or only the default space. + * + * When `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden. + */ + hasOnlyDefaultSpace$: Observable<boolean>; } /** @@ -84,6 +92,13 @@ export interface SpacesPluginSetup { export interface SpacesPluginStart { /** Service for interacting with spaces. */ spacesService: SpacesServiceStart; + + /** + * Determines whether Kibana supports multiple spaces or only the default space. + * + * When `xpack.spaces.maxSpaces` is set to 1 Kibana only supports the default space and any spaces related UI can safely be hidden. + */ + hasOnlyDefaultSpace$: Observable<boolean>; } export class SpacesPlugin @@ -99,12 +114,15 @@ export class SpacesPlugin private readonly spacesService: SpacesService; + private readonly hasOnlyDefaultSpace$: Observable<boolean>; + private spacesServiceStart?: SpacesServiceStart; private defaultSpaceService?: DefaultSpaceService; constructor(private readonly initializerContext: PluginInitializerContext) { this.config$ = initializerContext.config.create<ConfigType>(); + this.hasOnlyDefaultSpace$ = this.config$.pipe(map(({ maxSpaces }) => maxSpaces === 1)); this.log = initializerContext.logger.get(); this.spacesService = new SpacesService(); this.spacesClientService = new SpacesClientService((message) => this.log.debug(message)); @@ -195,6 +213,7 @@ export class SpacesPlugin return { spacesClient: spacesClientSetup, spacesService: spacesServiceSetup, + hasOnlyDefaultSpace$: this.hasOnlyDefaultSpace$, }; } @@ -208,6 +227,7 @@ export class SpacesPlugin return { spacesService: this.spacesServiceStart, + hasOnlyDefaultSpace$: this.hasOnlyDefaultSpace$, }; } diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.test.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.test.tsx index b9b8ba0dd38f7..025ac9deac732 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.test.tsx @@ -25,6 +25,7 @@ jest.mock('@kbn/text-based-editor', () => ({ fetchFieldsFromESQL: jest.fn(), })); const { fetchFieldsFromESQL } = jest.requireMock('@kbn/text-based-editor'); +const { getFields } = jest.requireMock('@kbn/triggers-actions-ui-plugin/public'); const AppWrapper: React.FC<{ children: React.ReactElement }> = React.memo(({ children }) => ( <I18nProvider>{children}</I18nProvider> @@ -133,6 +134,7 @@ describe('EsqlQueryRuleTypeExpression', () => { }, ], }); + getFields.mockResolvedValue([]); const result = render( <EsqlQueryExpression unifiedSearch={unifiedSearchMock} diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx index 5cc79bdf3503d..8f3edd45a1e28 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/esql_query_expression.tsx @@ -76,6 +76,11 @@ export const EsqlQueryExpression: React.FC< const setDefaultExpressionValues = async () => { setRuleProperty('params', currentRuleParams); setQuery(esqlQuery ?? { esql: '' }); + if (esqlQuery && 'esql' in esqlQuery) { + if (esqlQuery.esql) { + refreshTimeFields(esqlQuery); + } + } if (timeField) { setTimeFieldOptions([firstFieldOption, { text: timeField, value: timeField }]); } diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/query_form_type_chooser.tsx index 63d0b0d36fe53..0077a035d1e8d 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/expression/query_form_type_chooser.tsx @@ -7,6 +7,7 @@ import React, { useMemo } from 'react'; import { + EuiBetaBadge, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, @@ -21,6 +22,24 @@ import { i18n } from '@kbn/i18n'; import { SearchType } from '../types'; import { useTriggerUiActionServices } from '../util'; +export const ExperimentalBadge = React.memo(() => ( + <EuiBetaBadge + size="s" + label={i18n.translate('xpack.stackAlerts.esQuery.ui.selectQueryFormType.experimentalLabel', { + defaultMessage: 'Technical preview', + })} + tooltipContent={i18n.translate( + 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.experimentalDescription', + { + defaultMessage: + 'This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.', + } + )} + tooltipPosition="bottom" + /> +)); +ExperimentalBadge.displayName = 'ExperimentalBadge'; + export interface QueryFormTypeProps { searchType: SearchType | null; onFormTypeSelect: (formType: SearchType | null) => void; @@ -94,9 +113,18 @@ export const QueryFormTypeChooser: React.FC<QueryFormTypeProps> = ({ <> <EuiFlexGroup alignItems="center" gutterSize="s" responsive={false}> <EuiFlexItem> - <EuiTitle size="xs" data-test-subj="selectedRuleFormTypeTitle"> - <h5>{activeFormTypeItem?.label}</h5> - </EuiTitle> + <EuiFlexGroup alignItems="center" gutterSize="s"> + <EuiFlexItem grow={false}> + <EuiTitle size="xs" data-test-subj="selectedRuleFormTypeTitle"> + <h5>{activeFormTypeItem?.label}</h5> + </EuiTitle> + </EuiFlexItem> + {activeFormTypeItem?.formType === SearchType.esqlQuery && ( + <EuiFlexItem> + <ExperimentalBadge /> + </EuiFlexItem> + )} + </EuiFlexGroup> </EuiFlexItem> <EuiFlexItem grow={false}> <EuiButtonIcon @@ -140,7 +168,16 @@ export const QueryFormTypeChooser: React.FC<QueryFormTypeProps> = ({ color="primary" label={ <span> - <strong>{item.label}</strong> + <EuiFlexGroup alignItems="center" gutterSize="s"> + <EuiFlexItem grow={false}> + <strong>{item.label}</strong> + </EuiFlexItem> + {item.formType === SearchType.esqlQuery && ( + <EuiFlexItem> + <ExperimentalBadge /> + </EuiFlexItem> + )} + </EuiFlexGroup> <EuiText color="subdued" size="s"> <p>{item.description}</p> </EuiText> diff --git a/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts b/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts index 860976834076b..f82b89ee7c2b6 100644 --- a/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts +++ b/x-pack/plugins/stack_connectors/common/gen_ai/schema.ts @@ -60,8 +60,8 @@ export const GenAiRunActionResponseSchema = schema.object( }, { unknowns: 'ignore' } ), - finish_reason: schema.string(), - index: schema.number(), + finish_reason: schema.maybe(schema.string()), + index: schema.maybe(schema.number()), }, { unknowns: 'ignore' } ) diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor/index.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor/index.ts index 41daa9d2148ad..1aa698e715db2 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor/index.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/monitor/index.ts @@ -5,5 +5,4 @@ * 2.0. */ -export * from './locations'; export * from './state'; diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor/locations.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor/locations.ts deleted file mode 100644 index e37621c47ddf9..0000000000000 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor/locations.ts +++ /dev/null @@ -1,31 +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 * as t from 'io-ts'; -import { CheckGeoType, SummaryType } from '../common'; - -// IO type for validation -export const MonitorLocationType = t.type({ - up_history: t.number, - down_history: t.number, - timestamp: t.string, - summary: SummaryType, - geo: CheckGeoType, -}); - -// Typescript type for type checking -export type MonitorLocation = t.TypeOf<typeof MonitorLocationType>; - -export const MonitorLocationsType = t.intersection([ - t.type({ - monitorId: t.string, - up_history: t.number, - down_history: t.number, - }), - t.partial({ locations: t.array(MonitorLocationType) }), -]); -export type MonitorLocations = t.TypeOf<typeof MonitorLocationsType>; diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts index 99ce709c2672e..af2304acb9e24 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_types.ts @@ -46,6 +46,10 @@ export const TLSSensitiveFieldsCodec = t.partial({ export const TLSCodec = t.intersection([TLSFieldsCodec, TLSSensitiveFieldsCodec]); +const MonitorLocationsCodec = t.array(t.union([MonitorServiceLocationCodec, PrivateLocationCodec])); + +export type MonitorLocations = t.TypeOf<typeof MonitorLocationsCodec>; + // CommonFields export const CommonFieldsCodec = t.intersection([ t.interface({ @@ -56,7 +60,7 @@ export const CommonFieldsCodec = t.intersection([ [ConfigKey.SCHEDULE]: ScheduleCodec, [ConfigKey.APM_SERVICE_NAME]: t.string, [ConfigKey.TAGS]: t.array(t.string), - [ConfigKey.LOCATIONS]: t.array(t.union([MonitorServiceLocationCodec, PrivateLocationCodec])), + [ConfigKey.LOCATIONS]: MonitorLocationsCodec, [ConfigKey.MONITOR_QUERY_ID]: t.string, [ConfigKey.CONFIG_ID]: t.string, }), diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/permissions.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/permissions.tsx index 425a1f2ee0c60..f9dd560e4742e 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/permissions.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/permissions.tsx @@ -30,12 +30,14 @@ export const FleetPermissionsCallout = () => { */ export const NoPermissionsTooltip = ({ canEditSynthetics = true, + canUsePublicLocations = true, children, }: { canEditSynthetics?: boolean; + canUsePublicLocations?: boolean; children: ReactNode; }) => { - const disabledMessage = getRestrictionReasonLabel(canEditSynthetics); + const disabledMessage = getRestrictionReasonLabel(canEditSynthetics, canUsePublicLocations); if (disabledMessage) { return ( <EuiToolTip content={disabledMessage}> @@ -47,8 +49,16 @@ export const NoPermissionsTooltip = ({ return <>{children}</>; }; -function getRestrictionReasonLabel(canEditSynthetics = true): string | undefined { - return !canEditSynthetics ? CANNOT_PERFORM_ACTION_SYNTHETICS : undefined; +function getRestrictionReasonLabel( + canEditSynthetics = true, + canUsePublicLocations = true +): string | undefined { + const message = !canEditSynthetics ? CANNOT_PERFORM_ACTION_SYNTHETICS : undefined; + if (message) { + return message; + } + + return !canUsePublicLocations ? CANNOT_PERFORM_ACTION_PUBLIC_LOCATIONS : undefined; } export const NEED_PERMISSIONS_PRIVATE_LOCATIONS = i18n.translate( @@ -83,3 +93,10 @@ export const CANNOT_PERFORM_ACTION_SYNTHETICS = i18n.translate( defaultMessage: 'You do not have sufficient permissions to perform this action.', } ); + +export const CANNOT_PERFORM_ACTION_PUBLIC_LOCATIONS = i18n.translate( + 'xpack.synthetics.monitorManagement.canUsePublicLocations', + { + defaultMessage: 'You do not have sufficient permissions to use Elastic managed locations.', + } +); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx index 67c49f6030208..a7ab9c4e7d56f 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/field_config.tsx @@ -78,6 +78,7 @@ import { ResponseCheckJSON, ThrottlingConfig, RequestBodyCheck, + SourceType, } from '../types'; import { AlertConfigKey, ALLOWED_SCHEDULES_IN_MINUTES } from '../constants'; import { getDefaultFormFields } from './defaults'; @@ -404,8 +405,8 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({ props: ({ field, setValue, locations, trigger }) => { return { options: Object.values(locations).map((location) => ({ - label: locations?.find((loc) => location.id === loc.id)?.label || '', - id: location.id || '', + label: location.label, + id: location.id, isServiceManaged: location.isServiceManaged || false, isInvalid: location.isInvalid, disabled: location.isInvalid, @@ -417,7 +418,9 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({ : location.isServiceManaged ? 'default' : 'primary', - label: locations?.find((loc) => location.id === loc.id)?.label ?? location.id, + label: + (location.label || locations?.find((loc) => location.id === loc.id)?.label) ?? + location.id, id: location.id || '', isServiceManaged: location.isServiceManaged || false, })), @@ -483,66 +486,78 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({ helpText: i18n.translate('xpack.synthetics.monitorConfig.edit.enabled.label', { defaultMessage: `When disabled, the monitor doesn't run any tests. You can enable it at any time.`, }), - props: ({ setValue, field, trigger }): EuiSwitchProps => ({ - id: 'syntheticsMontiorConfigIsEnabled', - label: i18n.translate('xpack.synthetics.monitorConfig.enabled.label', { - defaultMessage: 'Enable Monitor', - }), - checked: field?.value || false, - onChange: async (event) => { - setValue(ConfigKey.ENABLED, !!event.target.checked); - await trigger(ConfigKey.ENABLED); - }, - 'data-test-subj': 'syntheticsEnableSwitch', - // enabled is an allowed field for read only - // isDisabled: readOnly, - }), + props: ({ setValue, field, trigger, formState }): EuiSwitchProps => { + const isProjectMonitor = + formState.defaultValues?.[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT; + return { + id: 'syntheticsMontiorConfigIsEnabled', + label: i18n.translate('xpack.synthetics.monitorConfig.enabled.label', { + defaultMessage: 'Enable Monitor', + }), + checked: field?.value || false, + onChange: async (event) => { + setValue(ConfigKey.ENABLED, !!event.target.checked); + await trigger(ConfigKey.ENABLED); + }, + 'data-test-subj': 'syntheticsEnableSwitch', + // enabled is an allowed field for read only + disabled: !isProjectMonitor && readOnly, + }; + }, }, [AlertConfigKey.STATUS_ENABLED]: { fieldKey: AlertConfigKey.STATUS_ENABLED, component: Switch, controlled: true, - props: ({ setValue, field, trigger }): EuiSwitchProps => ({ - id: 'syntheticsMonitorConfigIsAlertEnabled', - label: field?.value - ? i18n.translate('xpack.synthetics.monitorConfig.enabledAlerting.label', { - defaultMessage: 'Disable status alerts on this monitor', - }) - : i18n.translate('xpack.synthetics.monitorConfig.disabledAlerting.label', { - defaultMessage: 'Enable status alerts on this monitor', - }), - checked: field?.value || false, - onChange: async (event) => { - setValue(AlertConfigKey.STATUS_ENABLED, !!event.target.checked); - await trigger(AlertConfigKey.STATUS_ENABLED); - }, - 'data-test-subj': 'syntheticsAlertStatusSwitch', - // alert config is an allowed field for read only - // isDisabled: readOnly, - }), + props: ({ setValue, field, trigger, formState }): EuiSwitchProps => { + const isProjectMonitor = + formState.defaultValues?.[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT; + return { + id: 'syntheticsMonitorConfigIsAlertEnabled', + label: field?.value + ? i18n.translate('xpack.synthetics.monitorConfig.enabledAlerting.label', { + defaultMessage: 'Disable status alerts on this monitor', + }) + : i18n.translate('xpack.synthetics.monitorConfig.disabledAlerting.label', { + defaultMessage: 'Enable status alerts on this monitor', + }), + checked: field?.value || false, + onChange: async (event) => { + setValue(AlertConfigKey.STATUS_ENABLED, !!event.target.checked); + await trigger(AlertConfigKey.STATUS_ENABLED); + }, + 'data-test-subj': 'syntheticsAlertStatusSwitch', + // alert config is an allowed field for read only + disabled: !isProjectMonitor && readOnly, + }; + }, }, [AlertConfigKey.TLS_ENABLED]: { fieldKey: AlertConfigKey.TLS_ENABLED, component: Switch, controlled: true, - props: ({ setValue, field, trigger }): EuiSwitchProps => ({ - id: 'syntheticsMonitorConfigIsTlsAlertEnabled', - label: field?.value - ? i18n.translate('xpack.synthetics.monitorConfig.edit.alertTlsEnabled.label', { - defaultMessage: 'Disable TLS alerts on this monitor.', - }) - : i18n.translate('xpack.synthetics.monitorConfig.create.alertTlsEnabled.label', { - defaultMessage: 'Enable TLS alerts on this monitor.', - }), - checked: field?.value || false, - onChange: async (event) => { - setValue(AlertConfigKey.TLS_ENABLED, !!event.target.checked); - await trigger(AlertConfigKey.TLS_ENABLED); - }, - 'data-test-subj': 'syntheticsAlertStatusSwitch', - // alert config is an allowed field for read only - // isDisabled: readOnly, - }), + props: ({ setValue, field, trigger, formState }): EuiSwitchProps => { + const isProjectMonitor = + formState.defaultValues?.[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT; + return { + id: 'syntheticsMonitorConfigIsTlsAlertEnabled', + label: field?.value + ? i18n.translate('xpack.synthetics.monitorConfig.edit.alertTlsEnabled.label', { + defaultMessage: 'Disable TLS alerts on this monitor.', + }) + : i18n.translate('xpack.synthetics.monitorConfig.create.alertTlsEnabled.label', { + defaultMessage: 'Enable TLS alerts on this monitor.', + }), + checked: field?.value || false, + onChange: async (event) => { + setValue(AlertConfigKey.TLS_ENABLED, !!event.target.checked); + await trigger(AlertConfigKey.TLS_ENABLED); + }, + 'data-test-subj': 'syntheticsAlertStatusSwitch', + // alert config is an allowed field for read only + disabled: !isProjectMonitor && readOnly, + }; + }, }, [ConfigKey.TAGS]: { fieldKey: ConfigKey.TAGS, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/index.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/index.tsx index 33c8ec03e5ff9..bfd7ac5149a88 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/index.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/index.tsx @@ -18,7 +18,8 @@ export const MonitorForm: React.FC<{ defaultValues?: SyntheticsMonitor; space?: string; readOnly?: boolean; -}> = ({ children, defaultValues, space, readOnly = false }) => { + canUsePublicLocations: boolean; +}> = ({ children, defaultValues, space, readOnly = false, canUsePublicLocations }) => { const methods = useFormWrapped({ mode: 'onSubmit', reValidateMode: 'onSubmit', @@ -43,7 +44,7 @@ export const MonitorForm: React.FC<{ > {children} <EuiSpacer /> - <ActionBar readOnly={readOnly} /> + <ActionBar readOnly={readOnly} canUsePublicLocations={canUsePublicLocations} /> </EuiForm> <Disclaimer /> </FormProvider> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/run_test_btn.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/run_test_btn.tsx index 4b73d71b90b09..316e57e4a5065 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/run_test_btn.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/run_test_btn.tsx @@ -16,7 +16,11 @@ import { format } from './formatter'; import { MonitorFields as MonitorFieldsType } from '../../../../../../common/runtime_types'; import { runOnceMonitor } from '../../../state/manual_test_runs/api'; -export const RunTestButton = () => { +export const RunTestButton = ({ + canUsePublicLocations = true, +}: { + canUsePublicLocations?: boolean; +}) => { const { formState, getValues, handleSubmit } = useFormContext(); const [inProgress, setInProgress] = useState(false); @@ -56,7 +60,7 @@ export const RunTestButton = () => { <EuiButton data-test-subj="syntheticsRunTestBtn" color="success" - disabled={isDisabled} + disabled={isDisabled || !canUsePublicLocations} aria-label={TEST_NOW_ARIA_LABEL} iconType="play" onClick={handleSubmit(handleTestNow)} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/submit.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/submit.tsx index 749b9b041519a..4a8cca5410baa 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/submit.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/form/submit.tsx @@ -21,7 +21,13 @@ import { format } from './formatter'; import { MONITORS_ROUTE } from '../../../../../../common/constants'; -export const ActionBar = ({ readOnly = false }: { readOnly: boolean }) => { +export const ActionBar = ({ + readOnly = false, + canUsePublicLocations = true, +}: { + readOnly: boolean; + canUsePublicLocations: boolean; +}) => { const { monitorId } = useParams<{ monitorId: string }>(); const history = useHistory(); const { @@ -59,6 +65,7 @@ export const ActionBar = ({ readOnly = false }: { readOnly: boolean }) => { onClick={() => { setMonitorPendingDeletion(defaultValues as SyntheticsMonitor); }} + isDisabled={!canEditSynthetics || !canUsePublicLocations} > {DELETE_MONITOR_LABEL} </EuiButton> @@ -75,16 +82,19 @@ export const ActionBar = ({ readOnly = false }: { readOnly: boolean }) => { </EuiLink> </EuiFlexItem> <EuiFlexItem grow={false}> - <RunTestButton /> + <RunTestButton canUsePublicLocations={canUsePublicLocations} /> </EuiFlexItem> <EuiFlexItem grow={false} css={{ marginLeft: 'auto' }}> - <NoPermissionsTooltip canEditSynthetics={canEditSynthetics}> + <NoPermissionsTooltip + canEditSynthetics={canEditSynthetics} + canUsePublicLocations={canUsePublicLocations} + > <EuiButton fill isLoading={loading} onClick={handleSubmit(formSubmitter)} data-test-subj="syntheticsMonitorConfigSubmitButton" - disabled={!canEditSynthetics} + disabled={!canEditSynthetics || !canUsePublicLocations} > {isEdit ? UPDATE_MONITOR_LABEL : CREATE_MONITOR_LABEL} </EuiButton> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/monitor_edit_page.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/monitor_edit_page.tsx index 69b53c24d4cbc..16573ce19f57a 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/monitor_edit_page.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/monitor_edit_page.tsx @@ -12,6 +12,7 @@ import { EuiEmptyPrompt } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useTrackPageview, useFetcher } from '@kbn/observability-shared-plugin/public'; import { IHttpFetchError, ResponseErrorBody } from '@kbn/core-http-browser'; +import { useCanUsePublicLocations } from '../../../../hooks/use_capabilities'; import { EditMonitorNotFound } from './edit_monitor_not_found'; import { LoadingState } from '../monitors_page/overview/overview/monitor_detail_flyout'; import { ConfigKey, SourceType } from '../../../../../common/runtime_types'; @@ -50,11 +51,15 @@ export const MonitorEditPage: React.FC = () => { data?.id ); + const canUsePublicLocations = useCanUsePublicLocations(data?.[ConfigKey.LOCATIONS]); + if (monitorNotFoundError) { return <EditMonitorNotFound />; } - const isReadOnly = data?.[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT; + const isReadOnly = + data?.[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT || !canUsePublicLocations; + const projectId = data?.[ConfigKey.PROJECT_ID]; if (locationsError) { @@ -87,8 +92,13 @@ export const MonitorEditPage: React.FC = () => { return data && locationsLoaded && !loading && !error ? ( <> <AlertingCallout isAlertingEnabled={data[ConfigKey.ALERT_CONFIG]?.status?.enabled} /> - <MonitorForm defaultValues={data} readOnly={isReadOnly}> + <MonitorForm + defaultValues={data} + readOnly={isReadOnly} + canUsePublicLocations={canUsePublicLocations} + > <MonitorSteps + canUsePublicLocations={canUsePublicLocations} stepMap={EDIT_MONITOR_STEPS(isReadOnly)} isEditFlow={true} readOnly={isReadOnly} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/index.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/index.tsx index ecfd00b23d76e..94f681f0fd411 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/index.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/index.tsx @@ -16,6 +16,7 @@ import { MonitorTypePortal } from './monitor_type_portal'; import { ReadOnlyCallout } from './read_only_callout'; export const MonitorSteps = ({ + canUsePublicLocations, stepMap, projectId, isEditFlow = false, @@ -23,6 +24,7 @@ export const MonitorSteps = ({ }: { stepMap: StepMap; readOnly?: boolean; + canUsePublicLocations?: boolean; isEditFlow?: boolean; projectId?: string; }) => { @@ -32,12 +34,9 @@ export const MonitorSteps = ({ return ( <> - {readOnly ? ( - <> - <ReadOnlyCallout projectId={projectId} /> - <EuiSpacer size="m" /> - </> - ) : null} + {isEditFlow && ( + <ReadOnlyCallout projectId={projectId} canUsePublicLocations={canUsePublicLocations} /> + )} {isEditFlow ? ( steps.map((step) => ( <div key={step.title}> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/read_only_callout.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/read_only_callout.tsx index d20453be1c2ed..6f6f4533bb7dc 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/read_only_callout.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/steps/read_only_callout.tsx @@ -5,27 +5,65 @@ * 2.0. */ import React from 'react'; -import { EuiCallOut } from '@elastic/eui'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -export const ReadOnlyCallout = ({ projectId }: { projectId?: string }) => { - return ( - <EuiCallOut - title={ - <FormattedMessage - id="xpack.synthetics.project.readOnly.callout.title" - defaultMessage="This configuration is read-only" - /> - } - iconType="document" - > - <p> - <FormattedMessage - id="xpack.synthetics.project.readOnly.callout.content" - defaultMessage="This monitor was added from an external project: {projectId}. From this page, you can only enable and disable the monitor and its alerts, or remove it. To make configuration changes, you have to edit its source file and push it again from that project." - values={{ projectId: <strong>{projectId}</strong> }} - /> - </p> - </EuiCallOut> - ); +export const ReadOnlyCallout = ({ + projectId, + canUsePublicLocations, +}: { + projectId?: string; + canUsePublicLocations?: boolean; +}) => { + if (projectId) { + return ( + <> + <EuiCallOut + title={ + <FormattedMessage + id="xpack.synthetics.project.readOnly.callout.title" + defaultMessage="This configuration is read-only" + /> + } + iconType="document" + > + <p> + <FormattedMessage + id="xpack.synthetics.project.readOnly.callout.content" + defaultMessage="This monitor was added from an external project: {projectId}. From this page, you can only enable and disable the monitor and its alerts, or remove it. To make configuration changes, you have to edit its source file and push it again from that project." + values={{ projectId: <strong>{projectId}</strong> }} + /> + </p> + </EuiCallOut> + <EuiSpacer size="m" /> + </> + ); + } + + if (!canUsePublicLocations) { + return ( + <> + <EuiCallOut + color="warning" + title={ + <FormattedMessage + id="xpack.synthetics.publicLocations.readOnly.callout.title" + defaultMessage="You do not have permission to use Elastic managed locations" + /> + } + iconType="alert" + > + <p> + <FormattedMessage + id="xpack.synthetics.publicLocations.readOnly.callout.content" + defaultMessage="This monitor contains a Elastic managed location. To edit this monitor, you need to have permission to use Elastic managed locations." + /> + </p> + </EuiCallOut> + <EuiSpacer size="m" /> + </> + ); + } + + return null; }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_location.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_location.tsx index df9785bb9b98c..eabea42a34162 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_location.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_selected_location.tsx @@ -7,6 +7,7 @@ import { useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import { ServiceLocation } from '../../../../../../common/runtime_types'; import { useSelectedMonitor } from './use_selected_monitor'; import { selectSelectedLocationId, setMonitorDetailsLocationAction } from '../../../state'; import { useUrlParams, useLocations } from '../../../hooks'; @@ -41,8 +42,12 @@ export const useSelectedLocation = (updateUrl = true) => { monitor?.locations, ]); - return useMemo( - () => locations.find((loc) => loc.id === urlLocationId) ?? null, - [urlLocationId, locations] - ); + return useMemo(() => { + let selLoc = locations.find((loc) => loc.id === urlLocationId) ?? null; + if (!selLoc) { + selLoc = + (monitor?.locations?.find((loc) => loc.id === urlLocationId) as ServiceLocation) ?? null; + } + return selLoc; + }, [locations, urlLocationId, monitor?.locations]); }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/run_test_manually.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/run_test_manually.tsx index 55fb54dd0d0dc..a05bea3f7925e 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/run_test_manually.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/run_test_manually.tsx @@ -9,6 +9,9 @@ import { EuiButton, EuiToolTip } from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; import { useDispatch, useSelector } from 'react-redux'; +import { CANNOT_PERFORM_ACTION_PUBLIC_LOCATIONS } from '../common/components/permissions'; +import { useCanUsePublicLocations } from '../../../../hooks/use_capabilities'; +import { ConfigKey } from '../../../../../common/constants/monitor_management'; import { TEST_NOW_ARIA_LABEL, TEST_SCHEDULED_LABEL } from '../monitor_add_edit/form/run_test_btn'; import { useSelectedMonitor } from './hooks/use_selected_monitor'; import { @@ -22,7 +25,13 @@ export const RunTestManually = () => { const { monitor } = useSelectedMonitor(); const testInProgress = useSelector(manualTestRunInProgressSelector(monitor?.config_id)); - const content = testInProgress ? TEST_SCHEDULED_LABEL : TEST_NOW_ARIA_LABEL; + const canUsePublicLocations = useCanUsePublicLocations(monitor?.[ConfigKey.LOCATIONS]); + + const content = !canUsePublicLocations + ? CANNOT_PERFORM_ACTION_PUBLIC_LOCATIONS + : testInProgress + ? TEST_SCHEDULED_LABEL + : TEST_NOW_ARIA_LABEL; return ( <EuiToolTip content={content} key={content}> @@ -31,6 +40,7 @@ export const RunTestManually = () => { color="success" iconType="beaker" isLoading={!Boolean(monitor) || testInProgress} + isDisabled={!canUsePublicLocations} onClick={() => { if (monitor) { dispatch( diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_can_use_public_loc_id.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_can_use_public_loc_id.ts new file mode 100644 index 0000000000000..16842a401dc46 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_can_use_public_loc_id.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 { useSelector } from 'react-redux'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { selectOverviewState } from '../../../state'; + +export const useCanUsePublicLocById = (configId: string) => { + const { + data: { monitors }, + } = useSelector(selectOverviewState); + + const hasManagedLocation = monitors?.filter( + (mon) => mon.configId === configId && mon.location.isServiceManaged + ); + + const canUsePublicLocations = + useKibana().services?.application?.capabilities.uptime.elasticManagedLocationsEnabled ?? true; + + return hasManagedLocation ? !!canUsePublicLocations : true; +}; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx index 0c415ce3d4fb8..6d9c97df97d52 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/columns.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { useHistory } from 'react-router-dom'; import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useCanEditSynthetics } from '../../../../../../hooks/use_capabilities'; import { isStatusEnabled, @@ -55,6 +56,15 @@ export function useMonitorListColumns({ return alertStatus(fields[ConfigKey.CONFIG_ID]) === FETCH_STATUS.LOADING; }; + const canUsePublicLocations = + useKibana().services?.application?.capabilities.uptime.elasticManagedLocationsEnabled ?? true; + + const isPublicLocationsAllowed = (fields: EncryptedSyntheticsSavedMonitor) => { + const publicLocations = fields.locations.some((loc) => loc.isServiceManaged); + + return publicLocations ? Boolean(canUsePublicLocations) : true; + }; + const columns: Array<EuiBasicTableColumn<EncryptedSyntheticsSavedMonitor>> = [ { align: 'left' as const, @@ -166,14 +176,18 @@ export function useMonitorListColumns({ 'data-test-subj': 'syntheticsMonitorEditAction', isPrimary: true, name: (fields) => ( - <NoPermissionsTooltip canEditSynthetics={canEditSynthetics}> + <NoPermissionsTooltip + canEditSynthetics={canEditSynthetics} + canUsePublicLocations={isPublicLocationsAllowed(fields)} + > {labels.EDIT_LABEL} </NoPermissionsTooltip> ), description: labels.EDIT_LABEL, icon: 'pencil' as const, type: 'icon' as const, - enabled: (fields) => canEditSynthetics && !isActionLoading(fields), + enabled: (fields) => + canEditSynthetics && !isActionLoading(fields) && isPublicLocationsAllowed(fields), onClick: (fields) => { history.push({ pathname: `/edit-monitor/${fields[ConfigKey.CONFIG_ID]}`, @@ -184,7 +198,10 @@ export function useMonitorListColumns({ 'data-test-subj': 'syntheticsMonitorDeleteAction', isPrimary: true, name: (fields) => ( - <NoPermissionsTooltip canEditSynthetics={canEditSynthetics}> + <NoPermissionsTooltip + canEditSynthetics={canEditSynthetics} + canUsePublicLocations={isPublicLocationsAllowed(fields)} + > {labels.DELETE_LABEL} </NoPermissionsTooltip> ), @@ -192,7 +209,8 @@ export function useMonitorListColumns({ icon: 'trash' as const, type: 'icon' as const, color: 'danger' as const, - enabled: (fields) => canEditSynthetics && !isActionLoading(fields), + enabled: (fields) => + canEditSynthetics && !isActionLoading(fields) && isPublicLocationsAllowed(fields), onClick: (fields) => { setMonitorPendingDeletion(fields); }, @@ -207,7 +225,8 @@ export function useMonitorListColumns({ isStatusEnabled(fields[ConfigKey.ALERT_CONFIG]) ? 'bellSlash' : 'bell', type: 'icon' as const, color: 'danger' as const, - enabled: (fields) => canEditSynthetics && !isActionLoading(fields), + enabled: (fields) => + canEditSynthetics && !isActionLoading(fields) && isPublicLocationsAllowed(fields), onClick: (fields) => { updateAlertEnabledState({ monitor: { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx index c875b923a15c7..29555c0cf1e90 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_enabled.tsx @@ -10,7 +10,10 @@ import { EuiSwitch, EuiSwitchEvent, EuiLoadingSpinner } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; import { ConfigKey, EncryptedSyntheticsMonitor } from '../../../../../../../common/runtime_types'; -import { useCanEditSynthetics } from '../../../../../../hooks/use_capabilities'; +import { + useCanEditSynthetics, + useCanUsePublicLocations, +} from '../../../../../../hooks/use_capabilities'; import { useMonitorEnableHandler } from '../../../../hooks'; import { NoPermissionsTooltip } from '../../../common/components/permissions'; import * as labels from './labels'; @@ -32,6 +35,8 @@ export const MonitorEnabled = ({ }: Props) => { const canEditSynthetics = useCanEditSynthetics(); + const canUsePublicLocations = useCanUsePublicLocations(monitor?.[ConfigKey.LOCATIONS]); + const monitorName = monitor[ConfigKey.NAME]; const statusLabels = useMemo(() => { return { @@ -63,11 +68,14 @@ export const MonitorEnabled = ({ {isLoading || initialLoading ? ( <EuiLoadingSpinner size="m" /> ) : ( - <NoPermissionsTooltip canEditSynthetics={canEditSynthetics}> + <NoPermissionsTooltip + canEditSynthetics={canEditSynthetics} + canUsePublicLocations={canUsePublicLocations} + > <SwitchWithCursor compressed={true} checked={enabled} - disabled={isLoading || !canEditSynthetics} + disabled={isLoading || !canEditSynthetics || !canUsePublicLocations} showLabel={false} label={enabledDisableLabel} title={enabledDisableLabel} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_locations.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_locations.tsx index 421385b04da2b..5495a763e9ff7 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_locations.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/management/monitor_list_table/monitor_locations.tsx @@ -23,12 +23,19 @@ export const MonitorLocations = ({ locations, monitorId, status }: Props) => { const locationsToDisplay = locations .map((loc) => { + if (loc.label) { + return { + id: loc.id, + label: loc.label, + ...getLocationStatusColor(theme, loc.id, monitorId, status), + }; + } const fullLoc = allLocations.find((l) => l.id === loc.id); if (fullLoc) { return { id: fullLoc.id, label: fullLoc.label, - ...getLocationStatusColor(theme, fullLoc.label, monitorId, status), + ...getLocationStatusColor(theme, fullLoc.id, monitorId, status), }; } }) @@ -41,7 +48,7 @@ export const MonitorLocations = ({ locations, monitorId, status }: Props) => { function getLocationStatusColor( euiTheme: ReturnType<typeof useTheme>, - locationLabel: string | undefined, + locationId: string, monitorId: string, overviewStatus: OverviewStatusState | null ) { @@ -49,7 +56,7 @@ function getLocationStatusColor( eui: { euiColorVis9, euiColorVis0, euiColorDisabled }, } = euiTheme; - const locById = `${monitorId}-${locationLabel}`; + const locById = `${monitorId}-${locationId}`; if (overviewStatus?.downConfigs[locById]) { return { status: 'down', color: euiColorVis9 }; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx index ad3c29a0f77bf..55dcdb3d06341 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx @@ -14,10 +14,13 @@ import { EuiPanel, EuiLoadingSpinner, EuiContextMenuPanelItemDescriptor, + EuiToolTip, } from '@elastic/eui'; import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; +import { TEST_SCHEDULED_LABEL } from '../../../monitor_add_edit/form/run_test_btn'; +import { useCanUsePublicLocById } from '../../hooks/use_can_use_public_loc_id'; import { toggleStatusAlert } from '../../../../../../../common/runtime_types/monitor_management/alert_config'; import { manualTestMonitorAction, @@ -101,8 +104,7 @@ export function ActionsPopover({ }: Props) { const euiShadow = useEuiShadow('l'); const dispatch = useDispatch(); - const location = useLocationName({ locationId }); - const locationName = location?.label || monitor.location.id; + const locationName = useLocationName(monitor); const detailUrl = useMonitorDetailLocator({ configId: monitor.configId, @@ -112,6 +114,8 @@ export function ActionsPopover({ const canEditSynthetics = useCanEditSynthetics(); + const canUsePublicLocations = useCanUsePublicLocById(monitor.configId); + const labels = useMemo( () => ({ enabledSuccessLabel: enabledSuccessLabel(monitor.name), @@ -163,7 +167,6 @@ export function ActionsPopover({ }; const alertLoading = alertStatus(monitor.configId) === FETCH_STATUS.LOADING; - let popoverItems: EuiContextMenuPanelItemDescriptor[] = [ { name: actionsMenuGoToMonitorName, @@ -172,9 +175,17 @@ export function ActionsPopover({ }, quickInspectPopoverItem, { - name: runTestManually, + name: testInProgress ? ( + <EuiToolTip content={TEST_SCHEDULED_LABEL}> + <span>{runTestManually}</span> + </EuiToolTip> + ) : ( + <NoPermissionsTooltip canUsePublicLocations={canUsePublicLocations}> + {runTestManually} + </NoPermissionsTooltip> + ), icon: 'beaker', - disabled: testInProgress, + disabled: testInProgress || !canUsePublicLocations, onClick: () => { dispatch(manualTestMonitorAction.get({ configId: monitor.configId, name: monitor.name })); dispatch(setFlyoutConfig(null)); @@ -193,12 +204,15 @@ export function ActionsPopover({ }, { name: ( - <NoPermissionsTooltip canEditSynthetics={canEditSynthetics}> + <NoPermissionsTooltip + canEditSynthetics={canEditSynthetics} + canUsePublicLocations={canUsePublicLocations} + > {enableLabel} </NoPermissionsTooltip> ), icon: 'invert', - disabled: !canEditSynthetics, + disabled: !canEditSynthetics || !canUsePublicLocations, onClick: () => { if (status !== FETCH_STATUS.LOADING) { updateMonitorEnabledState(!monitor.isEnabled); @@ -207,11 +221,14 @@ export function ActionsPopover({ }, { name: ( - <NoPermissionsTooltip canEditSynthetics={canEditSynthetics}> + <NoPermissionsTooltip + canEditSynthetics={canEditSynthetics} + canUsePublicLocations={canUsePublicLocations} + > {monitor.isStatusAlertEnabled ? disableAlertLabel : enableMonitorAlertLabel} </NoPermissionsTooltip> ), - disabled: !canEditSynthetics, + disabled: !canEditSynthetics || !canUsePublicLocations, icon: alertLoading ? ( <EuiLoadingSpinner size="s" /> ) : monitor.isStatusAlertEnabled ? ( diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx index ce6de294d7e60..8cd43387cf710 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx @@ -64,8 +64,7 @@ export const MetricItem = ({ const [isMouseOver, setIsMouseOver] = useState(false); const [isPopoverOpen, setIsPopoverOpen] = useState(false); const isErrorPopoverOpen = useSelector(selectErrorPopoverState); - const locationName = - useLocationName({ locationId: monitor.location.id })?.label || monitor.location?.id; + const locationName = useLocationName(monitor); const { status, timestamp, ping, configIdByLocation } = useStatusByLocationOverview( monitor.configId, monitor.location.id diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid_item.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid_item.tsx index 3fb27e202f996..501fcb4a4136f 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid_item.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid_item.tsx @@ -27,8 +27,7 @@ export const OverviewGridItem = ({ monitor: MonitorOverviewItem; onClick: (params: FlyoutParamProps) => void; }) => { - const locationName = - useLocationName({ locationId: monitor.location?.id })?.label || monitor.location?.id; + const locationName = useLocationName(monitor); const { timestamp } = useStatusByLocationOverview(monitor.configId, locationName); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx index d03b70d94768c..f798880608bcc 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import { useLocationName } from './use_location_name'; import { WrappedHelper } from '../utils/testing'; +import { MonitorOverviewItem } from '../../../../common/runtime_types'; describe('useLocationName', () => { beforeEach(() => { @@ -47,16 +48,11 @@ describe('useLocationName', () => { const { result } = renderHook( () => useLocationName({ - locationId: 'us_central', - }), + location: { id: 'us_central' }, + } as MonitorOverviewItem), { wrapper: WrapperWithState } ); - expect(result.current).toEqual({ - id: 'us_central', - isServiceManaged: true, - label: 'US Central', - url: 'mockUrl', - }); + expect(result.current).toEqual('US Central'); }); it('returns the location id if matching location cannot be found', () => { @@ -92,10 +88,10 @@ describe('useLocationName', () => { const { result } = renderHook( () => useLocationName({ - locationId: 'us_west', - }), + location: { id: 'us_west' }, + } as MonitorOverviewItem), { wrapper: WrapperWithState } ); - expect(result.current).toEqual(undefined); + expect(result.current).toEqual('us_west'); }); }); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.tsx index 31782083541e2..b25112b15bb10 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_location_name.tsx @@ -7,9 +7,10 @@ import { useMemo, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; +import { MonitorOverviewItem } from '../../../../common/runtime_types'; import { selectServiceLocationsState, getServiceLocations } from '../state'; -export function useLocationName({ locationId }: { locationId: string }) { +export function useLocationName(monitor: MonitorOverviewItem) { const dispatch = useDispatch(); const { locationsLoaded, locations } = useSelector(selectServiceLocationsState); useEffect(() => { @@ -17,12 +18,14 @@ export function useLocationName({ locationId }: { locationId: string }) { dispatch(getServiceLocations()); } }); + const locationId = monitor?.location.id; return useMemo(() => { - if (!locationsLoaded) { - return undefined; + if (!locationsLoaded || monitor.location.label) { + return monitor.location.label ?? monitor.location.id; } else { - return locations.find((location) => location.id === locationId); + const location = locations.find((loc) => loc.id === locationId); + return location?.label ?? (monitor.location.label || monitor.location.id); } - }, [locationsLoaded, locations, locationId]); + }, [locationsLoaded, locations, locationId, monitor]); } diff --git a/x-pack/plugins/synthetics/public/hooks/use_capabilities.ts b/x-pack/plugins/synthetics/public/hooks/use_capabilities.ts index 5cde14df84f0e..082f9d9450d7c 100644 --- a/x-pack/plugins/synthetics/public/hooks/use_capabilities.ts +++ b/x-pack/plugins/synthetics/public/hooks/use_capabilities.ts @@ -6,7 +6,20 @@ */ import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { MonitorLocations } from '../../common/runtime_types'; export const useCanEditSynthetics = () => { return !!useKibana().services?.application?.capabilities.uptime.save; }; + +export const useCanUsePublicLocations = (monLocations?: MonitorLocations) => { + const canUsePublicLocations = + useKibana().services?.application?.capabilities.uptime.elasticManagedLocationsEnabled ?? true; + const publicLocations = monLocations?.some((loc) => loc.isServiceManaged); + + if (!publicLocations) { + return true; + } + + return !!canUsePublicLocations; +}; diff --git a/x-pack/plugins/synthetics/server/feature.ts b/x-pack/plugins/synthetics/server/feature.ts index 36a5888928680..1a19baa01dcbe 100644 --- a/x-pack/plugins/synthetics/server/feature.ts +++ b/x-pack/plugins/synthetics/server/feature.ts @@ -7,6 +7,11 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { OBSERVABILITY_THRESHOLD_RULE_TYPE_ID } from '@kbn/observability-plugin/common/constants'; +import { i18n } from '@kbn/i18n'; +import { + SubFeaturePrivilegeGroupConfig, + SubFeaturePrivilegeGroupType, +} from '@kbn/features-plugin/common'; import { syntheticsMonitorType, syntheticsParamType } from '../common/types/saved_objects'; import { SYNTHETICS_RULE_TYPES } from '../common/constants/synthetics_alerts'; import { privateLocationsSavedObjectName } from '../common/saved_objects/private_locations'; @@ -27,6 +32,24 @@ const ruleTypes = [ OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, ]; +const elasticManagedLocationsEnabledPrivilege: SubFeaturePrivilegeGroupConfig = { + groupType: 'independent' as SubFeaturePrivilegeGroupType, + privileges: [ + { + id: 'elastic_managed_locations_enabled', + name: i18n.translate('xpack.synthetics.features.elasticManagedLocations', { + defaultMessage: 'Elastic managed locations enabled', + }), + includeIn: 'all', + savedObject: { + all: [], + read: [], + }, + ui: ['elasticManagedLocationsEnabled'], + }, + ], +}; + export const uptimeFeature = { id: PLUGIN.ID, name: PLUGIN.NAME, @@ -94,4 +117,12 @@ export const uptimeFeature = { ui: ['show', 'alerting:save'], }, }, + subFeatures: [ + { + name: i18n.translate('xpack.synthetics.features.app', { + defaultMessage: 'Synthetics', + }), + privilegeGroups: [elasticManagedLocationsEnabledPrivilege], + }, + ], }; diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/delete_monitor.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/delete_monitor.ts index 4841ca581c077..0d5825dbbdd3f 100644 --- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/delete_monitor.ts +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/delete_monitor.ts @@ -6,6 +6,7 @@ */ import { schema } from '@kbn/config-schema'; import { SavedObjectsClientContract, SavedObjectsErrorHelpers } from '@kbn/core/server'; +import { validatePermissions } from './edit_monitor'; import { SyntheticsServerSetup } from '../../types'; import { RouteContext, SyntheticsRestApiRouteFactory } from '../types'; import { syntheticsMonitorType } from '../../../common/types/saved_objects'; @@ -39,10 +40,13 @@ export const deleteSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => const { monitorId } = request.params; try { - const errors = await deleteMonitor({ + const { errors, res } = await deleteMonitor({ routeContext, monitorId, }); + if (res) { + return res; + } if (errors && errors.length > 0) { return response.ok({ @@ -68,7 +72,7 @@ export const deleteMonitor = async ({ routeContext: RouteContext; monitorId: string; }) => { - const { spaceId, savedObjectsClient, server, syntheticsMonitorClient } = routeContext; + const { response, spaceId, savedObjectsClient, server, syntheticsMonitorClient } = routeContext; const { logger, telemetry, stackVersion } = server; const { monitor, monitorWithSecret } = await getMonitorToDelete( @@ -78,6 +82,17 @@ export const deleteMonitor = async ({ spaceId ); + const err = await validatePermissions(routeContext, monitor.attributes.locations); + if (err) { + return { + res: response.forbidden({ + body: { + message: err, + }, + }), + }; + } + let deletePromise; try { @@ -113,7 +128,7 @@ export const deleteMonitor = async ({ ) ); - return errors; + return { errors }; } catch (e) { if (deletePromise) { await deletePromise; diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts index d99261b49f2cf..69960d458c684 100644 --- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/edit_monitor.ts @@ -8,6 +8,7 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsUpdateResponse, SavedObject } from '@kbn/core/server'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { getDecryptedMonitor } from '../../saved_objects/synthetics_monitor'; import { getPrivateLocations } from '../../synthetics_service/get_private_locations'; import { mergeSourceMonitor } from './helper'; import { RouteContext, SyntheticsRestApiRouteFactory } from '../types'; @@ -18,6 +19,7 @@ import { SyntheticsMonitorWithSecretsAttributes, SyntheticsMonitor, ConfigKey, + MonitorLocations, } from '../../../common/runtime_types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; import { validateMonitor } from './monitor_validation'; @@ -39,10 +41,10 @@ export const editSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ( }), body: schema.any(), }, + writeAccess: true, handler: async (routeContext): Promise<any> => { const { request, response, savedObjectsClient, server } = routeContext; - const { encryptedSavedObjects, logger } = server; - const encryptedSavedObjectsClient = encryptedSavedObjects.getClient(); + const { logger } = server; const monitor = request.body as SyntheticsMonitor; const { monitorId } = request.params; @@ -55,14 +57,11 @@ export const editSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ( /* Decrypting the previous monitor before editing ensures that all existing fields remain * on the object, even in flows where decryption does not take place, such as the enabled tab * on the monitor list table. We do not decrypt monitors in bulk for the monitor list table */ - const decryptedPreviousMonitor = - await encryptedSavedObjectsClient.getDecryptedAsInternalUser<SyntheticsMonitorWithSecretsAttributes>( - syntheticsMonitorType, - monitorId, - { - namespace: previousMonitor.namespaces?.[0], - } - ); + const decryptedPreviousMonitor = await getDecryptedMonitor( + server, + monitorId, + previousMonitor.namespaces?.[0]! + ); const normalizedPreviousMonitor = normalizeSecrets(decryptedPreviousMonitor).attributes; const editedMonitor = mergeSourceMonitor(normalizedPreviousMonitor, monitor); @@ -74,6 +73,15 @@ export const editSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ( return response.badRequest({ body: { message, attributes: { details, ...payload } } }); } + const err = await validatePermissions(routeContext, editedMonitor.locations); + if (err) { + return response.forbidden({ + body: { + message: err, + }, + }); + } + const monitorWithRevision = { ...validationResult.decodedMonitor, /* reset config hash to empty string. Ensures that the synthetics agent is able @@ -230,3 +238,22 @@ export const syncEditedMonitor = async ({ throw e; } }; + +export const validatePermissions = async ( + { server, response, request }: RouteContext, + monitorLocations: MonitorLocations +) => { + const hasPublicLocations = monitorLocations?.some((loc) => loc.isServiceManaged); + if (!hasPublicLocations) { + return; + } + + const elasticManagedLocationsEnabled = + Boolean( + (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime + .elasticManagedLocationsEnabled + ) ?? true; + if (!elasticManagedLocationsEnabled) { + return "You don't have permission to use public locations"; + } +}; diff --git a/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts b/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts index 01f4946b3508f..8c4df4a2461f8 100644 --- a/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts +++ b/x-pack/plugins/synthetics/server/routes/synthetics_service/get_service_locations.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { toClientContract } from '../settings/private_locations/helpers'; +import { getPrivateLocationsAndAgentPolicies } from '../settings/private_locations/get_private_locations'; import { SyntheticsRestApiRouteFactory } from '../types'; import { getAllLocations } from '../../synthetics_service/get_all_locations'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; @@ -13,16 +15,37 @@ export const getServiceLocationsRoute: SyntheticsRestApiRouteFactory = () => ({ method: 'GET', path: SYNTHETICS_API_URLS.SERVICE_LOCATIONS, validate: {}, - handler: async ({ server, savedObjectsClient, syntheticsMonitorClient }): Promise<any> => { - const { throttling, allLocations } = await getAllLocations({ - server, - syntheticsMonitorClient, - savedObjectsClient, - }); + handler: async ({ + request, + server, + savedObjectsClient, + syntheticsMonitorClient, + }): Promise<any> => { + const elasticManagedLocationsEnabled = + Boolean( + (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime + .elasticManagedLocationsEnabled + ) ?? true; - return { - locations: allLocations, - throttling, - }; + if (elasticManagedLocationsEnabled) { + const { throttling, allLocations } = await getAllLocations({ + server, + syntheticsMonitorClient, + savedObjectsClient, + }); + + return { + locations: allLocations, + throttling, + }; + } else { + const { locations: privateLocations, agentPolicies } = + await getPrivateLocationsAndAgentPolicies(savedObjectsClient, syntheticsMonitorClient); + + const result = toClientContract({ locations: privateLocations }, agentPolicies).locations; + return { + locations: result, + }; + } }, }); diff --git a/x-pack/plugins/synthetics/server/synthetics_service/get_all_locations.ts b/x-pack/plugins/synthetics/server/synthetics_service/get_all_locations.ts index 491bde96d4067..6eb6a62547156 100644 --- a/x-pack/plugins/synthetics/server/synthetics_service/get_all_locations.ts +++ b/x-pack/plugins/synthetics/server/synthetics_service/get_all_locations.ts @@ -47,6 +47,11 @@ const getServicePublicLocations = async ( server: SyntheticsServerSetup, syntheticsMonitorClient: SyntheticsMonitorClient ) => { + if (!syntheticsMonitorClient.syntheticsService.isAllowed) { + return { + locations: [], + }; + } if (syntheticsMonitorClient.syntheticsService.locations.length === 0) { return await getServiceLocations(server); } diff --git a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts index 6a06ea93f3dcb..39a9afb0f0d14 100644 --- a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts @@ -190,6 +190,7 @@ describe('EphemeralTaskLifecycle', () => { task: taskManagerMock.createTask(), result: TaskRunResult.Success, persistence: TaskPersistence.Ephemeral, + isExpired: false, }) ) ); diff --git a/x-pack/plugins/task_manager/server/metrics/counter/counter.test.ts b/x-pack/plugins/task_manager/server/metrics/counter/counter.test.ts new file mode 100644 index 0000000000000..de915e64890b8 --- /dev/null +++ b/x-pack/plugins/task_manager/server/metrics/counter/counter.test.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Counter } from './counter'; + +describe('Counter', () => { + let counter: Counter; + beforeEach(() => { + counter = new Counter(); + }); + + test('should correctly initialize', () => { + expect(counter.get()).toEqual(0); + }); + + test('should correctly return initialCount', () => { + expect(counter.initialCount()).toEqual(0); + }); + + test('should correctly increment counter', () => { + counter.increment(); + counter.increment(); + expect(counter.get()).toEqual(2); + }); + + test('should correctly reset counter', () => { + counter.increment(); + counter.increment(); + counter.increment(); + counter.increment(); + counter.increment(); + counter.increment(); + counter.increment(); + expect(counter.get()).toEqual(7); + + counter.reset(); + expect(counter.get()).toEqual(0); + }); +}); diff --git a/x-pack/plugins/task_manager/server/metrics/counter/counter.ts b/x-pack/plugins/task_manager/server/metrics/counter/counter.ts new file mode 100644 index 0000000000000..be851cb84c049 --- /dev/null +++ b/x-pack/plugins/task_manager/server/metrics/counter/counter.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export class Counter { + private count = 0; + + public initialCount(): number { + return 0; + } + + public get(): number { + return this.count; + } + + public increment() { + this.count++; + } + + public reset() { + this.count = 0; + } +} diff --git a/x-pack/plugins/task_manager/server/metrics/counter/metric_counter_service.test.ts b/x-pack/plugins/task_manager/server/metrics/counter/metric_counter_service.test.ts new file mode 100644 index 0000000000000..75117fe5d99ce --- /dev/null +++ b/x-pack/plugins/task_manager/server/metrics/counter/metric_counter_service.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { MetricCounterService } from './metric_counter_service'; + +describe('MetricCounterService', () => { + test('should correctly initialize', () => { + const counterService = new MetricCounterService(['success', 'total']); + expect(counterService.collect()).toEqual({ success: 0, total: 0 }); + }); + + test('should correctly initialize with initial namespace', () => { + const counterService = new MetricCounterService(['success', 'total'], 'overall'); + expect(counterService.collect()).toEqual({ overall: { success: 0, total: 0 } }); + }); + + test('should correctly initialize with initial flattened namespace', () => { + const counterService = new MetricCounterService(['success', 'total'], 'overall.count'); + expect(counterService.collect()).toEqual({ overall: { count: { success: 0, total: 0 } } }); + }); + + test('should throw error if no keys provided', () => { + expect(() => { + new MetricCounterService([]); + }).toThrowErrorMatchingInlineSnapshot( + `"Metrics counter service must be initialized with at least one key"` + ); + }); + + test('should correctly return initialMetrics', () => { + const counterService = new MetricCounterService(['success', 'total']); + expect(counterService.initialMetrics()).toEqual({ success: 0, total: 0 }); + }); + + test('should correctly increment counter', () => { + const counterService = new MetricCounterService(['success', 'total']); + counterService.increment('success'); + counterService.increment('success'); + expect(counterService.collect()).toEqual({ success: 2, total: 0 }); + }); + + test('should correctly increment counter for new namespace', () => { + const counterService = new MetricCounterService(['success', 'total'], 'overall'); + counterService.increment('success', 'foo'); + expect(counterService.collect()).toEqual({ + overall: { success: 0, total: 0 }, + foo: { success: 1, total: 0 }, + }); + }); + + test('should correctly increment counter for nested namespace', () => { + const counterService = new MetricCounterService(['success', 'total'], 'overall'); + counterService.increment('success', 'foo.bar'); + counterService.increment('total', 'foo.baz'); + expect(counterService.collect()).toEqual({ + overall: { success: 0, total: 0 }, + foo: { bar: { success: 1, total: 0 }, baz: { success: 0, total: 1 } }, + }); + }); + + test('should correctly reset counter', () => { + const counterService = new MetricCounterService(['success', 'total'], 'overall'); + counterService.increment('success', 'overall'); + counterService.increment('total', 'overall'); + counterService.increment('success', 'foo.bar'); + counterService.increment('success', 'foo.bar'); + counterService.increment('total', 'foo.bar'); + counterService.increment('total', 'foo.bar'); + counterService.increment('total', 'foo.bar'); + counterService.increment('total', 'foo.bar'); + counterService.increment('total', 'foo.baz'); + counterService.increment('success', 'foo.cheese.whiz'); + expect(counterService.collect()).toEqual({ + overall: { success: 1, total: 1 }, + foo: { + bar: { success: 2, total: 4 }, + baz: { success: 0, total: 1 }, + cheese: { whiz: { success: 1, total: 0 } }, + }, + }); + + counterService.reset(); + expect(counterService.collect()).toEqual({ + overall: { success: 0, total: 0 }, + foo: { + bar: { success: 0, total: 0 }, + baz: { success: 0, total: 0 }, + cheese: { whiz: { success: 0, total: 0 } }, + }, + }); + }); +}); diff --git a/x-pack/plugins/task_manager/server/metrics/counter/metric_counter_service.ts b/x-pack/plugins/task_manager/server/metrics/counter/metric_counter_service.ts new file mode 100644 index 0000000000000..4ca1683355236 --- /dev/null +++ b/x-pack/plugins/task_manager/server/metrics/counter/metric_counter_service.ts @@ -0,0 +1,78 @@ +/* + * 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 { JsonObject } from '@kbn/utility-types'; +import { set } from '@kbn/safer-lodash-set'; +import { Counter } from './counter'; + +interface GenericObject { + [key: string]: unknown; +} +export const unflattenObject = <T extends object = GenericObject>(object: object): T => + Object.entries(object).reduce((acc, [key, value]) => { + set(acc, key, value); + return acc; + }, {} as T); + +export class MetricCounterService<T extends JsonObject> { + private readonly counters = new Map<string, Counter>(); + private readonly keys: string[]; + + constructor(keys: string[], initialNamespace?: string) { + if (!keys || !keys.length) { + throw new Error('Metrics counter service must be initialized with at least one key'); + } + + this.keys = keys; + this.initializeCountersForNamespace(initialNamespace); + } + + public initialMetrics(): T { + return this.toJson(true); + } + + public reset() { + this.counters.forEach((val: Counter) => { + val.reset(); + }); + } + + public increment(key: string, namespace?: string) { + // initialize counters for namespace if necessary + this.initializeCountersForNamespace(namespace); + + // increment counter in specified namespace + this.counters.get(this.buildCounterKey(key, namespace))?.increment(); + } + + public collect(): T { + return this.toJson(); + } + + private initializeCountersForNamespace(namespace?: string) { + for (const key of this.keys) { + const counterKey = this.buildCounterKey(key, namespace); + if (!this.counters.get(counterKey)) { + this.counters.set(counterKey, new Counter()); + } + } + } + + private buildCounterKey(key: string, namespace?: string) { + const prefix = namespace ? `${namespace}.` : ''; + return `${prefix}${key}`; + } + + private toJson(initialMetric: boolean = false): T { + const collected: Record<string, number> = {}; + this.counters.forEach((val: Counter, key: string) => { + collected[key] = initialMetric ? val.initialCount() : val.get(); + }); + + return unflattenObject(collected); + } +} diff --git a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts index 9671698329447..6ff99d482581a 100644 --- a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts +++ b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts @@ -410,123 +410,123 @@ describe('createAggregator', () => { expect(metrics[0]).toEqual({ key: 'task_run', value: { - overall: { success: 1, total: 1 }, + overall: { success: 1, not_timed_out: 1, total: 1 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[1]).toEqual({ key: 'task_run', value: { - overall: { success: 2, total: 2 }, + overall: { success: 2, not_timed_out: 2, total: 2 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[2]).toEqual({ key: 'task_run', value: { - overall: { success: 3, total: 3 }, + overall: { success: 3, not_timed_out: 3, total: 3 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[3]).toEqual({ key: 'task_run', value: { - overall: { success: 4, total: 4 }, + overall: { success: 4, not_timed_out: 4, total: 4 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[4]).toEqual({ key: 'task_run', value: { - overall: { success: 4, total: 5 }, + overall: { success: 4, not_timed_out: 5, total: 5 }, by_type: { - alerting: { success: 2, total: 3 }, - 'alerting:example': { success: 2, total: 3 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 3, total: 3 }, + 'alerting:example': { success: 2, not_timed_out: 3, total: 3 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[5]).toEqual({ key: 'task_run', value: { - overall: { success: 5, total: 6 }, + overall: { success: 5, not_timed_out: 6, total: 6 }, by_type: { - alerting: { success: 3, total: 4 }, - 'alerting:.index-threshold': { success: 1, total: 1 }, - 'alerting:example': { success: 2, total: 3 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 3, not_timed_out: 4, total: 4 }, + 'alerting:__index-threshold': { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 2, not_timed_out: 3, total: 3 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[6]).toEqual({ key: 'task_run', value: { - overall: { success: 6, total: 7 }, + overall: { success: 6, not_timed_out: 7, total: 7 }, by_type: { - alerting: { success: 4, total: 5 }, - 'alerting:.index-threshold': { success: 1, total: 1 }, - 'alerting:example': { success: 3, total: 4 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 4, not_timed_out: 5, total: 5 }, + 'alerting:__index-threshold': { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 3, not_timed_out: 4, total: 4 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[7]).toEqual({ key: 'task_run', value: { - overall: { success: 6, total: 8 }, + overall: { success: 6, not_timed_out: 8, total: 8 }, by_type: { - alerting: { success: 4, total: 6 }, - 'alerting:.index-threshold': { success: 1, total: 1 }, - 'alerting:example': { success: 3, total: 5 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 4, not_timed_out: 6, total: 6 }, + 'alerting:__index-threshold': { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 3, not_timed_out: 5, total: 5 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[8]).toEqual({ key: 'task_run', value: { - overall: { success: 7, total: 9 }, + overall: { success: 7, not_timed_out: 9, total: 9 }, by_type: { - alerting: { success: 5, total: 7 }, - 'alerting:.index-threshold': { success: 1, total: 1 }, - 'alerting:example': { success: 4, total: 6 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 5, not_timed_out: 7, total: 7 }, + 'alerting:__index-threshold': { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 4, not_timed_out: 6, total: 6 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[9]).toEqual({ key: 'task_run', value: { - overall: { success: 7, total: 10 }, + overall: { success: 7, not_timed_out: 10, total: 10 }, by_type: { - actions: { success: 0, total: 1 }, - alerting: { success: 5, total: 7 }, - 'actions:webhook': { success: 0, total: 1 }, - 'alerting:.index-threshold': { success: 1, total: 1 }, - 'alerting:example': { success: 4, total: 6 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + actions: { success: 0, not_timed_out: 1, total: 1 }, + alerting: { success: 5, not_timed_out: 7, total: 7 }, + 'actions:webhook': { success: 0, not_timed_out: 1, total: 1 }, + 'alerting:__index-threshold': { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 4, not_timed_out: 6, total: 6 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); @@ -583,56 +583,56 @@ describe('createAggregator', () => { expect(metrics[0]).toEqual({ key: 'task_run', value: { - overall: { success: 1, total: 1 }, + overall: { success: 1, not_timed_out: 1, total: 1 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[1]).toEqual({ key: 'task_run', value: { - overall: { success: 2, total: 2 }, + overall: { success: 2, not_timed_out: 2, total: 2 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[2]).toEqual({ key: 'task_run', value: { - overall: { success: 3, total: 3 }, + overall: { success: 3, not_timed_out: 3, total: 3 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[3]).toEqual({ key: 'task_run', value: { - overall: { success: 4, total: 4 }, + overall: { success: 4, not_timed_out: 4, total: 4 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[4]).toEqual({ key: 'task_run', value: { - overall: { success: 4, total: 5 }, + overall: { success: 4, not_timed_out: 5, total: 5 }, by_type: { - alerting: { success: 2, total: 3 }, - 'alerting:example': { success: 2, total: 3 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 3, total: 3 }, + 'alerting:example': { success: 2, not_timed_out: 3, total: 3 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); @@ -640,62 +640,62 @@ describe('createAggregator', () => { expect(metrics[5]).toEqual({ key: 'task_run', value: { - overall: { success: 1, total: 1 }, + overall: { success: 1, not_timed_out: 1, total: 1 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[6]).toEqual({ key: 'task_run', value: { - overall: { success: 2, total: 2 }, + overall: { success: 2, not_timed_out: 2, total: 2 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[7]).toEqual({ key: 'task_run', value: { - overall: { success: 2, total: 3 }, + overall: { success: 2, not_timed_out: 3, total: 3 }, by_type: { - alerting: { success: 2, total: 3 }, - 'alerting:example': { success: 2, total: 3 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 2, not_timed_out: 3, total: 3 }, + 'alerting:example': { success: 2, not_timed_out: 3, total: 3 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[8]).toEqual({ key: 'task_run', value: { - overall: { success: 3, total: 4 }, + overall: { success: 3, not_timed_out: 4, total: 4 }, by_type: { - alerting: { success: 3, total: 4 }, - 'alerting:example': { success: 3, total: 4 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 3, not_timed_out: 4, total: 4 }, + 'alerting:example': { success: 3, not_timed_out: 4, total: 4 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[9]).toEqual({ key: 'task_run', value: { - overall: { success: 3, total: 5 }, + overall: { success: 3, not_timed_out: 5, total: 5 }, by_type: { - actions: { success: 0, total: 1 }, - alerting: { success: 3, total: 4 }, - 'actions:webhook': { success: 0, total: 1 }, - 'alerting:example': { success: 3, total: 4 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + actions: { success: 0, not_timed_out: 1, total: 1 }, + alerting: { success: 3, not_timed_out: 4, total: 4 }, + 'actions:webhook': { success: 0, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 3, not_timed_out: 4, total: 4 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); @@ -760,56 +760,56 @@ describe('createAggregator', () => { expect(metrics[0]).toEqual({ key: 'task_run', value: { - overall: { success: 1, total: 1 }, + overall: { success: 1, not_timed_out: 1, total: 1 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[1]).toEqual({ key: 'task_run', value: { - overall: { success: 2, total: 2 }, + overall: { success: 2, not_timed_out: 2, total: 2 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[2]).toEqual({ key: 'task_run', value: { - overall: { success: 3, total: 3 }, + overall: { success: 3, not_timed_out: 3, total: 3 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[3]).toEqual({ key: 'task_run', value: { - overall: { success: 4, total: 4 }, + overall: { success: 4, not_timed_out: 4, total: 4 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); expect(metrics[4]).toEqual({ key: 'task_run', value: { - overall: { success: 4, total: 5 }, + overall: { success: 4, not_timed_out: 5, total: 5 }, by_type: { - alerting: { success: 2, total: 3 }, - 'alerting:example': { success: 2, total: 3 }, - report: { success: 1, total: 1 }, - telemetry: { success: 1, total: 1 }, + alerting: { success: 2, not_timed_out: 3, total: 3 }, + 'alerting:example': { success: 2, not_timed_out: 3, total: 3 }, + report: { success: 1, not_timed_out: 1, total: 1 }, + telemetry: { success: 1, not_timed_out: 1, total: 1 }, }, }, }); @@ -817,62 +817,62 @@ describe('createAggregator', () => { expect(metrics[5]).toEqual({ key: 'task_run', value: { - overall: { success: 1, total: 1 }, + overall: { success: 1, not_timed_out: 1, total: 1 }, by_type: { - alerting: { success: 1, total: 1 }, - 'alerting:example': { success: 1, total: 1 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 1, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 1, not_timed_out: 1, total: 1 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[6]).toEqual({ key: 'task_run', value: { - overall: { success: 2, total: 2 }, + overall: { success: 2, not_timed_out: 2, total: 2 }, by_type: { - alerting: { success: 2, total: 2 }, - 'alerting:example': { success: 2, total: 2 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 2, not_timed_out: 2, total: 2 }, + 'alerting:example': { success: 2, not_timed_out: 2, total: 2 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[7]).toEqual({ key: 'task_run', value: { - overall: { success: 2, total: 3 }, + overall: { success: 2, not_timed_out: 3, total: 3 }, by_type: { - alerting: { success: 2, total: 3 }, - 'alerting:example': { success: 2, total: 3 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 2, not_timed_out: 3, total: 3 }, + 'alerting:example': { success: 2, not_timed_out: 3, total: 3 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[8]).toEqual({ key: 'task_run', value: { - overall: { success: 3, total: 4 }, + overall: { success: 3, not_timed_out: 4, total: 4 }, by_type: { - alerting: { success: 3, total: 4 }, - 'alerting:example': { success: 3, total: 4 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + alerting: { success: 3, not_timed_out: 4, total: 4 }, + 'alerting:example': { success: 3, not_timed_out: 4, total: 4 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); expect(metrics[9]).toEqual({ key: 'task_run', value: { - overall: { success: 3, total: 5 }, + overall: { success: 3, not_timed_out: 5, total: 5 }, by_type: { - actions: { success: 0, total: 1 }, - alerting: { success: 3, total: 4 }, - 'actions:webhook': { success: 0, total: 1 }, - 'alerting:example': { success: 3, total: 4 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + actions: { success: 0, not_timed_out: 1, total: 1 }, + alerting: { success: 3, not_timed_out: 4, total: 4 }, + 'actions:webhook': { success: 0, not_timed_out: 1, total: 1 }, + 'alerting:example': { success: 3, not_timed_out: 4, total: 4 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }, }); diff --git a/x-pack/plugins/task_manager/server/metrics/success_rate_counter.test.ts b/x-pack/plugins/task_manager/server/metrics/success_rate_counter.test.ts deleted file mode 100644 index eb34f3a34c005..0000000000000 --- a/x-pack/plugins/task_manager/server/metrics/success_rate_counter.test.ts +++ /dev/null @@ -1,49 +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 { SuccessRateCounter } from './success_rate_counter'; - -describe('SuccessRateCounter', () => { - let successRateCounter: SuccessRateCounter; - beforeEach(() => { - successRateCounter = new SuccessRateCounter(); - }); - - test('should correctly initialize', () => { - expect(successRateCounter.get()).toEqual({ success: 0, total: 0 }); - }); - - test('should correctly return initialMetrics', () => { - expect(successRateCounter.initialMetric()).toEqual({ success: 0, total: 0 }); - }); - - test('should correctly increment counter when success is true', () => { - successRateCounter.increment(true); - successRateCounter.increment(true); - expect(successRateCounter.get()).toEqual({ success: 2, total: 2 }); - }); - - test('should correctly increment counter when success is false', () => { - successRateCounter.increment(false); - successRateCounter.increment(false); - expect(successRateCounter.get()).toEqual({ success: 0, total: 2 }); - }); - - test('should correctly reset counter', () => { - successRateCounter.increment(true); - successRateCounter.increment(true); - successRateCounter.increment(false); - successRateCounter.increment(false); - successRateCounter.increment(true); - successRateCounter.increment(true); - successRateCounter.increment(false); - expect(successRateCounter.get()).toEqual({ success: 4, total: 7 }); - - successRateCounter.reset(); - expect(successRateCounter.get()).toEqual({ success: 0, total: 0 }); - }); -}); diff --git a/x-pack/plugins/task_manager/server/metrics/success_rate_counter.ts b/x-pack/plugins/task_manager/server/metrics/success_rate_counter.ts deleted file mode 100644 index d9c61575a2698..0000000000000 --- a/x-pack/plugins/task_manager/server/metrics/success_rate_counter.ts +++ /dev/null @@ -1,44 +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 { JsonObject } from '@kbn/utility-types'; - -export interface SuccessRate extends JsonObject { - success: number; - total: number; -} - -export class SuccessRateCounter { - private success = 0; - private total = 0; - - public initialMetric(): SuccessRate { - return { - success: 0, - total: 0, - }; - } - - public get(): SuccessRate { - return { - success: this.success, - total: this.total, - }; - } - - public increment(success: boolean) { - if (success) { - this.success++; - } - this.total++; - } - - public reset() { - this.success = 0; - this.total = 0; - } -} diff --git a/x-pack/plugins/task_manager/server/metrics/task_claim_metrics_aggregator.ts b/x-pack/plugins/task_manager/server/metrics/task_claim_metrics_aggregator.ts index 2dc1a50e8d00e..a10ddf89c77b0 100644 --- a/x-pack/plugins/task_manager/server/metrics/task_claim_metrics_aggregator.ts +++ b/x-pack/plugins/task_manager/server/metrics/task_claim_metrics_aggregator.ts @@ -5,17 +5,27 @@ * 2.0. */ +import { JsonObject } from '@kbn/utility-types'; import { isOk } from '../lib/result_type'; import { TaskLifecycleEvent } from '../polling_lifecycle'; import { TaskRun } from '../task_events'; import { SimpleHistogram } from './simple_histogram'; -import { SuccessRate, SuccessRateCounter } from './success_rate_counter'; import { ITaskMetricsAggregator } from './types'; +import { MetricCounterService } from './counter/metric_counter_service'; const HDR_HISTOGRAM_MAX = 30000; // 30 seconds const HDR_HISTOGRAM_BUCKET_SIZE = 100; // 100 millis -export type TaskClaimMetric = SuccessRate & { +enum TaskClaimKeys { + SUCCESS = 'success', + TOTAL = 'total', +} +interface TaskClaimCounts extends JsonObject { + [TaskClaimKeys.SUCCESS]: number; + [TaskClaimKeys.TOTAL]: number; +} + +export type TaskClaimMetric = TaskClaimCounts & { duration: { counts: number[]; values: number[]; @@ -23,30 +33,35 @@ export type TaskClaimMetric = SuccessRate & { }; export class TaskClaimMetricsAggregator implements ITaskMetricsAggregator<TaskClaimMetric> { - private claimSuccessRate = new SuccessRateCounter(); + private counter: MetricCounterService<TaskClaimCounts> = new MetricCounterService( + Object.values(TaskClaimKeys) + ); private durationHistogram = new SimpleHistogram(HDR_HISTOGRAM_MAX, HDR_HISTOGRAM_BUCKET_SIZE); public initialMetric(): TaskClaimMetric { return { - ...this.claimSuccessRate.initialMetric(), + ...this.counter.initialMetrics(), duration: { counts: [], values: [] }, }; } public collect(): TaskClaimMetric { return { - ...this.claimSuccessRate.get(), + ...this.counter.collect(), duration: this.serializeHistogram(), }; } public reset() { - this.claimSuccessRate.reset(); + this.counter.reset(); this.durationHistogram.reset(); } public processTaskLifecycleEvent(taskEvent: TaskLifecycleEvent) { const success = isOk((taskEvent as TaskRun).event); - this.claimSuccessRate.increment(success); + if (success) { + this.counter.increment(TaskClaimKeys.SUCCESS); + } + this.counter.increment(TaskClaimKeys.TOTAL); if (taskEvent.timing) { const durationInMs = taskEvent.timing.stop - taskEvent.timing.start; diff --git a/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.test.ts b/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.test.ts index e3654fd9a21d5..d9e82a40eb601 100644 --- a/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.test.ts +++ b/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.test.ts @@ -12,7 +12,7 @@ import { asTaskRunEvent, TaskPersistence } from '../task_events'; import { TaskRunResult } from '../task_running'; import { TaskRunMetricsAggregator } from './task_run_metrics_aggregator'; -export const getTaskRunSuccessEvent = (type: string) => { +export const getTaskRunSuccessEvent = (type: string, isExpired: boolean = false) => { const id = uuid.v4(); return asTaskRunEvent( id, @@ -33,6 +33,7 @@ export const getTaskRunSuccessEvent = (type: string) => { }, persistence: TaskPersistence.Recurring, result: TaskRunResult.Success, + isExpired, }), { start: 1689698780490, @@ -41,7 +42,7 @@ export const getTaskRunSuccessEvent = (type: string) => { ); }; -export const getTaskRunFailedEvent = (type: string) => { +export const getTaskRunFailedEvent = (type: string, isExpired: boolean = false) => { const id = uuid.v4(); return asTaskRunEvent( id, @@ -63,6 +64,7 @@ export const getTaskRunFailedEvent = (type: string) => { }, persistence: TaskPersistence.Recurring, result: TaskRunResult.Failed, + isExpired, }) ); }; @@ -75,15 +77,13 @@ describe('TaskRunMetricsAggregator', () => { test('should correctly initialize', () => { expect(taskRunMetricsAggregator.collect()).toEqual({ - overall: { success: 0, total: 0 }, - by_type: {}, + overall: { success: 0, not_timed_out: 0, total: 0 }, }); }); test('should correctly return initialMetrics', () => { expect(taskRunMetricsAggregator.initialMetric()).toEqual({ - overall: { success: 0, total: 0 }, - by_type: {}, + overall: { success: 0, not_timed_out: 0, total: 0 }, }); }); @@ -91,9 +91,20 @@ describe('TaskRunMetricsAggregator', () => { taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('telemetry')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('telemetry')); expect(taskRunMetricsAggregator.collect()).toEqual({ - overall: { success: 2, total: 2 }, + overall: { success: 2, not_timed_out: 2, total: 2 }, by_type: { - telemetry: { success: 2, total: 2 }, + telemetry: { success: 2, not_timed_out: 2, total: 2 }, + }, + }); + }); + + test('should correctly process task run success event where task run has timed out', () => { + taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('telemetry', true)); + taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('telemetry', true)); + expect(taskRunMetricsAggregator.collect()).toEqual({ + overall: { success: 2, not_timed_out: 0, total: 2 }, + by_type: { + telemetry: { success: 2, not_timed_out: 0, total: 2 }, }, }); }); @@ -102,9 +113,20 @@ describe('TaskRunMetricsAggregator', () => { taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('telemetry')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('telemetry')); expect(taskRunMetricsAggregator.collect()).toEqual({ - overall: { success: 0, total: 2 }, + overall: { success: 0, not_timed_out: 2, total: 2 }, by_type: { - telemetry: { success: 0, total: 2 }, + telemetry: { success: 0, not_timed_out: 2, total: 2 }, + }, + }); + }); + + test('should correctly process task run failure event where task run has timed out', () => { + taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('telemetry', true)); + taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('telemetry', true)); + expect(taskRunMetricsAggregator.collect()).toEqual({ + overall: { success: 0, not_timed_out: 0, total: 2 }, + by_type: { + telemetry: { success: 0, not_timed_out: 0, total: 2 }, }, }); }); @@ -112,13 +134,13 @@ describe('TaskRunMetricsAggregator', () => { test('should correctly process different task types', () => { taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('telemetry')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('report')); - taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('report')); + taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('report', true)); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('telemetry')); expect(taskRunMetricsAggregator.collect()).toEqual({ - overall: { success: 3, total: 4 }, + overall: { success: 3, not_timed_out: 3, total: 4 }, by_type: { - report: { success: 2, total: 2 }, - telemetry: { success: 1, total: 2 }, + report: { success: 2, not_timed_out: 1, total: 2 }, + telemetry: { success: 1, not_timed_out: 2, total: 2 }, }, }); }); @@ -128,7 +150,9 @@ describe('TaskRunMetricsAggregator', () => { taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('report')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('report')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('telemetry')); - taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('alerting:example')); + taskRunMetricsAggregator.processTaskLifecycleEvent( + getTaskRunSuccessEvent('alerting:example', true) + ); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('alerting:example')); taskRunMetricsAggregator.processTaskLifecycleEvent( getTaskRunSuccessEvent('alerting:.index-threshold') @@ -140,19 +164,19 @@ describe('TaskRunMetricsAggregator', () => { taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('alerting:example')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('actions:.email')); taskRunMetricsAggregator.processTaskLifecycleEvent( - getTaskRunSuccessEvent('alerting:.index-threshold') + getTaskRunSuccessEvent('alerting:.index-threshold', true) ); expect(taskRunMetricsAggregator.collect()).toEqual({ - overall: { success: 11, total: 14 }, + overall: { success: 11, not_timed_out: 12, total: 14 }, by_type: { - actions: { success: 3, total: 3 }, - 'actions:.email': { success: 1, total: 1 }, - 'actions:webhook': { success: 2, total: 2 }, - alerting: { success: 5, total: 7 }, - 'alerting:example': { success: 3, total: 5 }, - 'alerting:.index-threshold': { success: 2, total: 2 }, - report: { success: 2, total: 2 }, - telemetry: { success: 1, total: 2 }, + actions: { success: 3, not_timed_out: 3, total: 3 }, + 'actions:__email': { success: 1, not_timed_out: 1, total: 1 }, + 'actions:webhook': { success: 2, not_timed_out: 2, total: 2 }, + alerting: { success: 5, not_timed_out: 5, total: 7 }, + 'alerting:example': { success: 3, not_timed_out: 4, total: 5 }, + 'alerting:__index-threshold': { success: 2, not_timed_out: 1, total: 2 }, + report: { success: 2, not_timed_out: 2, total: 2 }, + telemetry: { success: 1, not_timed_out: 2, total: 2 }, }, }); }); @@ -162,10 +186,12 @@ describe('TaskRunMetricsAggregator', () => { taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('report')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('report')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('telemetry')); - taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('alerting:example')); + taskRunMetricsAggregator.processTaskLifecycleEvent( + getTaskRunSuccessEvent('alerting:example', true) + ); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('alerting:example')); taskRunMetricsAggregator.processTaskLifecycleEvent( - getTaskRunSuccessEvent('alerting:.index-threshold') + getTaskRunSuccessEvent('alerting:.index-threshold', true) ); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunSuccessEvent('actions:webhook')); taskRunMetricsAggregator.processTaskLifecycleEvent(getTaskRunFailedEvent('alerting:example')); @@ -177,31 +203,31 @@ describe('TaskRunMetricsAggregator', () => { getTaskRunSuccessEvent('alerting:.index-threshold') ); expect(taskRunMetricsAggregator.collect()).toEqual({ - overall: { success: 11, total: 14 }, + overall: { success: 11, not_timed_out: 12, total: 14 }, by_type: { - actions: { success: 3, total: 3 }, - 'actions:.email': { success: 1, total: 1 }, - 'actions:webhook': { success: 2, total: 2 }, - alerting: { success: 5, total: 7 }, - 'alerting:example': { success: 3, total: 5 }, - 'alerting:.index-threshold': { success: 2, total: 2 }, - report: { success: 2, total: 2 }, - telemetry: { success: 1, total: 2 }, + actions: { success: 3, not_timed_out: 3, total: 3 }, + 'actions:__email': { success: 1, not_timed_out: 1, total: 1 }, + 'actions:webhook': { success: 2, not_timed_out: 2, total: 2 }, + alerting: { success: 5, not_timed_out: 5, total: 7 }, + 'alerting:example': { success: 3, not_timed_out: 4, total: 5 }, + 'alerting:__index-threshold': { success: 2, not_timed_out: 1, total: 2 }, + report: { success: 2, not_timed_out: 2, total: 2 }, + telemetry: { success: 1, not_timed_out: 2, total: 2 }, }, }); taskRunMetricsAggregator.reset(); expect(taskRunMetricsAggregator.collect()).toEqual({ - overall: { success: 0, total: 0 }, + overall: { success: 0, not_timed_out: 0, total: 0 }, by_type: { - actions: { success: 0, total: 0 }, - 'actions:.email': { success: 0, total: 0 }, - 'actions:webhook': { success: 0, total: 0 }, - alerting: { success: 0, total: 0 }, - 'alerting:example': { success: 0, total: 0 }, - 'alerting:.index-threshold': { success: 0, total: 0 }, - report: { success: 0, total: 0 }, - telemetry: { success: 0, total: 0 }, + actions: { success: 0, not_timed_out: 0, total: 0 }, + 'actions:__email': { success: 0, not_timed_out: 0, total: 0 }, + 'actions:webhook': { success: 0, not_timed_out: 0, total: 0 }, + alerting: { success: 0, not_timed_out: 0, total: 0 }, + 'alerting:example': { success: 0, not_timed_out: 0, total: 0 }, + 'alerting:__index-threshold': { success: 0, not_timed_out: 0, total: 0 }, + report: { success: 0, not_timed_out: 0, total: 0 }, + telemetry: { success: 0, not_timed_out: 0, total: 0 }, }, }); }); diff --git a/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.ts b/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.ts index c25d80f112df1..685c5a8cc8838 100644 --- a/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.ts +++ b/x-pack/plugins/task_manager/server/metrics/task_run_metrics_aggregator.ts @@ -9,70 +9,79 @@ import { JsonObject } from '@kbn/utility-types'; import { isOk, unwrap } from '../lib/result_type'; import { TaskLifecycleEvent } from '../polling_lifecycle'; import { ErroredTask, RanTask, TaskRun } from '../task_events'; -import { SuccessRate, SuccessRateCounter } from './success_rate_counter'; +import { MetricCounterService } from './counter/metric_counter_service'; import { ITaskMetricsAggregator } from './types'; const taskTypeGrouping = new Set<string>(['alerting:', 'actions:']); +enum TaskRunKeys { + SUCCESS = 'success', + NOT_TIMED_OUT = 'not_timed_out', + TOTAL = 'total', +} + +enum TaskRunMetricKeys { + OVERALL = 'overall', + BY_TYPE = 'by_type', +} + +interface TaskRunCounts extends JsonObject { + [TaskRunKeys.SUCCESS]: number; + [TaskRunKeys.NOT_TIMED_OUT]: number; + [TaskRunKeys.TOTAL]: number; +} + export interface TaskRunMetric extends JsonObject { - overall: SuccessRate; - by_type: { - [key: string]: SuccessRate; + [TaskRunMetricKeys.OVERALL]: TaskRunCounts; + [TaskRunMetricKeys.BY_TYPE]: { + [key: string]: TaskRunCounts; }; } export class TaskRunMetricsAggregator implements ITaskMetricsAggregator<TaskRunMetric> { - private taskRunSuccessRate = new SuccessRateCounter(); - private taskRunCounter: Map<string, SuccessRateCounter> = new Map(); + private counter: MetricCounterService<TaskRunMetric> = new MetricCounterService( + Object.values(TaskRunKeys), + TaskRunMetricKeys.OVERALL + ); public initialMetric(): TaskRunMetric { - return { - overall: this.taskRunSuccessRate.initialMetric(), - by_type: {}, - }; + return this.counter.initialMetrics(); } public collect(): TaskRunMetric { - return { - overall: this.taskRunSuccessRate.get(), - by_type: this.collectTaskTypeEntries(), - }; + return this.counter.collect(); } public reset() { - this.taskRunSuccessRate.reset(); - for (const taskType of this.taskRunCounter.keys()) { - this.taskRunCounter.get(taskType)!.reset(); - } + this.counter.reset(); } public processTaskLifecycleEvent(taskEvent: TaskLifecycleEvent) { - const { task }: RanTask | ErroredTask = unwrap((taskEvent as TaskRun).event); - const taskType = task.taskType; + const { task, isExpired }: RanTask | ErroredTask = unwrap((taskEvent as TaskRun).event); + const success = isOk((taskEvent as TaskRun).event); + const taskType = task.taskType.replaceAll('.', '__'); + const taskTypeGroup = this.getTaskTypeGroup(taskType); - const taskTypeSuccessRate: SuccessRateCounter = - this.taskRunCounter.get(taskType) ?? new SuccessRateCounter(); + // increment the total counters + this.incrementCounters(TaskRunKeys.TOTAL, taskType, taskTypeGroup); - const success = isOk((taskEvent as TaskRun).event); - this.taskRunSuccessRate.increment(success); - taskTypeSuccessRate.increment(success); - this.taskRunCounter.set(taskType, taskTypeSuccessRate); + // increment success counters + if (success) { + this.incrementCounters(TaskRunKeys.SUCCESS, taskType, taskTypeGroup); + } - const taskTypeGroup = this.getTaskTypeGroup(taskType); - if (taskTypeGroup) { - const taskTypeGroupSuccessRate: SuccessRateCounter = - this.taskRunCounter.get(taskTypeGroup) ?? new SuccessRateCounter(); - taskTypeGroupSuccessRate.increment(success); - this.taskRunCounter.set(taskTypeGroup, taskTypeGroupSuccessRate); + // increment expired counters + if (!isExpired) { + this.incrementCounters(TaskRunKeys.NOT_TIMED_OUT, taskType, taskTypeGroup); } } - private collectTaskTypeEntries() { - const collected: Record<string, SuccessRate> = {}; - for (const [key, value] of this.taskRunCounter) { - collected[key] = value.get(); + private incrementCounters(key: TaskRunKeys, taskType: string, group?: string) { + this.counter.increment(key, TaskRunMetricKeys.OVERALL); + this.counter.increment(key, `${TaskRunMetricKeys.BY_TYPE}.${taskType}`); + if (group) { + this.counter.increment(key, `${TaskRunMetricKeys.BY_TYPE}.${group}`); } - return collected; } private getTaskTypeGroup(taskType: string): string | undefined { diff --git a/x-pack/plugins/task_manager/server/monitoring/background_task_utilization_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/background_task_utilization_statistics.test.ts index 9507b3ab0e4cd..b2dae1a045d6a 100644 --- a/x-pack/plugins/task_manager/server/monitoring/background_task_utilization_statistics.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/background_task_utilization_statistics.test.ts @@ -647,6 +647,7 @@ const mockTaskRunEvent = ( persistence: persistence ?? (task.schedule ? TaskPersistence.Recurring : TaskPersistence.NonRecurring), result, + isExpired: false, }), timing ); diff --git a/x-pack/plugins/task_manager/server/monitoring/ephemeral_task_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/ephemeral_task_statistics.test.ts index 8d4ef4fab2eba..bbbb13dd9060f 100644 --- a/x-pack/plugins/task_manager/server/monitoring/ephemeral_task_statistics.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/ephemeral_task_statistics.test.ts @@ -362,7 +362,7 @@ const mockTaskRunEvent = ( ) => { const task = mockTaskInstance(overrides); const persistence = TaskPersistence.Recurring; - return asTaskRunEvent(task.id, asOk({ task, persistence, result }), timing); + return asTaskRunEvent(task.id, asOk({ task, persistence, result, isExpired: false }), timing); }; const mockTaskInstance = (overrides: Partial<ConcreteTaskInstance> = {}): ConcreteTaskInstance => ({ diff --git a/x-pack/plugins/task_manager/server/monitoring/task_run_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/task_run_statistics.test.ts index 91e81013b726f..9dfa3e8cadfe7 100644 --- a/x-pack/plugins/task_manager/server/monitoring/task_run_statistics.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/task_run_statistics.test.ts @@ -905,6 +905,7 @@ const mockTaskRunEvent = ( persistence: persistence ?? (task.schedule ? TaskPersistence.Recurring : TaskPersistence.NonRecurring), result, + isExpired: false, }), timing ); diff --git a/x-pack/plugins/task_manager/server/task_events.ts b/x-pack/plugins/task_manager/server/task_events.ts index e8808322b397a..68eaec9d9b28e 100644 --- a/x-pack/plugins/task_manager/server/task_events.ts +++ b/x-pack/plugins/task_manager/server/task_events.ts @@ -70,6 +70,7 @@ export interface RanTask { task: ConcreteTaskInstance; persistence: TaskPersistence; result: TaskRunResult; + isExpired: boolean; } export type ErroredTask = RanTask & { error: Error; diff --git a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts index a41297c90f67b..1b0a1b9c5b02d 100644 --- a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts @@ -347,6 +347,7 @@ export class EphemeralTaskManagerRunner implements TaskRunner { task: { ...this.instance.task, state }, persistence: TaskPersistence.Ephemeral, result: TaskRunResult.Success, + isExpired: false, }), taskTiming ) @@ -360,6 +361,7 @@ export class EphemeralTaskManagerRunner implements TaskRunner { task: { ...this.instance.task, state }, persistence: TaskPersistence.Ephemeral, result: TaskRunResult.Failed, + isExpired: false, error, }), taskTiming diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts index 7e897840f72c7..6676c17ccc630 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts @@ -922,6 +922,7 @@ describe('TaskManagerRunner', () => { persistence: TaskPersistence.Recurring, task: originalInstance, result: TaskRunResult.Failed, + isExpired: false, }) ) ) @@ -1254,6 +1255,47 @@ describe('TaskManagerRunner', () => { task: instance, persistence: TaskPersistence.NonRecurring, result: TaskRunResult.Success, + isExpired: false, + }) + ) + ) + ); + }); + + test('emits TaskEvent when a task is run successfully but completes after timeout', async () => { + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 0, 0, 0).valueOf()); + const id = _.random(1, 20).toString(); + const onTaskEvent = jest.fn(); + const { runner, instance } = await readyToRunStageSetup({ + onTaskEvent, + instance: { + id, + }, + definitions: { + bar: { + title: 'Bar!', + timeout: `1s`, + createTaskRunner: () => ({ + async run() { + return { state: {} }; + }, + }), + }, + }, + }); + + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 10, 0, 0).valueOf()); + await runner.run(); + + expect(onTaskEvent).toHaveBeenCalledWith( + withAnyTiming( + asTaskRunEvent( + id, + asOk({ + task: instance, + persistence: TaskPersistence.NonRecurring, + result: TaskRunResult.Success, + isExpired: true, }) ) ) @@ -1292,6 +1334,49 @@ describe('TaskManagerRunner', () => { task: instance, persistence: TaskPersistence.Recurring, result: TaskRunResult.Success, + isExpired: false, + }) + ) + ) + ); + }); + + test('emits TaskEvent when a recurring task is run successfully but completes after timeout', async () => { + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 0, 0, 0).valueOf()); + const id = _.random(1, 20).toString(); + const runAt = minutesFromNow(_.random(5)); + const onTaskEvent = jest.fn(); + const { runner, instance } = await readyToRunStageSetup({ + onTaskEvent, + instance: { + id, + schedule: { interval: '1m' }, + }, + definitions: { + bar: { + title: 'Bar!', + timeout: `1s`, + createTaskRunner: () => ({ + async run() { + return { runAt, state: {} }; + }, + }), + }, + }, + }); + + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 10, 0, 0).valueOf()); + await runner.run(); + + expect(onTaskEvent).toHaveBeenCalledWith( + withAnyTiming( + asTaskRunEvent( + id, + asOk({ + task: instance, + persistence: TaskPersistence.Recurring, + result: TaskRunResult.Success, + isExpired: true, }) ) ) @@ -1331,6 +1416,50 @@ describe('TaskManagerRunner', () => { persistence: TaskPersistence.Recurring, result: TaskRunResult.Success, error: new Error(`Alerting task failed to run.`), + isExpired: false, + }) + ) + ) + ); + }); + + test('emits TaskEvent when a recurring task returns a success result with hasError=true but completes after timeout', async () => { + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 0, 0, 0).valueOf()); + const id = _.random(1, 20).toString(); + const runAt = minutesFromNow(_.random(5)); + const onTaskEvent = jest.fn(); + const { runner, instance } = await readyToRunStageSetup({ + onTaskEvent, + instance: { + id, + schedule: { interval: '1m' }, + }, + definitions: { + bar: { + title: 'Bar!', + timeout: `1s`, + createTaskRunner: () => ({ + async run() { + return { runAt, state: {}, hasError: true }; + }, + }), + }, + }, + }); + + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 10, 0, 0).valueOf()); + await runner.run(); + + expect(onTaskEvent).toHaveBeenCalledWith( + withAnyTiming( + asTaskRunEvent( + id, + asErr({ + task: instance, + persistence: TaskPersistence.Recurring, + result: TaskRunResult.Success, + isExpired: true, + error: new Error(`Alerting task failed to run.`), }) ) ) @@ -1368,6 +1497,49 @@ describe('TaskManagerRunner', () => { task: instance, persistence: TaskPersistence.NonRecurring, result: TaskRunResult.RetryScheduled, + isExpired: false, + }) + ) + ) + ); + expect(onTaskEvent).toHaveBeenCalledTimes(1); + }); + + test('emits TaskEvent when a task run throws an error and has timed out', async () => { + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 0, 0, 0).valueOf()); + const id = _.random(1, 20).toString(); + const error = new Error('Dangit!'); + const onTaskEvent = jest.fn(); + const { runner, instance } = await readyToRunStageSetup({ + onTaskEvent, + instance: { + id, + }, + definitions: { + bar: { + title: 'Bar!', + timeout: `1s`, + createTaskRunner: () => ({ + async run() { + throw error; + }, + }), + }, + }, + }); + fakeTimer = sinon.useFakeTimers(new Date(2023, 1, 1, 0, 10, 0, 0).valueOf()); + await runner.run(); + + expect(onTaskEvent).toHaveBeenCalledWith( + withAnyTiming( + asTaskRunEvent( + id, + asErr({ + error, + task: instance, + persistence: TaskPersistence.NonRecurring, + result: TaskRunResult.Failed, + isExpired: true, }) ) ) @@ -1409,6 +1581,7 @@ describe('TaskManagerRunner', () => { task: instance, persistence: TaskPersistence.Recurring, result: TaskRunResult.RetryScheduled, + isExpired: false, }) ) ) @@ -1461,6 +1634,7 @@ describe('TaskManagerRunner', () => { task: originalInstance, persistence: TaskPersistence.NonRecurring, result: TaskRunResult.Failed, + isExpired: false, }) ) ) diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.ts index cfe41d832f31f..1742d88bc8f07 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.ts @@ -734,6 +734,8 @@ export class TaskManagerRunner implements TaskRunner { ): Promise<Result<SuccessfulRunResult, FailedRunResult>> { const { task } = this.instance; + const taskHasExpired = this.isExpired; + await eitherAsync( result, async ({ runAt, schedule, hasError }: SuccessfulRunResult) => { @@ -754,11 +756,16 @@ export class TaskManagerRunner implements TaskRunner { this.id, asErr({ ...processedResult, + isExpired: taskHasExpired, error: new Error(`Alerting task failed to run.`), }), taskTiming ) - : asTaskRunEvent(this.id, asOk(processedResult), taskTiming); + : asTaskRunEvent( + this.id, + asOk({ ...processedResult, isExpired: taskHasExpired }), + taskTiming + ); this.onTaskEvent(taskRunEvent); }, async ({ error }: FailedRunResult) => { @@ -769,6 +776,7 @@ export class TaskManagerRunner implements TaskRunner { task, persistence: task.schedule ? TaskPersistence.Recurring : TaskPersistence.NonRecurring, result: await this.processResultForRecurringTask(result), + isExpired: this.isExpired, error, }), taskTiming diff --git a/x-pack/plugins/task_manager/server/task_scheduling.test.ts b/x-pack/plugins/task_manager/server/task_scheduling.test.ts index 1a87bd59ec036..9f822b9cd2d76 100644 --- a/x-pack/plugins/task_manager/server/task_scheduling.test.ts +++ b/x-pack/plugins/task_manager/server/task_scheduling.test.ts @@ -700,6 +700,7 @@ describe('TaskScheduling', () => { }, result: TaskRunResult.Success, persistence: TaskPersistence.Ephemeral, + isExpired: false, }) ) ); @@ -743,6 +744,7 @@ describe('TaskScheduling', () => { }, result: TaskRunResult.Failed, persistence: TaskPersistence.Ephemeral, + isExpired: false, }) ) ); 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 c643f616e5eb3..000d54ade631c 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -5067,6 +5067,22 @@ } } }, + "top_traces": { + "properties": { + "max": { + "type": "long", + "_meta": { + "description": "Max number of documents in top 100 traces withing the last day" + } + }, + "median": { + "type": "long", + "_meta": { + "description": "Median number of documents in top 100 traces within the last day" + } + } + } + }, "tasks": { "properties": { "aggregated_transactions": { @@ -5278,6 +5294,20 @@ } } } + }, + "top_traces": { + "properties": { + "took": { + "properties": { + "ms": { + "type": "long", + "_meta": { + "description": "Execution time in milliseconds for the \"top_traces\" task" + } + } + } + } + } } } } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 0bb7f28f877ab..49fa6be17eb96 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -1317,7 +1317,6 @@ "data.search.aggs.rareTerms.aggTypesLabel": "Termes rares de {fieldName}", "data.search.es_search.queryTimeValue": "{queryTime} ms", "data.search.functions.geoBoundingBox.arguments.error": "Au moins un des groupes de paramètres suivants doit être fourni : {parameters}.", - "data.search.searchSource.fetch.shardsFailedNotificationMessage": "Échec de {shardsFailed} des {shardsTotal} partitions", "data.search.searchSource.indexPatternIdDescription": "ID dans l'index {kibanaIndexPattern}.", "data.search.searchSource.queryTimeValue": "{queryTime} ms", "data.search.searchSource.requestTimeValue": "{requestTime} ms", @@ -2064,15 +2063,7 @@ "data.search.searchSource.dataViewDescription": "La vue de données qui a été interrogée.", "data.search.searchSource.dataViewIdLabel": "ID de vue de données", "data.search.searchSource.dataViewLabel": "Vue de données", - "data.search.searchSource.fetch.requestTimedOutNotificationMessage": "Les données peuvent être incomplètes parce que votre requête est arrivée à échéance.", - "data.search.searchSource.fetch.shardsFailedModal.close": "Fermer", - "data.search.searchSource.fetch.shardsFailedModal.copyToClipboard": "Copier la réponse dans le presse-papiers", - "data.search.searchSource.fetch.shardsFailedModal.showDetails": "Afficher les détails", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "Requête", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "Réponse", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "Échecs de partition", "data.search.searchSource.fetch.shardsFailedModal.tableColReason": "Raison", - "data.search.searchSource.fetch.shardsFailedNotificationDescription": "Les données peuvent être incomplètes ou erronées.", "data.search.searchSource.hitsDescription": "Le nombre de documents renvoyés par la requête.", "data.search.searchSource.hitsLabel": "Résultats", "data.search.searchSource.hitsTotalDescription": "Le nombre de documents correspondant à la requête.", @@ -11310,11 +11301,8 @@ "xpack.csp.awsIntegration.sharedCredentialsDescription": "Si vous utilisez différentes informations d'identification AWS pour différents outils ou applications, vous pouvez utiliser les profils pour définir plusieurs clés d'accès dans le même fichier de configuration.", "xpack.csp.awsIntegration.temporaryKeysDescription": "Vous pouvez configurer dans AWS des informations d'identification de sécurité temporaires pour une durée spécifiée. Elles comprennent un ID de clé d'accès, une clé d'accès secrète et un jeton de sécurité, qui peut généralement être récupéré à l'aide de GetSessionToken.", "xpack.csp.awsIntegration.temporaryKeysLabel": "Clés temporaires", - "xpack.csp.benchmarks.benchmarkEmptyState.integrationsNotFoundTitle": "Aucune intégration Benchmark trouvée", - "xpack.csp.benchmarks.benchmarkEmptyState.integrationsNotFoundWithFiltersTitle": "Nous n'avons trouvé aucune intégration Benchmark avec les filtres ci-dessus.", "xpack.csp.benchmarks.benchmarkSearchField.searchPlaceholder": "Rechercher par nom d'intégration", "xpack.csp.benchmarks.benchmarksPageHeader.addIntegrationButtonLabel": "Ajouter une intégration", - "xpack.csp.benchmarks.benchmarksPageHeader.benchmarkIntegrationsTitle": "Intégrations Benchmark", "xpack.csp.benchmarks.benchmarksTable.agentPolicyColumnTitle": "Politique d'agent", "xpack.csp.benchmarks.benchmarksTable.createdAtColumnTitle": "Créé", "xpack.csp.benchmarks.benchmarksTable.createdByColumnTitle": "Créé par", @@ -11528,7 +11516,6 @@ "xpack.csp.rules.manageIntegrationButtonLabel": "Gérer l'intégration", "xpack.csp.rules.ruleFlyout.overviewTabLabel": "Aperçu", "xpack.csp.rules.ruleFlyout.remediationTabLabel": "Résolution", - "xpack.csp.rules.rulesPageHeader.benchmarkIntegrationsButtonLabel": "Intégrations Benchmark", "xpack.csp.rules.rulesPageSharedValues.benchmarkTitle": "Benchmark", "xpack.csp.rules.rulesPageSharedValues.deploymentTypeTitle": "Type de déploiement", "xpack.csp.rules.rulesPageSharedValues.integrationTitle": "Intégration", @@ -24115,13 +24102,7 @@ "xpack.ml.jobSelector.noResultsForJobLabel": "Aucun résultat", "xpack.ml.jobSelector.selectAllGroupLabel": "Tout sélectionner", "xpack.ml.jobSelector.selectAllOptionLabel": "*", - "xpack.ml.jobService.activeDatafeedsLabel": "Flux de données actifs", - "xpack.ml.jobService.activeMLNodesLabel": "Nœuds de ML actifs", - "xpack.ml.jobService.closedJobsLabel": "Tâches fermées", - "xpack.ml.jobService.failedJobsLabel": "Tâches échouées", "xpack.ml.jobService.jobAuditMessagesErrorTitle": "Erreur lors du chargement des messages liés à la tâche", - "xpack.ml.jobService.openJobsLabel": "Ouvrir les tâches", - "xpack.ml.jobService.totalJobsLabel": "Total de tâches", "xpack.ml.jobService.validateJobErrorTitle": "Erreur de validation de tâche", "xpack.ml.jobsHealthAlertingRule.actionGroupName": "Problème détecté", "xpack.ml.jobsHealthAlertingRule.name": "Intégrité des tâches de détection des anomalies", @@ -27103,7 +27084,6 @@ "xpack.observability_onboarding.selectLogs.useOwnShipper.description": "Utilisez votre propre agent de transfert pour collecter des données de logs en générant une clé d’API.", "xpack.observability_onboarding.steps.back": "Retour", "xpack.observability_onboarding.steps.exploreLogs": "Explorer les logs", - "xpack.observability_onboarding.steps.inspect": "Inspecter", "xpack.observability_onboarding.title.collectCustomLogs": "Collectez des logs personnalisés", "xpack.observability.apmEnableContinuousRollupsDescription": "{betaLabel} Lorsque les cumuls continus sont activés, l'interface utilisateur sélectionne des indicateurs ayant la résolution appropriée. Sur des plages temporelles plus larges, des indicateurs de résolution inférieure sont utilisés, ce qui améliore les temps de chargement.", "xpack.observability.apmEnableServiceMetricsDescription": "{betaLabel} Permet l'utilisation d'indicateurs de transaction de service. Il s'agit d'indicateurs à faible cardinalité qui peuvent être utilisés par certaines vues, comme l'inventaire de service, pour accélérer le chargement.", @@ -29887,8 +29867,6 @@ "xpack.securitySolution.exceptions.viewer.lastUpdated": "Mis à jour {updated}", "xpack.securitySolution.exceptions.viewer.paginationDetails": "Affichage de {partOne} sur {partTwo}", "xpack.securitySolution.fieldBrowser.descriptionForScreenReaderOnly": "Description pour le champ {field} :", - "xpack.securitySolution.flyout.errorMessage": "Une erreur est survenue lors de l'affichage de {message}", - "xpack.securitySolution.flyout.errorTitle": "Impossible d'afficher {title}", "xpack.securitySolution.footer.autoRefreshActiveTooltip": "Lorsque le rafraîchissement automatique est activé, la chronologie vous montre les {numberOfItems} derniers événements qui correspondent à votre requête.", "xpack.securitySolution.formattedNumber.countsLabel": "{mantissa}{scale}{hasRemainder}", "xpack.securitySolution.header.editableTitle.editButtonAria": "Vous pouvez modifier {title} en cliquant", @@ -33105,70 +33083,9 @@ "xpack.securitySolution.fleetIntegration.assets.name": "Hôtes", "xpack.securitySolution.fleetIntegration.elasticDefend.eventFilter.nonInteractiveSessions.description": "Filtre d'événement pour Cloud Security. Créé par l'intégration Elastic Defend.", "xpack.securitySolution.fleetIntegration.elasticDefend.eventFilter.nonInteractiveSessions.name": "Sessions non interactives", - "xpack.securitySolution.flyout.analyzerErrorMessage": "analyseur", "xpack.securitySolution.flyout.button.timeline": "chronologie", - "xpack.securitySolution.flyout.correlations.caseNameColumnTitle": "Nom", - "xpack.securitySolution.flyout.correlations.reasonColumnTitle": "Raison", - "xpack.securitySolution.flyout.correlations.ruleColumnTitle": "Règle", - "xpack.securitySolution.flyout.correlations.severityColumnTitle": "Sévérité", - "xpack.securitySolution.flyout.correlations.statusColumnTitle": "Statut", - "xpack.securitySolution.flyout.correlations.timestampColumnTitle": "Horodatage", - "xpack.securitySolution.flyout.documentDetails.alertReasonTitle": "Raison d'alerte", - "xpack.securitySolution.flyout.documentDetails.analyzerGraphButton": "Graph Analyseur", - "xpack.securitySolution.flyout.documentDetails.analyzerPreviewTitle": "Aperçu de l'analyseur", - "xpack.securitySolution.flyout.documentDetails.collapseDetailButton": "Réduire les détails de l'alerte", - "xpack.securitySolution.flyout.documentDetails.correlationsButton": "Corrélations", - "xpack.securitySolution.flyout.documentDetails.correlationsTitle": "Corrélations", - "xpack.securitySolution.flyout.documentDetails.documentDescriptionTitle": "Description du document", - "xpack.securitySolution.flyout.documentDetails.documentReasonTitle": "Motif du document", - "xpack.securitySolution.flyout.documentDetails.entitiesButton": "Entités", - "xpack.securitySolution.flyout.documentDetails.entitiesTitle": "Entités", - "xpack.securitySolution.flyout.documentDetails.expandDetailButton": "Développer les détails de l'alerte", - "xpack.securitySolution.flyout.documentDetails.highlightedFieldsTitle": "Champs en surbrillance", - "xpack.securitySolution.flyout.documentDetails.insightsOptions": "Options des informations exploitables", - "xpack.securitySolution.flyout.documentDetails.insightsTab": "Informations exploitables", - "xpack.securitySolution.flyout.documentDetails.insightsTitle": "Informations exploitables", - "xpack.securitySolution.flyout.documentDetails.investigationSectionTitle": "Investigation", - "xpack.securitySolution.flyout.documentDetails.investigationsTab": "Investigation", - "xpack.securitySolution.flyout.documentDetails.jsonTab": "JSON", - "xpack.securitySolution.flyout.documentDetails.overviewTab": "Aperçu", - "xpack.securitySolution.flyout.documentDetails.overviewTab.prevalenceRowText": "est inhabituel", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichment": "champ enrichi avec la Threat Intelligence", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichments": "champs enrichis avec la Threat Intelligence", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatch": "correspondance de menace détectée", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatches": "correspondances de menaces détectées", - "xpack.securitySolution.flyout.documentDetails.prevalenceButton": "Prévalence", - "xpack.securitySolution.flyout.documentDetails.prevalenceTitle": "Prévalence", - "xpack.securitySolution.flyout.documentDetails.riskScoreTitle": "Score de risque", - "xpack.securitySolution.flyout.documentDetails.ruleDescriptionTitle": "Description de la règle", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.commandText": "par", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.processText": "démarré", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.ruleText": "avec la règle", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.timeText": "à", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.title": "Aperçu du visualiseur de session", - "xpack.securitySolution.flyout.documentDetails.sessionViewButton": "Vue de session", - "xpack.securitySolution.flyout.documentDetails.severityTitle": "Sévérité", - "xpack.securitySolution.flyout.documentDetails.share": "Partager l'alerte", - "xpack.securitySolution.flyout.documentDetails.tableTab": "Tableau", - "xpack.securitySolution.flyout.documentDetails.threatIntelligenceButton": "Threat Intelligence", - "xpack.securitySolution.flyout.documentDetails.threatIntelligenceTitle": "Threat Intelligence", - "xpack.securitySolution.flyout.documentDetails.visualizationsTitle": "Visualisations", - "xpack.securitySolution.flyout.documentDetails.visualizeOptions": "Options Visualize", - "xpack.securitySolution.flyout.documentDetails.visualizeTab": "Visualiser", - "xpack.securitySolution.flyout.documentErrorMessage": "les valeurs et champs du document", - "xpack.securitySolution.flyout.documentErrorTitle": "informations du document", "xpack.securitySolution.flyout.entities.failRelatedHostsDescription": "Impossible de lancer la recherche sur les hôtes associés", "xpack.securitySolution.flyout.entities.failRelatedUsersDescription": "Impossible de lancer la recherche sur les utilisateurs associés", - "xpack.securitySolution.flyout.entities.hostsInfoTitle": "Informations sur l’hôte", - "xpack.securitySolution.flyout.entities.relatedEntitiesIpColumn": "Adresses IP", - "xpack.securitySolution.flyout.entities.relatedEntitiesNameColumn": "Nom", - "xpack.securitySolution.flyout.entities.relatedHostsTitle": "Hôtes associés", - "xpack.securitySolution.flyout.entities.relatedUsersTitle": "Utilisateurs associés", - "xpack.securitySolution.flyout.entities.usersInfoTitle": "Informations sur l’utilisateur", - "xpack.securitySolution.flyout.prevalenceTableAlertCountColumnTitle": "Nombre d'alertes", - "xpack.securitySolution.flyout.prevalenceTableDocCountColumnTitle": "Compte du document", - "xpack.securitySolution.flyout.response.title": "Réponses", - "xpack.securitySolution.flyout.sessionViewErrorMessage": "vue de session", "xpack.securitySolution.footer.autoRefreshActiveDescription": "Actualisation automatique active", "xpack.securitySolution.footer.cancel": "Annuler", "xpack.securitySolution.footer.data": "données", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a8cc0445a4a12..00df50d572e22 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1331,7 +1331,6 @@ "data.search.aggs.rareTerms.aggTypesLabel": "{fieldName}の希少な用語", "data.search.es_search.queryTimeValue": "{queryTime}ms", "data.search.functions.geoBoundingBox.arguments.error": "次のパラメーターのグループの1つ以上を指定する必要があります:{parameters}。", - "data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal}件中{shardsFailed}件のシャードでエラーが発生しました", "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern}インデックス内のIDです。", "data.search.searchSource.queryTimeValue": "{queryTime}ms", "data.search.searchSource.requestTimeValue": "{requestTime}ms", @@ -2078,15 +2077,7 @@ "data.search.searchSource.dataViewDescription": "照会されたデータビュー。", "data.search.searchSource.dataViewIdLabel": "データビューID", "data.search.searchSource.dataViewLabel": "データビュー", - "data.search.searchSource.fetch.requestTimedOutNotificationMessage": "リクエストがタイムアウトしたため、データが不完全な可能性があります", - "data.search.searchSource.fetch.shardsFailedModal.close": "閉じる", - "data.search.searchSource.fetch.shardsFailedModal.copyToClipboard": "応答をクリップボードにコピー", - "data.search.searchSource.fetch.shardsFailedModal.showDetails": "詳細を表示", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "リクエスト", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "応答", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "シャードエラー", "data.search.searchSource.fetch.shardsFailedModal.tableColReason": "理由", - "data.search.searchSource.fetch.shardsFailedNotificationDescription": "データが不完全か誤りの可能性があります。", "data.search.searchSource.hitsDescription": "クエリにより返されたドキュメントの数です。", "data.search.searchSource.hitsLabel": "ヒット数", "data.search.searchSource.hitsTotalDescription": "クエリに一致するドキュメントの数です。", @@ -11325,11 +11316,8 @@ "xpack.csp.awsIntegration.sharedCredentialsDescription": "ツールやアプリケーションごとに異なるAWS認証情報を使用する場合、プロファイルを使用して、同じ設定ファイルに複数のアクセスキーを定義することができます。", "xpack.csp.awsIntegration.temporaryKeysDescription": "AWSの一時的なセキュリティ認証情報は、指定した期間だけ存続するように設定することができます。アクセスキーID、シークレットアクセスキー、セキュリティトークンから構成され、通常GetSessionTokenで確認することができます。", "xpack.csp.awsIntegration.temporaryKeysLabel": "一時キー", - "xpack.csp.benchmarks.benchmarkEmptyState.integrationsNotFoundTitle": "ベンチマーク統合が見つかりません", - "xpack.csp.benchmarks.benchmarkEmptyState.integrationsNotFoundWithFiltersTitle": "上記のフィルターでベンチマーク統合が見つかりませんでした。", "xpack.csp.benchmarks.benchmarkSearchField.searchPlaceholder": "統合名で検索", "xpack.csp.benchmarks.benchmarksPageHeader.addIntegrationButtonLabel": "統合の追加", - "xpack.csp.benchmarks.benchmarksPageHeader.benchmarkIntegrationsTitle": "ベンチマーク統合", "xpack.csp.benchmarks.benchmarksTable.agentPolicyColumnTitle": "エージェントポリシー", "xpack.csp.benchmarks.benchmarksTable.createdAtColumnTitle": "作成済み", "xpack.csp.benchmarks.benchmarksTable.createdByColumnTitle": "作成者", @@ -11543,7 +11531,6 @@ "xpack.csp.rules.manageIntegrationButtonLabel": "統合を管理", "xpack.csp.rules.ruleFlyout.overviewTabLabel": "概要", "xpack.csp.rules.ruleFlyout.remediationTabLabel": "修正", - "xpack.csp.rules.rulesPageHeader.benchmarkIntegrationsButtonLabel": "ベンチマーク統合", "xpack.csp.rules.rulesPageSharedValues.benchmarkTitle": "ベンチマーク", "xpack.csp.rules.rulesPageSharedValues.deploymentTypeTitle": "デプロイタイプ", "xpack.csp.rules.rulesPageSharedValues.integrationTitle": "統合", @@ -24115,13 +24102,7 @@ "xpack.ml.jobSelector.noResultsForJobLabel": "成果がありません", "xpack.ml.jobSelector.selectAllGroupLabel": "すべて選択", "xpack.ml.jobSelector.selectAllOptionLabel": "*", - "xpack.ml.jobService.activeDatafeedsLabel": "アクティブなデータフィード", - "xpack.ml.jobService.activeMLNodesLabel": "アクティブな ML ノード", - "xpack.ml.jobService.closedJobsLabel": "ジョブを作成", - "xpack.ml.jobService.failedJobsLabel": "失敗したジョブ", "xpack.ml.jobService.jobAuditMessagesErrorTitle": "ジョブメッセージの読み込みエラー", - "xpack.ml.jobService.openJobsLabel": "ジョブを開く", - "xpack.ml.jobService.totalJobsLabel": "合計ジョブ数", "xpack.ml.jobService.validateJobErrorTitle": "ジョブ検証エラー", "xpack.ml.jobsHealthAlertingRule.actionGroupName": "問題が検出されました", "xpack.ml.jobsHealthAlertingRule.name": "異常検知ジョブヘルス", @@ -27103,7 +27084,6 @@ "xpack.observability_onboarding.selectLogs.useOwnShipper.description": "APIキーを生成し、ログデータを収集するために独自のシッパーを使用します。", "xpack.observability_onboarding.steps.back": "戻る", "xpack.observability_onboarding.steps.exploreLogs": "ログを探索", - "xpack.observability_onboarding.steps.inspect": "検査", "xpack.observability_onboarding.title.collectCustomLogs": "カスタムログを収集", "xpack.observability.apmEnableContinuousRollupsDescription": "{betaLabel}連続ロールアップが有効な場合、UIは適切な解像度でメトリックを選択します。より大きな時間範囲では、より低い解像度の測定基準が使用され、読み込み時間が改善されます。", "xpack.observability.apmEnableServiceMetricsDescription": "{betaLabel}サービストランザクションメトリックの使用を有効にします。これは、サービスインベントリなどの特定のビューで使用できる低カーディナリティのメトリックで、読み込み時間を短縮します。", @@ -29886,8 +29866,6 @@ "xpack.securitySolution.exceptions.viewer.lastUpdated": "{updated}を更新しました", "xpack.securitySolution.exceptions.viewer.paginationDetails": "{partOne}/{partTwo}ページを表示中", "xpack.securitySolution.fieldBrowser.descriptionForScreenReaderOnly": "フィールド{field}の説明:", - "xpack.securitySolution.flyout.errorMessage": "{message}の表示中にエラーが発生しました", - "xpack.securitySolution.flyout.errorTitle": "{title}を表示できません", "xpack.securitySolution.footer.autoRefreshActiveTooltip": "自動更新が有効な間、タイムラインはクエリに一致する直近{numberOfItems}件のイベントを表示します。", "xpack.securitySolution.formattedNumber.countsLabel": "{mantissa}{scale}{hasRemainder}", "xpack.securitySolution.header.editableTitle.editButtonAria": "クリックすると{title}を編集できます", @@ -33104,70 +33082,9 @@ "xpack.securitySolution.fleetIntegration.assets.name": "ホスト", "xpack.securitySolution.fleetIntegration.elasticDefend.eventFilter.nonInteractiveSessions.description": "クラウドセキュリティのイベントフィルター。Elastic Defend統合によって作成。", "xpack.securitySolution.fleetIntegration.elasticDefend.eventFilter.nonInteractiveSessions.name": "非インタラクティブセッション", - "xpack.securitySolution.flyout.analyzerErrorMessage": "アナライザー", "xpack.securitySolution.flyout.button.timeline": "タイムライン", - "xpack.securitySolution.flyout.correlations.caseNameColumnTitle": "名前", - "xpack.securitySolution.flyout.correlations.reasonColumnTitle": "理由", - "xpack.securitySolution.flyout.correlations.ruleColumnTitle": "ルール", - "xpack.securitySolution.flyout.correlations.severityColumnTitle": "深刻度", - "xpack.securitySolution.flyout.correlations.statusColumnTitle": "ステータス", - "xpack.securitySolution.flyout.correlations.timestampColumnTitle": "タイムスタンプ", - "xpack.securitySolution.flyout.documentDetails.alertReasonTitle": "アラートの理由", - "xpack.securitySolution.flyout.documentDetails.analyzerGraphButton": "アナライザーグラフ", - "xpack.securitySolution.flyout.documentDetails.analyzerPreviewTitle": "アナライザープレビュー", - "xpack.securitySolution.flyout.documentDetails.collapseDetailButton": "アラート詳細を折りたたむ", - "xpack.securitySolution.flyout.documentDetails.correlationsButton": "相関関係", - "xpack.securitySolution.flyout.documentDetails.correlationsTitle": "相関関係", - "xpack.securitySolution.flyout.documentDetails.documentDescriptionTitle": "ドキュメント説明", - "xpack.securitySolution.flyout.documentDetails.documentReasonTitle": "ドキュメント理由", - "xpack.securitySolution.flyout.documentDetails.entitiesButton": "エンティティ", - "xpack.securitySolution.flyout.documentDetails.entitiesTitle": "エンティティ", - "xpack.securitySolution.flyout.documentDetails.expandDetailButton": "アラート詳細を展開", - "xpack.securitySolution.flyout.documentDetails.highlightedFieldsTitle": "ハイライトされたフィールド", - "xpack.securitySolution.flyout.documentDetails.insightsOptions": "インサイトオプション", - "xpack.securitySolution.flyout.documentDetails.insightsTab": "インサイト", - "xpack.securitySolution.flyout.documentDetails.insightsTitle": "インサイト", - "xpack.securitySolution.flyout.documentDetails.investigationSectionTitle": "調査", - "xpack.securitySolution.flyout.documentDetails.investigationsTab": "調査", - "xpack.securitySolution.flyout.documentDetails.jsonTab": "JSON", - "xpack.securitySolution.flyout.documentDetails.overviewTab": "概要", - "xpack.securitySolution.flyout.documentDetails.overviewTab.prevalenceRowText": "共通しない", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichment": "脅威インテリジェンスで拡張されたフィールド", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichments": "脅威インテリジェンスで拡張されたフィールド", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatch": "脅威一致が検出されました", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatches": "脅威一致が検出されました", - "xpack.securitySolution.flyout.documentDetails.prevalenceButton": "発生率", - "xpack.securitySolution.flyout.documentDetails.prevalenceTitle": "発生率", - "xpack.securitySolution.flyout.documentDetails.riskScoreTitle": "リスクスコア", - "xpack.securitySolution.flyout.documentDetails.ruleDescriptionTitle": "ルールの説明", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.commandText": "グループ基準", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.processText": "開始済み", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.ruleText": "ルールがある", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.timeText": "に", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.title": "セッションビューアープレビュー", - "xpack.securitySolution.flyout.documentDetails.sessionViewButton": "セッションビュー", - "xpack.securitySolution.flyout.documentDetails.severityTitle": "深刻度", - "xpack.securitySolution.flyout.documentDetails.share": "アラートを共有", - "xpack.securitySolution.flyout.documentDetails.tableTab": "表", - "xpack.securitySolution.flyout.documentDetails.threatIntelligenceButton": "脅威インテリジェンス", - "xpack.securitySolution.flyout.documentDetails.threatIntelligenceTitle": "脅威インテリジェンス", - "xpack.securitySolution.flyout.documentDetails.visualizationsTitle": "ビジュアライゼーション", - "xpack.securitySolution.flyout.documentDetails.visualizeOptions": "Visualizeオプション", - "xpack.securitySolution.flyout.documentDetails.visualizeTab": "可視化", - "xpack.securitySolution.flyout.documentErrorMessage": "ドキュメントフィールドおよび値", - "xpack.securitySolution.flyout.documentErrorTitle": "ドキュメント情報", "xpack.securitySolution.flyout.entities.failRelatedHostsDescription": "関連するホストで検索を実行できませんでした", "xpack.securitySolution.flyout.entities.failRelatedUsersDescription": "関連するユーザーで検索を実行できませんでした", - "xpack.securitySolution.flyout.entities.hostsInfoTitle": "ホスト情報", - "xpack.securitySolution.flyout.entities.relatedEntitiesIpColumn": "IPアドレス", - "xpack.securitySolution.flyout.entities.relatedEntitiesNameColumn": "名前", - "xpack.securitySolution.flyout.entities.relatedHostsTitle": "関連するホスト", - "xpack.securitySolution.flyout.entities.relatedUsersTitle": "関連するユーザー", - "xpack.securitySolution.flyout.entities.usersInfoTitle": "ユーザー情報", - "xpack.securitySolution.flyout.prevalenceTableAlertCountColumnTitle": "アラート件数", - "xpack.securitySolution.flyout.prevalenceTableDocCountColumnTitle": "ドキュメントカウント", - "xpack.securitySolution.flyout.response.title": "対応", - "xpack.securitySolution.flyout.sessionViewErrorMessage": "セッションビュー", "xpack.securitySolution.footer.autoRefreshActiveDescription": "自動更新アクション", "xpack.securitySolution.footer.cancel": "キャンセル", "xpack.securitySolution.footer.data": "データ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9c5c310d41a15..7c0d74cc40459 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1331,7 +1331,6 @@ "data.search.aggs.rareTerms.aggTypesLabel": "{fieldName} 的稀有词", "data.search.es_search.queryTimeValue": "{queryTime}ms", "data.search.functions.geoBoundingBox.arguments.error": "必须至少提供一个以下参数组:{parameters}。", - "data.search.searchSource.fetch.shardsFailedNotificationMessage": "{shardsTotal} 个分片有 {shardsFailed} 个失败", "data.search.searchSource.indexPatternIdDescription": "{kibanaIndexPattern} 索引中的 ID。", "data.search.searchSource.queryTimeValue": "{queryTime}ms", "data.search.searchSource.requestTimeValue": "{requestTime}ms", @@ -2078,15 +2077,7 @@ "data.search.searchSource.dataViewDescription": "被查询的数据视图。", "data.search.searchSource.dataViewIdLabel": "数据视图 ID", "data.search.searchSource.dataViewLabel": "数据视图", - "data.search.searchSource.fetch.requestTimedOutNotificationMessage": "由于您的请求超时,数据可能不完整", - "data.search.searchSource.fetch.shardsFailedModal.close": "关闭", - "data.search.searchSource.fetch.shardsFailedModal.copyToClipboard": "将响应复制到剪贴板", - "data.search.searchSource.fetch.shardsFailedModal.showDetails": "显示详情", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderRequest": "请求", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderResponse": "响应", - "data.search.searchSource.fetch.shardsFailedModal.tabHeaderShardFailures": "分片错误", "data.search.searchSource.fetch.shardsFailedModal.tableColReason": "原因", - "data.search.searchSource.fetch.shardsFailedNotificationDescription": "数据可能不完整或有错误。", "data.search.searchSource.hitsDescription": "查询返回的文档数目。", "data.search.searchSource.hitsLabel": "命中数", "data.search.searchSource.hitsTotalDescription": "与查询匹配的文档数目。", @@ -11325,11 +11316,8 @@ "xpack.csp.awsIntegration.sharedCredentialsDescription": "如果对不同工具或应用程序使用不同的 AWS 凭据,可以使用配置文件在同一配置文件中定义多个访问密钥。", "xpack.csp.awsIntegration.temporaryKeysDescription": "您可以在 AWS 中配置在指定持续时间内有效的临时安全凭据。它们包括访问密钥 ID、机密访问密钥和安全令牌(通常使用 GetSessionToken 查找)。", "xpack.csp.awsIntegration.temporaryKeysLabel": "临时密钥", - "xpack.csp.benchmarks.benchmarkEmptyState.integrationsNotFoundTitle": "找不到基准集成", - "xpack.csp.benchmarks.benchmarkEmptyState.integrationsNotFoundWithFiltersTitle": "使用上述筛选,我们无法找到任何基准集成。", "xpack.csp.benchmarks.benchmarkSearchField.searchPlaceholder": "按集成名称搜索", "xpack.csp.benchmarks.benchmarksPageHeader.addIntegrationButtonLabel": "添加集成", - "xpack.csp.benchmarks.benchmarksPageHeader.benchmarkIntegrationsTitle": "基准集成", "xpack.csp.benchmarks.benchmarksTable.agentPolicyColumnTitle": "代理策略", "xpack.csp.benchmarks.benchmarksTable.createdAtColumnTitle": "创建时间", "xpack.csp.benchmarks.benchmarksTable.createdByColumnTitle": "创建者", @@ -11543,7 +11531,6 @@ "xpack.csp.rules.manageIntegrationButtonLabel": "管理集成", "xpack.csp.rules.ruleFlyout.overviewTabLabel": "概览", "xpack.csp.rules.ruleFlyout.remediationTabLabel": "补救", - "xpack.csp.rules.rulesPageHeader.benchmarkIntegrationsButtonLabel": "基准集成", "xpack.csp.rules.rulesPageSharedValues.benchmarkTitle": "基准", "xpack.csp.rules.rulesPageSharedValues.deploymentTypeTitle": "部署类型", "xpack.csp.rules.rulesPageSharedValues.integrationTitle": "集成", @@ -24114,13 +24101,7 @@ "xpack.ml.jobSelector.noResultsForJobLabel": "无结果", "xpack.ml.jobSelector.selectAllGroupLabel": "全选", "xpack.ml.jobSelector.selectAllOptionLabel": "*", - "xpack.ml.jobService.activeDatafeedsLabel": "活动数据馈送", - "xpack.ml.jobService.activeMLNodesLabel": "活动 ML 节点", - "xpack.ml.jobService.closedJobsLabel": "已关闭的作业", - "xpack.ml.jobService.failedJobsLabel": "失败的作业", "xpack.ml.jobService.jobAuditMessagesErrorTitle": "加载作业消息时出错", - "xpack.ml.jobService.openJobsLabel": "打开的作业", - "xpack.ml.jobService.totalJobsLabel": "总计作业数", "xpack.ml.jobService.validateJobErrorTitle": "作业验证错误", "xpack.ml.jobsHealthAlertingRule.actionGroupName": "检测到问题", "xpack.ml.jobsHealthAlertingRule.name": "异常检测作业运行状况", @@ -27101,7 +27082,6 @@ "xpack.observability_onboarding.selectLogs.useOwnShipper.description": "通过生成 API 密钥使用您自己的采集器来收集日志数据。", "xpack.observability_onboarding.steps.back": "返回", "xpack.observability_onboarding.steps.exploreLogs": "浏览日志", - "xpack.observability_onboarding.steps.inspect": "检查", "xpack.observability_onboarding.title.collectCustomLogs": "收集定制日志", "xpack.observability.apmEnableContinuousRollupsDescription": "{betaLabel} 启用连续汇总/打包时,UI 将以适当分辨率选择指标。在更大时间范围内,将使用分辨率较低的指标,这会缩短加载时间。", "xpack.observability.apmEnableServiceMetricsDescription": "{betaLabel} 启用服务事务指标,这种是低基数指标,可供某些视图(如服务库存)使用来加快加载速度。", @@ -29882,8 +29862,6 @@ "xpack.securitySolution.exceptions.viewer.lastUpdated": "已更新 {updated}", "xpack.securitySolution.exceptions.viewer.paginationDetails": "正在显示 {partOne} 个,共 {partTwo} 个", "xpack.securitySolution.fieldBrowser.descriptionForScreenReaderOnly": "{field} 字段的描述:", - "xpack.securitySolution.flyout.errorMessage": "显示 {message} 时出现错误", - "xpack.securitySolution.flyout.errorTitle": "无法显示 {title}", "xpack.securitySolution.footer.autoRefreshActiveTooltip": "自动刷新已启用时,时间线将显示匹配查询的最近 {numberOfItems} 个事件。", "xpack.securitySolution.formattedNumber.countsLabel": "{mantissa}{scale}{hasRemainder}", "xpack.securitySolution.header.editableTitle.editButtonAria": "通过单击,可以编辑 {title}", @@ -33100,70 +33078,9 @@ "xpack.securitySolution.fleetIntegration.assets.name": "主机", "xpack.securitySolution.fleetIntegration.elasticDefend.eventFilter.nonInteractiveSessions.description": "云安全事件筛选。已由 Elastic Defend 集成创建。", "xpack.securitySolution.fleetIntegration.elasticDefend.eventFilter.nonInteractiveSessions.name": "非交互式会话", - "xpack.securitySolution.flyout.analyzerErrorMessage": "分析器", "xpack.securitySolution.flyout.button.timeline": "时间线", - "xpack.securitySolution.flyout.correlations.caseNameColumnTitle": "名称", - "xpack.securitySolution.flyout.correlations.reasonColumnTitle": "原因", - "xpack.securitySolution.flyout.correlations.ruleColumnTitle": "规则", - "xpack.securitySolution.flyout.correlations.severityColumnTitle": "严重性", - "xpack.securitySolution.flyout.correlations.statusColumnTitle": "状态", - "xpack.securitySolution.flyout.correlations.timestampColumnTitle": "时间戳", - "xpack.securitySolution.flyout.documentDetails.alertReasonTitle": "告警原因", - "xpack.securitySolution.flyout.documentDetails.analyzerGraphButton": "分析器图表", - "xpack.securitySolution.flyout.documentDetails.analyzerPreviewTitle": "分析器预览", - "xpack.securitySolution.flyout.documentDetails.collapseDetailButton": "折叠告警详情", - "xpack.securitySolution.flyout.documentDetails.correlationsButton": "相关性", - "xpack.securitySolution.flyout.documentDetails.correlationsTitle": "相关性", - "xpack.securitySolution.flyout.documentDetails.documentDescriptionTitle": "文档描述", - "xpack.securitySolution.flyout.documentDetails.documentReasonTitle": "文档原因", - "xpack.securitySolution.flyout.documentDetails.entitiesButton": "实体", - "xpack.securitySolution.flyout.documentDetails.entitiesTitle": "实体", - "xpack.securitySolution.flyout.documentDetails.expandDetailButton": "展开告警详情", - "xpack.securitySolution.flyout.documentDetails.highlightedFieldsTitle": "突出显示的字段", - "xpack.securitySolution.flyout.documentDetails.insightsOptions": "洞见选项", - "xpack.securitySolution.flyout.documentDetails.insightsTab": "洞见", - "xpack.securitySolution.flyout.documentDetails.insightsTitle": "洞见", - "xpack.securitySolution.flyout.documentDetails.investigationSectionTitle": "调查", - "xpack.securitySolution.flyout.documentDetails.investigationsTab": "调查", - "xpack.securitySolution.flyout.documentDetails.jsonTab": "JSON", - "xpack.securitySolution.flyout.documentDetails.overviewTab": "概览", - "xpack.securitySolution.flyout.documentDetails.overviewTab.prevalenceRowText": "不常见", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichment": "已使用威胁情报扩充字段", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatEnrichments": "已使用威胁情报扩充字段", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatch": "检测到威胁匹配", - "xpack.securitySolution.flyout.documentDetails.overviewTab.threatIntelligence.threatMatches": "检测到威胁匹配", - "xpack.securitySolution.flyout.documentDetails.prevalenceButton": "普及率", - "xpack.securitySolution.flyout.documentDetails.prevalenceTitle": "普及率", - "xpack.securitySolution.flyout.documentDetails.riskScoreTitle": "风险分数", - "xpack.securitySolution.flyout.documentDetails.ruleDescriptionTitle": "规则描述", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.commandText": "依据", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.processText": "已启动", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.ruleText": "具有规则", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.timeText": "处于", - "xpack.securitySolution.flyout.documentDetails.sessionPreview.title": "会话查看器预览", - "xpack.securitySolution.flyout.documentDetails.sessionViewButton": "会话视图", - "xpack.securitySolution.flyout.documentDetails.severityTitle": "严重性", - "xpack.securitySolution.flyout.documentDetails.share": "共享告警", - "xpack.securitySolution.flyout.documentDetails.tableTab": "表", - "xpack.securitySolution.flyout.documentDetails.threatIntelligenceButton": "威胁情报", - "xpack.securitySolution.flyout.documentDetails.threatIntelligenceTitle": "威胁情报", - "xpack.securitySolution.flyout.documentDetails.visualizationsTitle": "可视化", - "xpack.securitySolution.flyout.documentDetails.visualizeOptions": "Visualize 选项", - "xpack.securitySolution.flyout.documentDetails.visualizeTab": "Visualize", - "xpack.securitySolution.flyout.documentErrorMessage": "文档字段和值", - "xpack.securitySolution.flyout.documentErrorTitle": "文档信息", "xpack.securitySolution.flyout.entities.failRelatedHostsDescription": "无法对相关主机执行搜索", "xpack.securitySolution.flyout.entities.failRelatedUsersDescription": "无法对相关用户执行搜索", - "xpack.securitySolution.flyout.entities.hostsInfoTitle": "主机信息", - "xpack.securitySolution.flyout.entities.relatedEntitiesIpColumn": "IP 地址", - "xpack.securitySolution.flyout.entities.relatedEntitiesNameColumn": "名称", - "xpack.securitySolution.flyout.entities.relatedHostsTitle": "相关主机", - "xpack.securitySolution.flyout.entities.relatedUsersTitle": "相关用户", - "xpack.securitySolution.flyout.entities.usersInfoTitle": "用户信息", - "xpack.securitySolution.flyout.prevalenceTableAlertCountColumnTitle": "告警计数", - "xpack.securitySolution.flyout.prevalenceTableDocCountColumnTitle": "文档计数", - "xpack.securitySolution.flyout.response.title": "响应", - "xpack.securitySolution.flyout.sessionViewErrorMessage": "会话视图", "xpack.securitySolution.footer.autoRefreshActiveDescription": "自动刷新已启用", "xpack.securitySolution.footer.cancel": "取消", "xpack.securitySolution.footer.data": "数据", diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts index b6c86b49c7fba..e80a8f94d93b6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/alerts_as_data/install_resources.ts @@ -163,6 +163,7 @@ export default function createAlertsAsDataInstallResourcesTest({ getService }: F rollover_alias: '.alerts-test.patternfiring.alerts-default', }, mapping: { + ignore_malformed: 'true', total_fields: { limit: '2500', }, @@ -196,6 +197,7 @@ export default function createAlertsAsDataInstallResourcesTest({ getService }: F }); expect(contextIndex[indexName].settings?.index?.mapping).to.eql({ + ignore_malformed: 'true', total_fields: { limit: '2500', }, diff --git a/x-pack/test/api_integration/apis/search/search.ts b/x-pack/test/api_integration/apis/search/search.ts index a7bf10ea7dc6c..48ff19e51623d 100644 --- a/x-pack/test/api_integration/apis/search/search.ts +++ b/x-pack/test/api_integration/apis/search/search.ts @@ -455,8 +455,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(404); }); - // FLAKY: https://github.com/elastic/kibana/issues/164856 - it.skip('should delete a completed search', async function () { + it('should delete a completed search', async function () { await markRequiresShardDelayAgg(this); const resp = await supertest @@ -483,7 +482,7 @@ export default function ({ getService }: FtrProviderContext) { await new Promise((resolve) => setTimeout(resolve, 3000)); - await retry.tryForTime(10000, async () => { + await retry.tryForTime(30000, async () => { const resp2 = await supertest .post(`/internal/search/ese/${id}`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') diff --git a/x-pack/test/api_integration/apis/security/privileges.ts b/x-pack/test/api_integration/apis/security/privileges.ts index d49df52bfcd1c..c786a41411a5b 100644 --- a/x-pack/test/api_integration/apis/security/privileges.ts +++ b/x-pack/test/api_integration/apis/security/privileges.ts @@ -55,7 +55,7 @@ export default function ({ getService }: FtrProviderContext) { 'file_operations_all', 'execute_operations_all', ], - uptime: ['all', 'read', 'minimal_all', 'minimal_read'], + uptime: ['all', 'read', 'minimal_all', 'minimal_read', 'elastic_managed_locations_enabled'], securitySolutionAssistant: ['all', 'read', 'minimal_all', 'minimal_read'], securitySolutionCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], infrastructure: ['all', 'read', 'minimal_all', 'minimal_read'], diff --git a/x-pack/test/api_integration/apis/security/privileges_basic.ts b/x-pack/test/api_integration/apis/security/privileges_basic.ts index c6982b3c6d53e..6c6d32c1cb1e9 100644 --- a/x-pack/test/api_integration/apis/security/privileges_basic.ts +++ b/x-pack/test/api_integration/apis/security/privileges_basic.ts @@ -130,7 +130,13 @@ export default function ({ getService }: FtrProviderContext) { 'file_operations_all', 'execute_operations_all', ], - uptime: ['all', 'read', 'minimal_all', 'minimal_read'], + uptime: [ + 'all', + 'elastic_managed_locations_enabled', + 'read', + 'minimal_all', + 'minimal_read', + ], securitySolutionAssistant: ['all', 'read', 'minimal_all', 'minimal_read'], securitySolutionCases: ['all', 'read', 'minimal_all', 'minimal_read', 'cases_delete'], infrastructure: ['all', 'read', 'minimal_all', 'minimal_read'], diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/basic/attachments_framework/registered_persistable_state_basic.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/basic/attachments_framework/registered_persistable_state_basic.ts new file mode 100644 index 0000000000000..bb7ae7d04c418 --- /dev/null +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/basic/attachments_framework/registered_persistable_state_basic.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + /** + * Attachment types are being registered in + * x-pack/test/cases_api_integration/common/plugins/cases/server/plugin.ts + */ + describe('Persistable state attachments', () => { + // This test is intended to fail when new persistable state attachment types are registered. + // To resolve, add the new persistable state attachment types ID to this list. This will trigger + // a CODEOWNERS review by Response Ops. + describe('check registered persistable state attachment types', () => { + const getRegisteredTypes = () => { + return supertest + .get('/api/cases_fixture/registered_persistable_state_attachments') + .expect(200) + .then((response) => response.body); + }; + + it('should check changes on all registered persistable state attachment types', async () => { + const types = await getRegisteredTypes(); + + expect(types).to.eql({ + '.lens': '78559fd806809ac3a1008942ead2a079864054f5', + '.test': 'ab2204830c67f5cf992c9aa2f7e3ead752cc60a1', + aiopsChangePointChart: 'a1212d71947ec34487b374cecc47ab9941b5d91c', + }); + }); + }); + }); +}; diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/basic/index.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/basic/index.ts index 6fc840f873ba1..2750559ca3fb5 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/basic/index.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/basic/index.ts @@ -30,6 +30,7 @@ export default ({ loadTestFile, getService }: FtrProviderContext): void => { loadTestFile(require.resolve('./cases/assignees')); loadTestFile(require.resolve('./cases/push_case')); loadTestFile(require.resolve('./configure/get_connectors')); + loadTestFile(require.resolve('./attachments_framework/registered_persistable_state_basic')); // Internal routes loadTestFile(require.resolve('./internal/suggest_user_profiles')); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/attachments_framework/persistable_state.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/attachments_framework/persistable_state.ts index 8c9701ed58e33..24d9cc5132c64 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/attachments_framework/persistable_state.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/attachments_framework/persistable_state.ts @@ -273,29 +273,5 @@ export default ({ getService }: FtrProviderContext): void => { }); }); }); - - // This test is intended to fail when new persistable state attachment types are registered. - // To resolve, add the new persistable state attachment types ID to this list. This will trigger - // a CODEOWNERS review by Response Ops. - describe('check registered persistable state attachment types', () => { - const getRegisteredTypes = () => { - return supertest - .get('/api/cases_fixture/registered_persistable_state_attachments') - .expect(200) - .then((response) => response.body); - }; - - it('should check changes on all registered persistable state attachment types', async () => { - const types = await getRegisteredTypes(); - - expect(types).to.eql({ - '.lens': '78559fd806809ac3a1008942ead2a079864054f5', - '.test': 'ab2204830c67f5cf992c9aa2f7e3ead752cc60a1', - aiopsChangePointChart: 'a1212d71947ec34487b374cecc47ab9941b5d91c', - ml_anomaly_charts: '23e92e824af9db6e8b8bb1d63c222e04f57d2147', - ml_anomaly_swimlane: 'a3517f3e53fb041e9cbb150477fb6ef0f731bd5f', - }); - }); - }); }); }; diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/attachments_framework/registered_persistable_state_trial.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/attachments_framework/registered_persistable_state_trial.ts new file mode 100644 index 0000000000000..3b2b536b3c88d --- /dev/null +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/attachments_framework/registered_persistable_state_trial.ts @@ -0,0 +1,45 @@ +/* + * 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 '../../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + + /** + * Attachment types are being registered in + * x-pack/test/cases_api_integration/common/plugins/cases/server/plugin.ts + */ + describe('Persistable state attachments', () => { + // This test is intended to fail when new persistable state attachment types are registered. + // To resolve, add the new persistable state attachment types ID to this list. This will trigger + // a CODEOWNERS review by Response Ops. + describe('check registered persistable state attachment types', () => { + const getRegisteredTypes = () => { + return supertest + .get('/api/cases_fixture/registered_persistable_state_attachments') + .expect(200) + .then((response) => response.body); + }; + + it('should check changes on all registered persistable state attachment types', async () => { + const types = await getRegisteredTypes(); + + expect(types).to.eql({ + '.lens': '78559fd806809ac3a1008942ead2a079864054f5', + '.test': 'ab2204830c67f5cf992c9aa2f7e3ead752cc60a1', + aiopsChangePointChart: 'a1212d71947ec34487b374cecc47ab9941b5d91c', + ml_anomaly_charts: '23e92e824af9db6e8b8bb1d63c222e04f57d2147', + ml_anomaly_swimlane: 'a3517f3e53fb041e9cbb150477fb6ef0f731bd5f', + }); + }); + }); + }); +}; diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/index.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/index.ts index 9e68a8379b702..f6ef4d3ede478 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/index.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/index.ts @@ -33,6 +33,7 @@ export default ({ loadTestFile, getService }: FtrProviderContext): void => { loadTestFile(require.resolve('./cases/assignees')); loadTestFile(require.resolve('./cases/find_cases')); loadTestFile(require.resolve('./configure')); + loadTestFile(require.resolve('./attachments_framework/registered_persistable_state_trial')); // sub privileges are only available with a license above basic loadTestFile(require.resolve('./delete_sub_privilege')); loadTestFile(require.resolve('./user_profiles/get_current')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/init_and_status_apis.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/init_and_status_apis.ts index 0babe434c7f90..5f6363ada6a29 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/init_and_status_apis.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/risk_engine/init_and_status_apis.ts @@ -104,6 +104,7 @@ export default ({ getService }: FtrProviderContext) => { dynamic: 'strict', properties: { '@timestamp': { + ignore_malformed: false, type: 'date', }, host: { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts index 32ae758b20807..ca9c047209b53 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/non_ecs_fields.ts @@ -56,7 +56,6 @@ export default ({ getService }: FtrProviderContext) => { }; }; - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/154277 describe('Non ECS fields in alert document source', () => { before(async () => { await esArchiver.load( @@ -257,9 +256,10 @@ export default ({ getService }: FtrProviderContext) => { expect(alertSource).toHaveProperty('client.nat.port', '3000'); }); - // we don't validate it because geo_point is very complex type with many various representations: array, different object, string with few valid patterns - // more on geo_point type https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html - it('should fail creating alert when ECS field mapping is geo_point', async () => { + // We don't validate it because geo_point is very complex type with many various representations: array, + // different object, string with few valid patterns. + // More on geo_point type https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html + it('should not fail creating alert when ECS field mapping is geo_point', async () => { const document = { client: { geo: { @@ -269,12 +269,10 @@ export default ({ getService }: FtrProviderContext) => { }, }; - const { errors } = await indexAndCreatePreviewAlert(document); + const { errors, alertSource } = await indexAndCreatePreviewAlert(document); - expect(errors[0]).toContain('Bulk Indexing of signals failed'); - expect(errors[0]).toContain( - 'failed to parse field [client.geo.location] of type [geo_point]' - ); + expect(errors).toEqual([]); + expect(alertSource).toHaveProperty('client.geo.location', 'test test'); }); it('should strip invalid boolean values and left valid ones', async () => { diff --git a/x-pack/test/functional/apps/discover/async_scripted_fields.js b/x-pack/test/functional/apps/discover/async_scripted_fields.js index 0d48f42c5ba1e..d86298405b72d 100644 --- a/x-pack/test/functional/apps/discover/async_scripted_fields.js +++ b/x-pack/test/functional/apps/discover/async_scripted_fields.js @@ -27,7 +27,7 @@ export default function ({ getService, getPageObjects }) { const security = getService('security'); const dashboardAddPanel = getService('dashboardAddPanel'); - describe('async search with scripted fields', function () { + describe('search with scripted fields', function () { this.tags(['skipFirefox']); before(async function () { @@ -51,7 +51,7 @@ export default function ({ getService, getPageObjects }) { await security.testUser.restoreDefaults(); }); - it('query should show failed shards callout', async function () { + it('query should show incomplete results callout', async function () { if (false) { /* If you had to modify the scripted fields, you could un-comment all this, run it, use es_archiver to update 'kibana_scripted_fields_on_logstash' */ @@ -81,11 +81,11 @@ export default function ({ getService, getPageObjects }) { 'dscNoResultsInterceptedWarningsCallout_warningTitle' ); log.debug(shardMessage); - expect(shardMessage).to.be('1 of 3 shards failed'); + expect(shardMessage).to.be('The data might be incomplete or wrong.'); }); }); - it('query should show failed shards badge on dashboard', async function () { + it('query should show incomplete results badge on dashboard', async function () { await security.testUser.setRoles([ 'test_logstash_reader', 'global_discover_all', diff --git a/x-pack/test/functional/apps/lens/group4/tsdb.ts b/x-pack/test/functional/apps/lens/group4/tsdb.ts index 02dfa4ea2da5e..745592a02cb1d 100644 --- a/x-pack/test/functional/apps/lens/group4/tsdb.ts +++ b/x-pack/test/functional/apps/lens/group4/tsdb.ts @@ -311,8 +311,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.info(`Indexed ${res.items.length} test data docs.`); }; - // Failing: See https://github.com/elastic/kibana/issues/166097 - describe.skip('lens tsdb', function () { + describe('lens tsdb', function () { const tsdbIndex = 'kibana_sample_data_logstsdb'; const tsdbDataView = tsdbIndex; const tsdbEsArchive = 'test/functional/fixtures/es_archiver/kibana_sample_data_logs_tsdb'; @@ -827,16 +826,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // check there's some data after the upgrade expect(counterBars[counterBars.length - 1].y).to.eql(5000); + // due to the flaky nature of exact check here, we're going to relax it + // as long as there's data before and after it is ok log.info('Check count before the upgrade'); const columnsToCheck = countBars.length / 2; // Before the upgrade the count is N times the indexes - expect(sumFirstNValues(columnsToCheck, countBars)).to.eql( - indexes.length * TEST_DOC_COUNT + expect(sumFirstNValues(columnsToCheck, countBars)).to.be.greaterThan( + indexes.length * TEST_DOC_COUNT - 1 ); log.info('Check count after the upgrade'); // later there are only documents for the upgraded stream - expect(sumFirstNValues(columnsToCheck, [...countBars].reverse())).to.eql( - TEST_DOC_COUNT + expect(sumFirstNValues(columnsToCheck, [...countBars].reverse())).to.be.greaterThan( + TEST_DOC_COUNT - 1 ); }); }); @@ -912,12 +913,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const data = await PageObjects.lens.getCurrentChartDebugState('xyVisChart'); const bars = data.bars![0].bars; const columnsToCheck = bars.length / 2; + // due to the flaky nature of exact check here, we're going to relax it + // as long as there's data before and after it is ok log.info('Check count before the downgrade'); // Before the upgrade the count is N times the indexes - expect(sumFirstNValues(columnsToCheck, bars)).to.eql(indexes.length * TEST_DOC_COUNT); + expect(sumFirstNValues(columnsToCheck, bars)).to.be.greaterThan( + indexes.length * TEST_DOC_COUNT - 1 + ); log.info('Check count after the downgrade'); // later there are only documents for the upgraded stream - expect(sumFirstNValues(columnsToCheck, [...bars].reverse())).to.eql(TEST_DOC_COUNT); + expect(sumFirstNValues(columnsToCheck, [...bars].reverse())).to.be.greaterThan( + TEST_DOC_COUNT - 1 + ); }); it('should visualize data when moving the time window around the downgrade moment', async () => { diff --git a/x-pack/test/functional/apps/observability_log_explorer/header_menu.ts b/x-pack/test/functional/apps/observability_log_explorer/header_menu.ts index ee15563b7f208..7cc6f74c452e6 100644 --- a/x-pack/test/functional/apps/observability_log_explorer/header_menu.ts +++ b/x-pack/test/functional/apps/observability_log_explorer/header_menu.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { + const browser = getService('browser'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const retry = getService('retry'); @@ -35,6 +36,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('Discover fallback link', () => { + before(async () => { + await PageObjects.observabilityLogExplorer.navigateTo(); + }); + it('should render a button link ', async () => { const discoverLink = await PageObjects.observabilityLogExplorer.getDiscoverFallbackLink(); expect(await discoverLink.isDisplayed()).to.be(true); @@ -77,5 +82,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); }); + + describe('Add data link', () => { + before(async () => { + await PageObjects.observabilityLogExplorer.navigateTo(); + }); + + it('should render a button link ', async () => { + const onboardingLink = await PageObjects.observabilityLogExplorer.getOnboardingLink(); + expect(await onboardingLink.isDisplayed()).to.be(true); + }); + + it('should navigate to the observability onboarding overview page', async () => { + const onboardingLink = await PageObjects.observabilityLogExplorer.getOnboardingLink(); + onboardingLink.click(); + + await retry.try(async () => { + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/app/observabilityOnboarding`); + }); + }); + }); }); } diff --git a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts index 3f0adc5783893..ae6ac9adab2f5 100644 --- a/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts +++ b/x-pack/test/functional/apps/transform/creation/runtime_mappings_saved_search/creation_runtime_mappings.ts @@ -34,7 +34,8 @@ export default function ({ getService }: FtrProviderContext) { }, }; - describe('creation with runtime mappings', function () { + // Failing: See https://github.com/elastic/kibana/issues/166395 + describe.skip('creation with runtime mappings', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await transform.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); diff --git a/x-pack/test/functional/page_objects/observability_log_explorer.ts b/x-pack/test/functional/page_objects/observability_log_explorer.ts index 7e4b83083ace0..9e46c9bf826a3 100644 --- a/x-pack/test/functional/page_objects/observability_log_explorer.ts +++ b/x-pack/test/functional/page_objects/observability_log_explorer.ts @@ -323,6 +323,10 @@ export function ObservabilityLogExplorerPageObject({ return testSubjects.find('logExplorerDiscoverFallbackLink'); }, + getOnboardingLink() { + return testSubjects.find('logExplorerOnboardingLink'); + }, + // Query Bar getQueryBar() { return testSubjects.find('queryInput'); diff --git a/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts b/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts index 5f09137850a2d..f7f9b1eb9ff00 100644 --- a/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts +++ b/x-pack/test/observability_functional/apps/observability/pages/rule_details_page.ts @@ -36,8 +36,7 @@ export default ({ getService }: FtrProviderContext) => { return true; } - // FLAKY: https://github.com/elastic/kibana/issues/165619 - describe.skip('Observability Rule Details page', function () { + describe('Observability Rule Details page', function () { this.tags('includeFirefox'); let uptimeRuleId: string; @@ -149,10 +148,14 @@ export default ({ getService }: FtrProviderContext) => { describe('Alert summary widget component', () => { before(async () => { - await observability.alerts.common.navigateToRuleDetailsByRuleId(uptimeRuleId); + await observability.alerts.common.navigateToRuleDetailsByRuleId(logThresholdRuleId); + await retry.waitFor( + 'Rule details to be visible', + async () => await testSubjects.exists('ruleDetails') + ); }); - it('shows component on the rule detils page', async () => { + it('shows component on the rule details page', async () => { await observability.components.alertSummaryWidget.getCompactComponentSelectorOrFail(); const timeRangeTitle = diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/metrics_route.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/metrics_route.ts index 4da679b6839ac..7a0507959c117 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/metrics_route.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/metrics_route.ts @@ -185,12 +185,13 @@ export default function ({ getService }: FtrProviderContext) { await request.delete(`/api/alerting/rule/${ruleId}`).set('kbn-xsrf', 'foo').expect(204); }); - it('should increment task run success/total counters', async () => { + it('should increment task run success/not_timed_out/total counters', async () => { const initialMetrics = ( await getMetrics( false, (metrics) => metrics?.metrics?.task_run?.value.by_type.alerting?.total === 1 && + metrics?.metrics?.task_run?.value.by_type.alerting?.not_timed_out === 1 && metrics?.metrics?.task_run?.value.by_type.alerting?.success === 1 ) ).metrics; @@ -210,6 +211,7 @@ export default function ({ getService }: FtrProviderContext) { false, (metrics) => metrics?.metrics?.task_run?.value.by_type.alerting?.total === i + 2 && + metrics?.metrics?.task_run?.value.by_type.alerting?.not_timed_out === i + 2 && metrics?.metrics?.task_run?.value.by_type.alerting?.success === i + 2 ); } @@ -219,6 +221,7 @@ export default function ({ getService }: FtrProviderContext) { false, (metrics) => metrics?.metrics?.task_run?.value.by_type.alerting?.total === 0 && + metrics?.metrics?.task_run?.value.by_type.alerting?.not_timed_out === 0 && metrics?.metrics?.task_run?.value.by_type.alerting?.success === 0 ); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts index ffcfb468e0824..35e6e596131ec 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_auto_refresh.cy.ts @@ -22,6 +22,7 @@ import { expectNumberOfRules, selectRulesByName, getRuleRow, + setRulesTableAutoRefreshIntervalSetting, } from '../../../../tasks/alerts_detection_rules'; import { login, visit, visitWithoutDateRange } from '../../../../tasks/login'; @@ -30,8 +31,7 @@ import { createRule } from '../../../../tasks/api_calls/rules'; import { cleanKibana } from '../../../../tasks/common'; import { getNewRule } from '../../../../objects/rule'; -const DEFAULT_RULE_REFRESH_INTERVAL_VALUE = 60000; -const NUM_OF_TEST_RULES = 6; +const RULES_TABLE_REFRESH_INTERVAL_MS = 60000; // TODO: https://github.com/elastic/kibana/issues/161540 describe( @@ -42,82 +42,128 @@ describe( cleanKibana(); login(); - for (let i = 1; i <= NUM_OF_TEST_RULES; ++i) { - createRule(getNewRule({ name: `Test rule ${i}`, rule_id: `${i}`, enabled: false })); - } + setRulesTableAutoRefreshIntervalSetting({ + enabled: true, + refreshInterval: RULES_TABLE_REFRESH_INTERVAL_MS, + }); + createRule(getNewRule({ name: 'Test rule 1', rule_id: '1', enabled: false })); }); beforeEach(() => { login(); }); - it('Auto refreshes rules', () => { - mockGlobalClock(); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + it('gets deactivated when any rule selected and activated after rules unselected', () => { + visit(DETECTIONS_RULE_MANAGEMENT_URL); + + expectNumberOfRules(RULES_MANAGEMENT_TABLE, 1); + + // check refresh settings if it's enabled before selecting + expectAutoRefreshIsEnabled(); + + selectAllRules(); - expectNumberOfRules(RULES_MANAGEMENT_TABLE, NUM_OF_TEST_RULES); + // auto refresh should be deactivated (which means disabled without an ability to enable it) after rules selected + expectAutoRefreshIsDeactivated(); - // // mock 1 minute passing to make sure refresh is conducted - cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist'); - cy.tick(DEFAULT_RULE_REFRESH_INTERVAL_VALUE); - cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('be.visible'); + clearAllRuleSelection(); - cy.contains(REFRESH_RULES_STATUS, 'Updated now'); + // after all rules unselected, auto refresh should be reset to its previous state + expectAutoRefreshIsEnabled(); }); - it('should prevent table from rules refetch if any rule selected', () => { - mockGlobalClock(); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + describe('when enabled', () => { + beforeEach(() => { + mockGlobalClock(); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - expectNumberOfRules(RULES_MANAGEMENT_TABLE, NUM_OF_TEST_RULES); + expectNumberOfRules(RULES_MANAGEMENT_TABLE, 1); + }); - selectRulesByName(['Test rule 1']); + it('refreshes rules after refresh interval has passed', () => { + cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist'); + cy.tick(RULES_TABLE_REFRESH_INTERVAL_MS); + cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('be.visible'); - // mock 1 minute passing to make sure refresh is not conducted - cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist'); - cy.tick(DEFAULT_RULE_REFRESH_INTERVAL_VALUE); - cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist'); + cy.contains(REFRESH_RULES_STATUS, 'Updated now'); + }); - // ensure rule is still selected - getRuleRow('Test rule 1').find(EUI_CHECKBOX).should('be.checked'); + it('refreshes rules on window focus', () => { + cy.tick(RULES_TABLE_REFRESH_INTERVAL_MS / 2); - cy.get(REFRESH_RULES_STATUS).should('have.not.text', 'Updated now'); + cy.window().trigger('blur'); + cy.window().trigger('focus'); + + cy.contains(REFRESH_RULES_STATUS, 'Updated now'); + }); }); - it('should disable auto refresh when any rule selected and enable it after rules unselected', () => { - visit(DETECTIONS_RULE_MANAGEMENT_URL); + describe('when disabled', () => { + beforeEach(() => { + mockGlobalClock(); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + expectNumberOfRules(RULES_MANAGEMENT_TABLE, 1); + }); - expectNumberOfRules(RULES_MANAGEMENT_TABLE, NUM_OF_TEST_RULES); + it('does NOT refresh rules after refresh interval has passed', () => { + disableAutoRefresh(); + cy.tick(RULES_TABLE_REFRESH_INTERVAL_MS * 2); // Make sure enough time has passed to verify auto-refresh doesn't happen - // check refresh settings if it's enabled before selecting - expectAutoRefreshIsEnabled(); + cy.contains(REFRESH_RULES_STATUS, 'Updated 2 minutes ago'); + }); - selectAllRules(); + it('does NOT refresh rules on window focus', () => { + disableAutoRefresh(); + cy.tick(RULES_TABLE_REFRESH_INTERVAL_MS * 2); // Make sure enough time has passed to verify auto-refresh doesn't happen - // auto refresh should be deactivated (which means disabled without an ability to enable it) after rules selected - expectAutoRefreshIsDeactivated(); + cy.window().trigger('blur'); + cy.window().trigger('focus'); - clearAllRuleSelection(); + // We need to make sure window focus event doesn't cause refetching. Without some delay + // the following expectations always pass even. It happens since 'focus' event gets handled + // in an async way so the status text is updated with some delay. + // eslint-disable-next-line cypress/no-unnecessary-waiting + cy.wait(1000); - // after all rules unselected, auto refresh should be reset to its previous state - expectAutoRefreshIsEnabled(); - }); + // By using a custom timeout make sure it doesn't wait too long due to global timeout configuration + // so the expected text appears after a refresh and the test passes while it shouldn't. + cy.contains(REFRESH_RULES_STATUS, 'Updated 2 minutes ago', { timeout: 10000 }); + }); - it('should not enable auto refresh after rules were unselected if auto refresh was disabled', () => { - visit(DETECTIONS_RULE_MANAGEMENT_URL); + it('does NOT get enabled after rules were unselected', () => { + disableAutoRefresh(); + cy.tick(RULES_TABLE_REFRESH_INTERVAL_MS * 2); // Make sure enough time has passed to verify auto-refresh doesn't happen - expectNumberOfRules(RULES_MANAGEMENT_TABLE, NUM_OF_TEST_RULES); + selectAllRules(); - disableAutoRefresh(); + expectAutoRefreshIsDeactivated(); - selectAllRules(); + clearAllRuleSelection(); - expectAutoRefreshIsDeactivated(); + // after all rules unselected, auto refresh should still be disabled + expectAutoRefreshIsDisabled(); + }); + }); - clearAllRuleSelection(); + describe('when one rule is selected', () => { + it('does NOT refresh after refresh interval has passed', () => { + mockGlobalClock(); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + + expectNumberOfRules(RULES_MANAGEMENT_TABLE, 1); + + selectRulesByName(['Test rule 1']); + + // mock 1 minute passing to make sure refresh is not conducted + cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist'); + cy.tick(RULES_TABLE_REFRESH_INTERVAL_MS * 2); // Make sure enough time has passed + cy.get(RULES_TABLE_AUTOREFRESH_INDICATOR).should('not.exist'); + + // ensure rule is still selected + getRuleRow('Test rule 1').find(EUI_CHECKBOX).should('be.checked'); - // after all rules unselected, auto refresh should still be disabled - expectAutoRefreshIsDisabled(); + cy.get(REFRESH_RULES_STATUS).should('have.not.text', 'Updated now'); + }); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts index 969934eb5fee1..02c25f751e6a6 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts @@ -268,13 +268,13 @@ describe( cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) .eq(0) .should('be.visible') - .and('have.text', '0 threat match detected'); // TODO work on getting proper IoC data to get proper data here + .and('have.text', '0 threat matches detected'); // TODO work on getting proper IoC data to get proper data here // field with threat enrichement cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES) .eq(1) .should('be.visible') - .and('have.text', '0 field enriched with threat intelligence'); // TODO work on getting proper IoC data to get proper data here + .and('have.text', '0 fields enriched with threat intelligence'); // TODO work on getting proper IoC data to get proper data here }); cy.log('should navigate to left panel Threat Intelligence tab'); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/cell_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/cell_actions.cy.ts index 4360df7bf6798..41cd4e02dca29 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/cell_actions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/discover/cell_actions.cy.ts @@ -23,7 +23,7 @@ const INITIAL_END_DATE = 'Jan 19, 2024 @ 20:33:29.186'; const TIMESTAMP_COLUMN_NAME = '@timestamp'; // FLAKY: https://github.com/elastic/kibana/issues/165650 -describe( +describe.skip( `Discover Datagrid Cell Actions`, { env: { ftrConfig: { enableExperimental: ['discoverInTimeline'] } }, diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts index cb920e8093be1..304e35e6826bf 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/alerts_detection_rules.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { DEFAULT_RULES_TABLE_REFRESH_SETTING } from '@kbn/security-solution-plugin/common/constants'; import { COLLAPSED_ACTION_BTN, CUSTOM_RULES_BTN, @@ -64,6 +65,7 @@ import { PAGE_CONTENT_SPINNER } from '../screens/common/page'; import { goToRuleEditSettings } from './rule_details'; import { goToActionsStepTab } from './create_new_rule'; +import { setKibanaSetting } from './api_calls/kibana_advanced_settings'; export const getRulesManagementTableRows = () => cy.get(RULES_MANAGEMENT_TABLE).find(RULES_ROW); @@ -516,3 +518,29 @@ const unselectRuleByName = (ruleName: string) => { cy.log(`Make sure rule "${ruleName}" has been unselected`); getRuleRow(ruleName).find(EUI_CHECKBOX).should('not.be.checked'); }; + +/** + * Set Kibana `securitySolution:rulesTableRefresh` setting looking like + * + * ``` + * { "on": true, "value": 60000 } + * ``` + * + * @param enabled whether the auto-refresh is enabled + * @param refreshInterval refresh interval in milliseconds + */ +export const setRulesTableAutoRefreshIntervalSetting = ({ + enabled, + refreshInterval, +}: { + enabled: boolean; + refreshInterval: number; // milliseconds +}) => { + setKibanaSetting( + DEFAULT_RULES_TABLE_REFRESH_SETTING, + JSON.stringify({ + on: enabled, + value: refreshInterval, + }) + ); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts index f86cd0186c8c2..2c982adad5275 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/api_calls/kibana_advanced_settings.ts @@ -5,30 +5,27 @@ * 2.0. */ +import { SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID } from '@kbn/management-settings-ids'; +import { ENABLE_EXPANDABLE_FLYOUT_SETTING } from '@kbn/security-solution-plugin/common/constants'; import { rootRequest } from '../common'; -const kibanaSettings = (body: Cypress.RequestBody) => { +export const setKibanaSetting = (key: string, value: boolean | number | string) => { rootRequest({ method: 'POST', url: 'internal/kibana/settings', - body, + body: { changes: { [key]: value } }, headers: { 'kbn-xsrf': 'cypress-creds', 'x-elastic-internal-origin': 'security-solution' }, }); }; -const relatedIntegrationsBody = (status: boolean): Cypress.RequestBody => { - return { changes: { 'securitySolution:showRelatedIntegrations': status } }; -}; - export const enableRelatedIntegrations = () => { - kibanaSettings(relatedIntegrationsBody(true)); + setKibanaSetting(SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID, true); }; export const disableRelatedIntegrations = () => { - kibanaSettings(relatedIntegrationsBody(false)); + setKibanaSetting(SECURITY_SOLUTION_SHOW_RELATED_INTEGRATIONS_ID, false); }; export const disableExpandableFlyout = () => { - const body = { changes: { 'securitySolution:enableExpandableFlyout': false } }; - kibanaSettings(body); + setKibanaSetting(ENABLE_EXPANDABLE_FLYOUT_SETTING, false); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tsconfig.json b/x-pack/test/security_solution_cypress/cypress/tsconfig.json index ec9ce83a98f03..b82ce28aa8f04 100644 --- a/x-pack/test/security_solution_cypress/cypress/tsconfig.json +++ b/x-pack/test/security_solution_cypress/cypress/tsconfig.json @@ -37,6 +37,7 @@ "@kbn/config-schema", "@kbn/lists-plugin", "@kbn/securitysolution-list-constants", - "@kbn/security-plugin" + "@kbn/security-plugin", + "@kbn/management-settings-ids" ] } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/alerting/alert_documents.ts b/x-pack/test_serverless/api_integration/test_suites/common/alerting/alert_documents.ts index 12d23a3c6d78e..799d87f65e10f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/alerting/alert_documents.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/alerting/alert_documents.ts @@ -19,9 +19,7 @@ export default function ({ getService }: FtrProviderContext) { const esClient = getService('es'); const objectRemover = new ObjectRemover(supertest); - // FLAKY: https://github.com/elastic/kibana/issues/165779 - // FLAKY: https://github.com/elastic/kibana/issues/165388 - describe.skip('Alert documents', () => { + describe('Alert documents', () => { const RULE_TYPE_ID = '.es-query'; const ALERT_INDEX = '.alerts-stack.alerts-default'; let ruleId: string; diff --git a/x-pack/test_serverless/api_integration/test_suites/common/alerting/helpers/alerting_wait_for_helpers.ts b/x-pack/test_serverless/api_integration/test_suites/common/alerting/helpers/alerting_wait_for_helpers.ts index 7b86988e879c3..5422d6a7b8cee 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/alerting/helpers/alerting_wait_for_helpers.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/alerting/helpers/alerting_wait_for_helpers.ts @@ -23,7 +23,7 @@ export async function waitForDocumentInIndex({ indexName: string; num?: number; }): Promise<SearchResponse> { - return pRetry( + return await pRetry( async () => { const response = await esClient.search({ index: indexName }); if (response.hits.hits.length < num) { @@ -74,7 +74,7 @@ export async function waitForAlertInIndex<T>({ ruleId: string; num: number; }): Promise<SearchResponse<T, Record<string, AggregationsAggregate>>> { - return pRetry( + return await pRetry( async () => { const response = await esClient.search<T>({ index: indexName, @@ -115,7 +115,7 @@ export async function waitForAllTasksIdle({ esClient: Client; filter: Date; }): Promise<SearchResponse> { - return pRetry( + return await pRetry( async () => { const response = await esClient.search({ index: '.kibana_task_manager', @@ -167,7 +167,7 @@ export async function waitForAllTasks({ taskType: string; attempts: number; }): Promise<SearchResponse> { - return pRetry( + return await pRetry( async () => { const response = await esClient.search({ index: '.kibana_task_manager', @@ -225,7 +225,7 @@ export async function waitForDisabled({ ruleId: string; filter: Date; }): Promise<SearchResponse> { - return pRetry( + return await pRetry( async () => { const response = await esClient.search({ index: '.kibana_task_manager', @@ -280,7 +280,7 @@ export async function waitForExecutionEventLog({ ruleId: string; num?: number; }): Promise<SearchResponse> { - return pRetry( + return await pRetry( async () => { const response = await esClient.search({ index: '.kibana-event-log*', diff --git a/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts b/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts index dd6060a397059..e9d3c85f21028 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts @@ -35,8 +35,7 @@ export default function ({ getService }: FtrProviderContext) { const esClient = getService('es'); const esDeleteAllIndices = getService('esDeleteAllIndices'); - // Failing: See https://github.com/elastic/kibana/issues/164017 - describe.skip('Alerting rules', () => { + describe('Alerting rules', () => { const RULE_TYPE_ID = '.es-query'; const ALERT_ACTION_INDEX = 'alert-action-es-query'; let actionId: string; @@ -119,22 +118,6 @@ export default function ({ getService }: FtrProviderContext) { }); expect(resp.hits.hits.length).to.be(1); - await waitForAllTasksIdle({ - esClient, - filter: testStart, - }); - - await disableRule({ - supertest, - ruleId, - }); - - await waitForDisabled({ - esClient, - ruleId, - filter: testStart, - }); - const document = resp.hits.hits[0]; expect(document._source).to.eql({ alertActionGroup: 'query matched', @@ -157,7 +140,7 @@ export default function ({ getService }: FtrProviderContext) { expect(eventLogResp.hits.hits.length).to.be(1); const eventLogDocument = eventLogResp.hits.hits[0]._source; - await validateEventLog(eventLogDocument, { + validateEventLog(eventLogDocument, { ruleId, ruleTypeId: RULE_TYPE_ID, outcome: 'success', @@ -928,7 +911,8 @@ function validateEventLog(event: any, params: ValidateEventLogParams) { expect(event?.kibana?.alert?.rule?.execution?.metrics?.number_of_triggered_actions).to.be(1); expect(event?.kibana?.alert?.rule?.execution?.metrics?.number_of_searches).to.be(1); - expect(event?.kibana?.alert?.rule?.execution?.metrics?.es_search_duration_ms).to.be(0); + // Sometimes fast enough that it will report 0ms + expect(event?.kibana?.alert?.rule?.execution?.metrics?.es_search_duration_ms >= 0).to.be.ok(); expect( event?.kibana?.alert?.rule?.execution?.metrics?.total_search_duration_ms ).to.be.greaterThan(0); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/search_xpack/search.ts b/x-pack/test_serverless/api_integration/test_suites/common/search_xpack/search.ts index 1a4839cbae6fa..d820f22e72567 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/search_xpack/search.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/search_xpack/search.ts @@ -430,8 +430,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(404); }); - // FLAKY: https://github.com/elastic/kibana/issues/164856 - it.skip('should delete a completed search', async function () { + it('should delete a completed search', async function () { await markRequiresShardDelayAgg(this); const resp = await supertest @@ -460,7 +459,7 @@ export default function ({ getService }: FtrProviderContext) { await new Promise((resolve) => setTimeout(resolve, 3000)); - await retry.tryForTime(10000, async () => { + await retry.tryForTime(30000, async () => { const resp2 = await supertest .post(`/internal/search/ese/${id}`) .set(ELASTIC_HTTP_VERSION_HEADER, '1') diff --git a/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts b/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts index 1e32185187f8d..22b59a9e3ed05 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts @@ -72,7 +72,10 @@ describe.skip('Serverless', () => { cy.contains('Log rate analysis').click(); cy.url().should('include', '/app/ml/aiops/log_rate_analysis_index_select'); - cy.contains('Change Point Detection').click(); + cy.contains('Log pattern analysis').click(); + cy.url().should('include', '/app/ml/aiops/log_categorization_index_select'); + + cy.contains('Change point detection').click(); cy.url().should('include', '/app/ml/aiops/change_point_detection_index_select'); cy.contains('Job notifications').click(); diff --git a/x-pack/test_serverless/functional/test_suites/observability/observability_log_explorer/header_menu.ts b/x-pack/test_serverless/functional/test_suites/observability/observability_log_explorer/header_menu.ts index 0b40780aace2b..5e3d235f10c53 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/observability_log_explorer/header_menu.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/observability_log_explorer/header_menu.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { + const browser = getService('browser'); const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const retry = getService('retry'); @@ -36,6 +37,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('Discover fallback link', () => { + before(async () => { + await PageObjects.observabilityLogExplorer.navigateTo(); + }); + it('should render a button link ', async () => { const discoverLink = await PageObjects.observabilityLogExplorer.getDiscoverFallbackLink(); expect(await discoverLink.isDisplayed()).to.be(true); @@ -78,5 +83,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); }); + + describe('Add data link', () => { + before(async () => { + await PageObjects.observabilityLogExplorer.navigateTo(); + }); + + it('should render a button link ', async () => { + const onboardingLink = await PageObjects.observabilityLogExplorer.getOnboardingLink(); + expect(await onboardingLink.isDisplayed()).to.be(true); + }); + + it('should navigate to the observability onboarding overview page', async () => { + const onboardingLink = await PageObjects.observabilityLogExplorer.getOnboardingLink(); + onboardingLink.click(); + + await retry.try(async () => { + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/app/observabilityOnboarding`); + }); + }); + }); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/cypress/cypress.config.ts b/x-pack/test_serverless/functional/test_suites/security/cypress/cypress.config.ts index 33d7c582835d2..1db2cc6e0119f 100644 --- a/x-pack/test_serverless/functional/test_suites/security/cypress/cypress.config.ts +++ b/x-pack/test_serverless/functional/test_suites/security/cypress/cypress.config.ts @@ -20,6 +20,12 @@ export default defineCypressConfig({ viewportHeight: 946, viewportWidth: 1680, numTestsKeptInMemory: 10, + env: { + KIBANA_USERNAME: 'system_indices_superuser', + KIBANA_PASSWORD: 'changeme', + ELASTICSEARCH_USERNAME: 'system_indices_superuser', + ELASTICSEARCH_PASSWORD: 'changeme', + }, e2e: { experimentalRunAllSpecs: true, experimentalMemoryManagement: true, diff --git a/x-pack/test_serverless/shared/config.base.ts b/x-pack/test_serverless/shared/config.base.ts index eb193d5ea5487..a15405cd0f231 100644 --- a/x-pack/test_serverless/shared/config.base.ts +++ b/x-pack/test_serverless/shared/config.base.ts @@ -121,6 +121,11 @@ export default async () => { // In the real world the SAML config is injected by control plane. `--plugin-path=${samlIdPPlugin}`, '--xpack.cloud.id=ftr_fake_cloud_id', + // Ensure that SAML is used as the default authentication method whenever a user navigates to Kibana. In other + // words, Kibana should attempt to authenticate the user using the provider with the lowest order if the Login + // Selector is disabled (which is how Serverless Kibana is configured). By declaring `cloud-basic` with a higher + // order, we indicate that basic authentication can still be used, but only if explicitly requested when the + // user navigates to `/login` page directly and enters username and password in the login form. '--xpack.security.authc.selector.enabled=false', `--xpack.security.authc.providers=${JSON.stringify({ saml: { 'cloud-saml-kibana': { order: 0, realm: 'cloud-saml-kibana' } }, diff --git a/yarn.lock b/yarn.lock index 14c9d60a29e6c..e9c20dd8ff99a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1375,9 +1375,9 @@ globby "^11.0.4" "@cypress/request@^2.88.10": - version "2.88.10" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce" - integrity sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg== + version "2.88.12" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.12.tgz#ba4911431738494a85e93fb04498cb38bc55d590" + integrity sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -1392,9 +1392,9 @@ json-stringify-safe "~5.0.1" mime-types "~2.1.19" performance-now "^2.1.0" - qs "~6.5.2" + qs "~6.10.3" safe-buffer "^5.1.2" - tough-cookie "~2.5.0" + tough-cookie "^4.1.3" tunnel-agent "^0.6.0" uuid "^8.3.2" @@ -4910,6 +4910,10 @@ version "0.0.0" uid "" +"@kbn/metrics-data-access-plugin@link:x-pack/plugins/metrics_data_access": + version "0.0.0" + uid "" + "@kbn/ml-agg-utils@link:x-pack/packages/ml/agg_utils": version "0.0.0" uid "" @@ -12714,10 +12718,10 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^115.0.1: - version "115.0.1" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-115.0.1.tgz#76cbf35f16e0c1f5e29ab821fb3b8b06d22c3e40" - integrity sha512-faE6WvIhXfhnoZ3nAxUXYzeDCKy612oPwpkUp0mVkA7fZPg2JHSUiYOQhUYgzHQgGvDWD5Fy2+M2xV55GKHBVQ== +chromedriver@^116.0.0: + version "116.0.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-116.0.0.tgz#3f5d07b5427953270461791651d7b68cb6afe9fe" + integrity sha512-/TQaRn+RUAYnVqy5Vx8VtU8DvtWosU8QLM2u7BoNM5h55PRQPXF/onHAehEi8Sj/CehdKqH50NFdiumQAUr0DQ== dependencies: "@testim/chrome-version" "^1.1.3" axios "^1.4.0" @@ -24913,7 +24917,7 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= -psl@^1.1.28, psl@^1.1.33: +psl@^1.1.33: version "1.4.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== @@ -25039,10 +25043,12 @@ qs@^6.11.0: dependencies: side-channel "^1.0.4" -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +qs@~6.10.3: + version "6.10.5" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.5.tgz#974715920a80ff6a262264acd2c7e6c2a53282b4" + integrity sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ== + dependencies: + side-channel "^1.0.4" query-string@^6.13.2: version "6.13.2" @@ -28966,24 +28972,16 @@ totalist@^1.0.0: resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== -tough-cookie@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" - integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== +tough-cookie@^4.1.2, tough-cookie@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== dependencies: psl "^1.1.33" punycode "^2.1.1" universalify "^0.2.0" url-parse "^1.5.3" -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"