diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 3d02dae1fb9ca..b3f879d6aead1 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-06-16 +date: 2023-06-18 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 0706c589bd3bf..6180fa461e493 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index db0c186a86bf1..edf1006706d56 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index c1a7e5775763f..ed2d74b94f3f1 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-06-16 +date: 2023-06-18 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 a60b90af8e078..8fb4f42ec84fc 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 8aedb40c4febc..2ce0f2682b506 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-06-16 +date: 2023-06-18 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 30459acef70f0..f6b7431232106 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-06-16 +date: 2023-06-18 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 89db9c87a1cb6..5a1db554cac82 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-06-16 +date: 2023-06-18 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 b23e5d566e8d7..168507a4fd23f 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.devdocs.json b/api_docs/cases.devdocs.json index d8038f8cf266b..989ee06213efd 100644 --- a/api_docs/cases.devdocs.json +++ b/api_docs/cases.devdocs.json @@ -2379,6 +2379,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "cases", + "id": "def-common.LENS_ATTACHMENT_TYPE", + "type": "string", + "tags": [], + "label": "LENS_ATTACHMENT_TYPE", + "description": [], + "signature": [ + "\".lens\"" + ], + "path": "x-pack/plugins/cases/common/constants/visualizations.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "cases", "id": "def-common.OBSERVABILITY_OWNER", diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index abe95c7bbf931..5c5dd62aaa8fa 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 79 | 0 | 64 | 26 | +| 80 | 0 | 65 | 26 | ## Client diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 7e544f65a21d7..4dbf9eee69329 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 08046d1bfbc06..9a459b9a8ba74 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-06-16 +date: 2023-06-18 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 d785b2b21031d..d98069e2155f2 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-06-16 +date: 2023-06-18 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 5b57e3b028634..4ae410b5f4350 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-06-16 +date: 2023-06-18 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 b63d149f0f45f..0e913807f84e6 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-06-16 +date: 2023-06-18 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 fc7ea33ed4be3..9b93bcb1f3244 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index 7be1d161bf6f5..1e96b2920dd8d 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-06-16 +date: 2023-06-18 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 30853189357b8..66b551c716aba 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-06-16 +date: 2023-06-18 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 e14194d25997f..29f13a3c7f33c 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-06-16 +date: 2023-06-18 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 58d90d728e734..41dcac082bddd 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-06-16 +date: 2023-06-18 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 5706f08beffbe..965af7f110474 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-06-16 +date: 2023-06-18 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 99d1c7926dcd9..5c15b8542dba5 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-06-16 +date: 2023-06-18 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 8eaee27226621..35b13623d383a 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-06-16 +date: 2023-06-18 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 4ee493f68dcfd..009e0db18907f 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index fb606c540d245..faf14a9f883e3 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-06-16 +date: 2023-06-18 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 | |-------------------|-----------|------------------------|-----------------| -| 3302 | 119 | 2578 | 27 | +| 3303 | 119 | 2579 | 27 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index c8ec35cd1664e..d58aebf552cf6 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-06-16 +date: 2023-06-18 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 | |-------------------|-----------|------------------------|-----------------| -| 3302 | 119 | 2578 | 27 | +| 3303 | 119 | 2579 | 27 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index eea3d7ffbdf1f..ade5572ce56ec 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -345,7 +345,7 @@ }, ">>; get: (sessionId: string) => Promise<", "SearchSessionSavedObject", - ">; delete: (sessionId: string) => Promise; find: (options: Omit<", + ">; delete: (sessionId: string) => Promise; find: (opts: Omit<", { "pluginId": "@kbn/core-saved-objects-api-server", "scope": "common", @@ -361,39 +361,7 @@ "section": "def-common.SearchSessionsFindResponse", "text": "SearchSessionsFindResponse" }, - ">; extend: (sessionId: string, expires: string) => Promise<", - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsFindResponse", - "text": "SavedObjectsFindResponse" - }, - "<", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionSavedObjectAttributes", - "text": "SearchSessionSavedObjectAttributes" - }, - ", unknown>>; rename: (sessionId: string, newName: string) => Promise<", - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsUpdateResponse", - "text": "SavedObjectsUpdateResponse" - }, - ">>; }" + ">; extend: (sessionId: string, expires: string) => Promise; rename: (sessionId: string, newName: string) => Promise; }" ], "path": "src/plugins/data/public/search/types.ts", "deprecated": false, @@ -813,7 +781,7 @@ }, ">>; get: (sessionId: string) => Promise<", "SearchSessionSavedObject", - ">; delete: (sessionId: string) => Promise; find: (options: Omit<", + ">; delete: (sessionId: string) => Promise; find: (opts: Omit<", { "pluginId": "@kbn/core-saved-objects-api-server", "scope": "common", @@ -829,39 +797,7 @@ "section": "def-common.SearchSessionsFindResponse", "text": "SearchSessionsFindResponse" }, - ">; extend: (sessionId: string, expires: string) => Promise<", - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsFindResponse", - "text": "SavedObjectsFindResponse" - }, - "<", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionSavedObjectAttributes", - "text": "SearchSessionSavedObjectAttributes" - }, - ", unknown>>; rename: (sessionId: string, newName: string) => Promise<", - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsUpdateResponse", - "text": "SavedObjectsUpdateResponse" - }, - ">>; }" + ">; extend: (sessionId: string, expires: string) => Promise; rename: (sessionId: string, newName: string) => Promise; }" ], "path": "src/plugins/data/public/search/types.ts", "deprecated": false, @@ -1393,7 +1329,7 @@ }, ">>; get: (sessionId: string) => Promise<", "SearchSessionSavedObject", - ">; delete: (sessionId: string) => Promise; find: (options: Omit<", + ">; delete: (sessionId: string) => Promise; find: (opts: Omit<", { "pluginId": "@kbn/core-saved-objects-api-server", "scope": "common", @@ -1409,39 +1345,7 @@ "section": "def-common.SearchSessionsFindResponse", "text": "SearchSessionsFindResponse" }, - ">; extend: (sessionId: string, expires: string) => Promise<", - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsFindResponse", - "text": "SavedObjectsFindResponse" - }, - "<", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionSavedObjectAttributes", - "text": "SearchSessionSavedObjectAttributes" - }, - ", unknown>>; rename: (sessionId: string, newName: string) => Promise<", - { - "pluginId": "@kbn/core-saved-objects-api-server", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", - "section": "def-common.SavedObjectsUpdateResponse", - "text": "SavedObjectsUpdateResponse" - }, - ">>; }" + ">; extend: (sessionId: string, expires: string) => Promise; rename: (sessionId: string, newName: string) => Promise; }" ], "path": "src/plugins/data/public/search/session/sessions_client.ts", "deprecated": false, @@ -4022,6 +3926,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-server.INITIAL_SEARCH_SESSION_REST_VERSION", + "type": "string", + "tags": [], + "label": "INITIAL_SEARCH_SESSION_REST_VERSION", + "description": [], + "signature": [ + "\"1\"" + ], + "path": "src/plugins/data/server/search/routes/session.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-server.SearchRequestHandlerContext", diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 68f64302fd622..f665a83108e80 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3302 | 119 | 2578 | 27 | +| 3303 | 119 | 2579 | 27 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index e9c80867db201..c0a901e1c47e2 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 72bbc68e802b8..990ff356dc7c0 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 8651fe2860eb2..f73c37962a879 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 84a8d589c29a3..40f17ef3fade3 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index b7d1d7e1b21a9..84e9e6e8e651c 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-06-16 +date: 2023-06-18 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 3cf5c85f6b681..b968375c2e90a 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 2b6e8cfde928e..80fb145837651 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 6a4977eeaefae..5652f23d9db6c 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index e69e7bcb97ca5..3197dde040cf9 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-06-16 +date: 2023-06-18 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 6ead8e4277f38..1a0795a2f0c57 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-06-16 +date: 2023-06-18 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 ccf0c2be52776..d2ed1109a6365 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-06-16 +date: 2023-06-18 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 91000b2fdb712..b9b296bd4d6a3 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 86fab78e45b11..2a5bd71b05d52 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-06-16 +date: 2023-06-18 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 98176b5c8aec7..950f34e5fd817 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-06-16 +date: 2023-06-18 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 0c454cb723d5d..f615b1c0302ec 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-06-16 +date: 2023-06-18 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 0e7189422acba..d2c07a947127d 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-06-16 +date: 2023-06-18 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 82ba1307873b1..97f95d38e4e3c 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/ess_security.mdx b/api_docs/ess_security.mdx index 8df7655ee4480..e9b5146dcbea0 100644 --- a/api_docs/ess_security.mdx +++ b/api_docs/ess_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/essSecurity title: "essSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the essSecurity plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'essSecurity'] --- import essSecurityObj from './ess_security.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index a56de69ffc28f..797a1fb15d324 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-06-16 +date: 2023-06-18 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 be7c55231d264..ab2a335b782fe 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-06-16 +date: 2023-06-18 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 3483b6e081487..5c126f9ed7c2d 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-06-16 +date: 2023-06-18 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 a36fbba0bcdc6..fd02ef1076512 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-06-16 +date: 2023-06-18 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 7176c58b0bae8..a6111f526424e 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-06-16 +date: 2023-06-18 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 52ece1dfa168d..8769516a35442 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-06-16 +date: 2023-06-18 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 7493b99a43eaa..ee6605c06e793 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-06-16 +date: 2023-06-18 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 86e67b2d9166d..48445286ff5a4 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-06-16 +date: 2023-06-18 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 7386106aa3f27..8eecf3d634fea 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-06-16 +date: 2023-06-18 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 2347f04522636..983c17e6dd9dc 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-06-16 +date: 2023-06-18 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 991530357e6d7..0527baf46f2fe 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-06-16 +date: 2023-06-18 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 94d9e387f0cb9..bdc4a5c9aa292 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-06-16 +date: 2023-06-18 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 ae2aa1ce132e9..a9c0a1ec659fb 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-06-16 +date: 2023-06-18 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 7ec3b9e96e277..0295c791c0209 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-06-16 +date: 2023-06-18 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 68a830fa3fe37..e8463624cef36 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-06-16 +date: 2023-06-18 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 2a57e80567067..231efdf6483fc 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-06-16 +date: 2023-06-18 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 362021d9905e8..53242093855c5 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-06-16 +date: 2023-06-18 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 1ff41afe310c0..b995527704722 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-06-16 +date: 2023-06-18 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 208678088ad48..fce6e5faef654 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-06-16 +date: 2023-06-18 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 bf473fa754483..8e8a501899889 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-06-16 +date: 2023-06-18 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 4f02546adbd83..b7ad66f8de6bc 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-06-16 +date: 2023-06-18 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 625d0ac94546e..af866a6d401b1 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-06-16 +date: 2023-06-18 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 244e0480c4f1a..33577ea004e77 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-06-16 +date: 2023-06-18 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 a7a2d4c5d8ddf..f08fdbf5b192a 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-06-16 +date: 2023-06-18 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 d309d871d74eb..3fa955ff987d6 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-06-16 +date: 2023-06-18 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 0929862402179..0084e853c41c5 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-06-16 +date: 2023-06-18 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 4b77acc434df4..2dad48ab43381 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-06-16 +date: 2023-06-18 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 e7d05b1d21909..1d941fd3655c4 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-06-16 +date: 2023-06-18 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 17fda1db8087b..ba3294ca2346b 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index f412b69ce557a..dc20b34565680 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 927fc6f82bae1..ea159f6c212ee 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-06-16 +date: 2023-06-18 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 483eacb491b91..cc0579734ad51 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-06-16 +date: 2023-06-18 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 239d55a41971f..641e7546d5439 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-06-16 +date: 2023-06-18 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 c65a65c9e3b5c..aa8434ae1b5f4 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-06-16 +date: 2023-06-18 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 fd564678e6ef8..9e5a7953ee1ef 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 3e2bb44f29b2f..faa94b0caf123 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-06-16 +date: 2023-06-18 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 fddaf9d4ebff4..0c1b91bb79901 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-06-16 +date: 2023-06-18 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 bb1bdd3f5900d..46a1942a107b5 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-06-16 +date: 2023-06-18 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 47ff78bebd411..3f582eb2c663a 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index e296c3d91d1a4..71154eac6063c 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-06-16 +date: 2023-06-18 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 fdef95eba1104..dda4476370e39 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-06-16 +date: 2023-06-18 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 de080bd9e09e0..a57379447db50 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-06-16 +date: 2023-06-18 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 90ddc6287c8e5..4b95471f96cf1 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-06-16 +date: 2023-06-18 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 2493028fd6902..3fe7cf12ddbf4 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-06-16 +date: 2023-06-18 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 b023684ebcb47..a6e1d80d7afb9 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-06-16 +date: 2023-06-18 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 4241c7d6921f8..469a5b6bbe817 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-06-16 +date: 2023-06-18 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 0e89c0b18e9f6..ffbfcdd015be2 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-06-16 +date: 2023-06-18 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 7caf22a9e80ea..f33da3b2ad489 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-06-16 +date: 2023-06-18 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 1f21b3182319f..cc13612d2b008 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-06-16 +date: 2023-06-18 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 26724c1e65945..4696b9800be4a 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-06-16 +date: 2023-06-18 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 f8f74436e38d2..bc18d2bd582b4 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-06-16 +date: 2023-06-18 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 80ba6c62c8360..b203e24148a2b 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-06-16 +date: 2023-06-18 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 7a3c96d367336..28c2edbd0e1bf 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-06-16 +date: 2023-06-18 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 c2c865b5b1ae3..bcdc200d05183 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-06-16 +date: 2023-06-18 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 fd5de76135e67..614f07929b9ab 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-06-16 +date: 2023-06-18 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 886f34c9dde95..6b3b149609acd 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-06-16 +date: 2023-06-18 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 8fe4a0b900710..c8129a5be5271 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-06-16 +date: 2023-06-18 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 4aa24eb482226..596ee0d13926b 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-06-16 +date: 2023-06-18 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 ac96ce28ca541..3bff25c865d68 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-06-16 +date: 2023-06-18 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 43050899e6ade..f27b45d58fd81 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-06-16 +date: 2023-06-18 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 b8c1e48d8507b..274aed2a6ad1d 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-06-16 +date: 2023-06-18 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 f91c2cc258cdf..77cf24e9113f8 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-06-16 +date: 2023-06-18 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 b63bea91d0a93..e68aea476cd02 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-06-16 +date: 2023-06-18 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 1319e2bb5ebc3..247487fd41a54 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-06-16 +date: 2023-06-18 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 e7b023276d201..b3dc073a5899c 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-06-16 +date: 2023-06-18 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 c431a21fb18a7..18c5fbf1bf610 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-06-16 +date: 2023-06-18 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 8094ae7c9bd74..c7c3eda29b5aa 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-06-16 +date: 2023-06-18 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 2554c8c4bab95..892a9c67794b8 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-06-16 +date: 2023-06-18 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 4bd585a596f68..97799b8cb05be 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-06-16 +date: 2023-06-18 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 c1d409bbd5963..ba8c5b3dfaed0 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-06-16 +date: 2023-06-18 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 cd0f7b3d16be7..91ca28030653b 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-06-16 +date: 2023-06-18 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 85bdcd0822bac..d9986070c1019 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-06-16 +date: 2023-06-18 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 50d3401458f70..38c60f55371de 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-06-16 +date: 2023-06-18 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 98cc98648d6a7..f0dd3229ab4a2 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-06-16 +date: 2023-06-18 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 ba23fdd5fc4dd..d68251b1ce6a5 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-06-16 +date: 2023-06-18 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 63693630887a4..cf5a25b2554cc 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-06-16 +date: 2023-06-18 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 776a3df6e4eb2..5a65fd1f924c8 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-06-16 +date: 2023-06-18 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 58359cb058eec..66c0b946c4539 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-06-16 +date: 2023-06-18 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 f5e9379da5040..9100f3bb55c26 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-06-16 +date: 2023-06-18 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 686679b05fa04..b124143e0e009 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-06-16 +date: 2023-06-18 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 2e0c9e1690d19..6a10d74324a18 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-06-16 +date: 2023-06-18 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 574bf025183ba..727c18c3fcea6 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-06-16 +date: 2023-06-18 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 e5a8364b2fd14..5d80af31b682f 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-06-16 +date: 2023-06-18 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 c61b9a764373c..6283019e1cc4b 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-06-16 +date: 2023-06-18 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 62034b01238c4..f0e4bdee7d792 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-06-16 +date: 2023-06-18 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 2dbcca45249d8..ff082295b9d28 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-06-16 +date: 2023-06-18 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 8ce6aea9f04e6..b6b84378d9d48 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-06-16 +date: 2023-06-18 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 ad3c6b0886440..1149973a02aea 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-06-16 +date: 2023-06-18 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 536da9acfa468..6bc8dc9c90775 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-06-16 +date: 2023-06-18 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 0a412b101100f..7bd8b1d3bcd4c 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-06-16 +date: 2023-06-18 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 1d7a0e4833674..c49c9e0fdea3b 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-06-16 +date: 2023-06-18 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 3423e73c7019d..d892809368e57 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-06-16 +date: 2023-06-18 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 bed279259c9c6..2c80101bd124e 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-06-16 +date: 2023-06-18 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 a181234ab27e6..3bcbadb52a25d 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-06-16 +date: 2023-06-18 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 799a6a5fd8ac0..71b4bd3c4fb15 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-06-16 +date: 2023-06-18 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 5b07000e25ad3..2ff3214db22c8 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-06-16 +date: 2023-06-18 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 70a5875228353..43658bfca4089 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-06-16 +date: 2023-06-18 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 7749592f9cf56..2d427dc5aaec3 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-06-16 +date: 2023-06-18 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 c6a19e3f4a114..bf4ee620f7403 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-06-16 +date: 2023-06-18 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 514aacaf42b97..8fda0ed8893ac 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-06-16 +date: 2023-06-18 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 4e90b5e982a3b..a27b914cac9b5 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-06-16 +date: 2023-06-18 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 9ded06447f08d..b57447bec7bfc 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-06-16 +date: 2023-06-18 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 878db4363253f..08af0d740ebc6 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-06-16 +date: 2023-06-18 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 b5fdc6c1311a0..6f56ddd827e6c 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-06-16 +date: 2023-06-18 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 3e0196f4e5254..3e5c8ef70dde9 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-06-16 +date: 2023-06-18 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 cb57efa69e1f4..76b5e7a6a3435 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-06-16 +date: 2023-06-18 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 4fbd824d31690..4f9ea0aa943b0 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-06-16 +date: 2023-06-18 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 4c11c5bcf87f6..de5a0e1c3c831 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-06-16 +date: 2023-06-18 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 3503f4d4ed5d7..d722dbe32379a 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-06-16 +date: 2023-06-18 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 c9ea796097ef9..ef2708b3317f9 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-06-16 +date: 2023-06-18 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 a9dec40cde64e..b6df12e25a3b8 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-06-16 +date: 2023-06-18 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 80e46aa5c1821..c75f1ba15b2d7 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-06-16 +date: 2023-06-18 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 17a3ada354ec9..655049b755d78 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-06-16 +date: 2023-06-18 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 3f2c28d5272f9..97fb980458ec7 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-06-16 +date: 2023-06-18 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 2bc2d3445f6d4..4f2e73c93413b 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-06-16 +date: 2023-06-18 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 df2ed09482a38..02be0e96e6436 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-06-16 +date: 2023-06-18 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 2e33050bb92be..fd1aeecd14848 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-06-16 +date: 2023-06-18 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 fa7465e2612c7..c3e918e62e550 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-06-16 +date: 2023-06-18 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 c19415fe64a73..97c308bfe4b73 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-06-16 +date: 2023-06-18 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 abc84df00df7d..3f7e847d8e9de 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-06-16 +date: 2023-06-18 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 3cb22a32469a6..7d5fdbfe7d2f0 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-06-16 +date: 2023-06-18 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 0ec6e59dd5513..479f8c9388e1f 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-06-16 +date: 2023-06-18 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 c038872884ddd..585738c4f799c 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-06-16 +date: 2023-06-18 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 ae283f636687c..6212ffec5798d 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-06-16 +date: 2023-06-18 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 a9528d68a47e6..da3294d40fbf8 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-06-16 +date: 2023-06-18 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 beb08da3cbc56..a24e712701a82 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-06-16 +date: 2023-06-18 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 6eee4cb7ce6b1..b01a96eb322aa 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-06-16 +date: 2023-06-18 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 d2156303a1f1e..d4addba9eafc5 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-06-16 +date: 2023-06-18 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 f08c5d3f095eb..0711fcea0dd37 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-06-16 +date: 2023-06-18 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 e0bd5596154bf..eb505ebc2befc 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-06-16 +date: 2023-06-18 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 2928587448624..0c7c800229b69 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-06-16 +date: 2023-06-18 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 fa10ee724b89f..241db5bf78f23 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-06-16 +date: 2023-06-18 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 949ddbc25d5eb..3d6ce3a9bfbeb 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-06-16 +date: 2023-06-18 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 66134a66459b6..9f67c6a24eeb1 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-06-16 +date: 2023-06-18 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 f0b3c1e838b61..37f128c77b04b 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-06-16 +date: 2023-06-18 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 563232125e2af..19a4b8580dd54 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-06-16 +date: 2023-06-18 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 fc07ad6fe8dbe..ebfc0a25347a4 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-06-16 +date: 2023-06-18 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 d96f47c6761b4..5b481bb7928a4 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-06-16 +date: 2023-06-18 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 d64690ffd62eb..c64fa574d6eb7 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -3487,14 +3487,6 @@ "plugin": "bfetch", "path": "src/plugins/bfetch/server/plugin.ts" }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, { "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" @@ -6533,22 +6525,6 @@ "plugin": "bfetch", "path": "src/plugins/bfetch/server/plugin.ts" }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, { "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" @@ -8887,10 +8863,6 @@ "plugin": "bfetch", "path": "src/plugins/bfetch/server/plugin.ts" }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, { "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" @@ -10067,10 +10039,6 @@ "plugin": "bfetch", "path": "src/plugins/bfetch/server/plugin.ts" }, - { - "plugin": "data", - "path": "src/plugins/data/server/search/routes/session.ts" - }, { "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" @@ -14166,6 +14134,14 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/internal/has_data_views.ts" }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, { "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/json_schema.ts" @@ -14654,6 +14630,10 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/internal/fields_for.ts" }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, { "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/annotations.ts" @@ -14814,6 +14794,22 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/internal/fields_for.ts" }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, { "plugin": "data", "path": "src/plugins/data/server/search/routes/search.ts" @@ -15374,6 +15370,10 @@ "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/public/delete_data_view.ts" }, + { + "plugin": "data", + "path": "src/plugins/data/server/search/routes/session.ts" + }, { "plugin": "data", "path": "src/plugins/data/server/search/routes/search.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 9e3387ae1b866..8b57ab85e0740 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-06-16 +date: 2023-06-18 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 d254d271c0717..58e3bb4e78b13 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-06-16 +date: 2023-06-18 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 f41eb6d5c8770..541a2e9e8c7a1 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-06-16 +date: 2023-06-18 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 1e52083fff343..74b81395c078f 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-06-16 +date: 2023-06-18 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 67476503485a6..bb263b7842c02 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-06-16 +date: 2023-06-18 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 bfbaf3c240efd..8fdb161a084b0 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-06-16 +date: 2023-06-18 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 17a7ca15eb530..8a8cbbdc502f0 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-06-16 +date: 2023-06-18 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 05da25617624d..b428d185d1a63 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-06-16 +date: 2023-06-18 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 87e5ec1bb6b8a..8a74d32d08c51 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-06-16 +date: 2023-06-18 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 890a7d8177e02..e84d4fac31740 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-06-16 +date: 2023-06-18 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 555f3a0e8bbfa..d3e9b6e06c56d 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-06-16 +date: 2023-06-18 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 9ef6ee0542522..902e9cb71b655 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-06-16 +date: 2023-06-18 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 e8d838e80e712..00557c0218ee7 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-06-16 +date: 2023-06-18 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 91385f0b221ee..8a38b260d781b 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-06-16 +date: 2023-06-18 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 95fac0656d440..9b468e7784f01 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-06-16 +date: 2023-06-18 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 a409f931834b1..922300847278c 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-06-16 +date: 2023-06-18 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 7f7d25e9c0888..63cf06589ea37 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-06-16 +date: 2023-06-18 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 80692c45f8329..20695fad0575b 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-06-16 +date: 2023-06-18 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 329cc7af9c562..6e577f54b5ed0 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-06-16 +date: 2023-06-18 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 1d8b773edad76..0fb4871e99532 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-06-16 +date: 2023-06-18 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 f3a2d5654aa94..66c6e4df211ac 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-06-16 +date: 2023-06-18 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 612b803b2f007..061e2b02ee1e3 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-06-16 +date: 2023-06-18 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 400ff855cf017..29255a0938c6b 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-06-16 +date: 2023-06-18 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 25816db97fc16..4c52b1cc1ce42 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-06-16 +date: 2023-06-18 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 007d390007f79..e6f43511d23cc 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-06-16 +date: 2023-06-18 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 456c212dfd89d..6dcb2bd7398ba 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-06-16 +date: 2023-06-18 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 9d956ee92abe5..3c1518caf4b52 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-06-16 +date: 2023-06-18 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 97ea4eafba4f9..4057757502dab 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-06-16 +date: 2023-06-18 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 1a5df8ad10007..1e92a0c2d9739 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-06-16 +date: 2023-06-18 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 1bc37c8da75b9..894e823af91ac 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-06-16 +date: 2023-06-18 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 f311d1ffc0f91..0de23a23b6817 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-06-16 +date: 2023-06-18 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 884322e4ad923..8c48e10cd4027 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-06-16 +date: 2023-06-18 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 54cffc4f4d35a..1f5cbf1e66aaf 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-06-16 +date: 2023-06-18 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 5dea2e2eaa078..a7f0931d3c710 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-06-16 +date: 2023-06-18 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 6d218d9f1ee5a..b758ca7a5f3ab 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-06-16 +date: 2023-06-18 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 3d1d2964e62d2..582efeb3c384c 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-06-16 +date: 2023-06-18 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 64f5eec669305..cb20f7f230c85 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-06-16 +date: 2023-06-18 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 2da1714f3c652..738619666efd5 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-06-16 +date: 2023-06-18 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 e3b611b1439c5..1d2830c9f7ba4 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-06-16 +date: 2023-06-18 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 5eda9b48d4f67..63736164e1301 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-06-16 +date: 2023-06-18 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 87a53f900dd1b..ac1e8a07a80c7 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-06-16 +date: 2023-06-18 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 38529bbefe47d..e3a563c86d34b 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-06-16 +date: 2023-06-18 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 527eff6ee9d82..3f014de280498 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-06-16 +date: 2023-06-18 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 5f0651c5a5aeb..b1f3c31b6a4de 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-06-16 +date: 2023-06-18 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 7b8dd30fcab07..99e9414b8552f 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-06-16 +date: 2023-06-18 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 1ffb6d9adfe6a..7a758c60f929a 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-06-16 +date: 2023-06-18 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 d9bb9350422b0..3c694c339b072 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-06-16 +date: 2023-06-18 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 d776d06e894c4..a3af3d43f665d 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-06-16 +date: 2023-06-18 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 ea3637fa726ae..5f932128587a9 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-06-16 +date: 2023-06-18 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 8184a3d814690..8ff13b8273741 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-06-16 +date: 2023-06-18 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 e64be798cb170..7645ba0e3c6b9 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-06-16 +date: 2023-06-18 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 e273dffaab0f2..8f0e544793a15 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-06-16 +date: 2023-06-18 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 3381c21c6dcc8..3397f4dbeb1a5 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-06-16 +date: 2023-06-18 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 6f7d59e0605f7..dddec5702fe0d 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-06-16 +date: 2023-06-18 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 fdffc6be2a413..3f17bcf58f18d 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-06-16 +date: 2023-06-18 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 7b636268d1691..2f460e8fe0ffd 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-06-16 +date: 2023-06-18 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 7d0a2c7b1f55c..dfd6f14ba74c6 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-06-16 +date: 2023-06-18 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 e8b20692728df..10dabf084046d 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 54cec8fc9730e..a6f744bd337f9 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-06-16 +date: 2023-06-18 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 ef506e50631ba..7f34d5917e975 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-06-16 +date: 2023-06-18 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 cc5b249f27d94..4dff8eeec16fc 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-06-16 +date: 2023-06-18 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 006f208bd3d07..367b40f437c0a 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-06-16 +date: 2023-06-18 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 ea0e8e7f2eee3..d25a1b854f67f 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-06-16 +date: 2023-06-18 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 d9dabd05667a1..805fb078a60b3 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-06-16 +date: 2023-06-18 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 e90f34ca606de..921f05712fadf 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-06-16 +date: 2023-06-18 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 417f2d132d265..f7b99df2cb7cd 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-06-16 +date: 2023-06-18 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 de49d96b9b35b..2c2720c3ec608 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-06-16 +date: 2023-06-18 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 08a4978e386c0..d6ed7b7bd230e 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-06-16 +date: 2023-06-18 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 ccec04e7117ec..99aefa3333996 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-06-16 +date: 2023-06-18 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 05065d647c140..b58169927fdfc 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-06-16 +date: 2023-06-18 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 c42560c6e0b8d..c79a2c8701e15 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-06-16 +date: 2023-06-18 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 e96c826ff529e..b9186e69489a2 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-06-16 +date: 2023-06-18 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 fe97ea2ad21c3..0b45d70a82626 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index 37e53f693e41f..a7a33fc086236 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 36293887ed045..887fcd2ddd85f 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-06-16 +date: 2023-06-18 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 d45aee34d9d28..cc00618fe2b9f 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-06-16 +date: 2023-06-18 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 62dcd8bbb3f64..8effc9fd64a15 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-06-16 +date: 2023-06-18 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 d3fceca488bf5..ed05e442d3c80 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-06-16 +date: 2023-06-18 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 972516d8bc430..f9e7a36b1d5bb 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-06-16 +date: 2023-06-18 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 c8c7fa0968180..82719d0ad41ef 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-06-16 +date: 2023-06-18 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 650f82a793259..1c2ff7afbc1a9 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-06-16 +date: 2023-06-18 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 7557c28befcb3..3bc4e9f72cb2a 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-06-16 +date: 2023-06-18 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 097735204d0b2..cacf32bf3a406 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-06-16 +date: 2023-06-18 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 0c56236f21c39..c0d94629c30fe 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-06-16 +date: 2023-06-18 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 90fdc301ecbb2..076b4d4df2dd8 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-06-16 +date: 2023-06-18 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 f0d6eae13ae41..4e86c8519c5ea 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-06-16 +date: 2023-06-18 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 d4fef6c676b63..70fbbcf59d19d 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-06-16 +date: 2023-06-18 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 4714588b6fbbf..7089e69e08546 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-06-16 +date: 2023-06-18 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 787256e182cb5..4c7cbcd1bc2d3 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-06-16 +date: 2023-06-18 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 2a40b4732b0a5..f9950d09bda47 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 8b9aa9d893455..506b8086abb7e 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index da82bcd091275..a3f96d77f272a 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-06-16 +date: 2023-06-18 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 8c6464faf8086..829dac954e890 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-06-16 +date: 2023-06-18 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 1efddbc268726..b0a6b667bc716 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-06-16 +date: 2023-06-18 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 265d85b6c821e..511b2c2fa3a0d 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-06-16 +date: 2023-06-18 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 44a9bdc90adfc..3680d125714d5 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-06-16 +date: 2023-06-18 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 f972e8bb4aaa8..93beabbcc2920 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-06-16 +date: 2023-06-18 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 1f58316d5a9e6..b48b0d37d1d5c 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-06-16 +date: 2023-06-18 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 4fc3a8bc9ebbe..7e85d7380deae 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-06-16 +date: 2023-06-18 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 a2ac04726a9c6..e0ed4ac2a5667 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-06-16 +date: 2023-06-18 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 1a3414a6a14b3..95a42d78f46f5 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 386fffbe07987..379d6effa715b 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-06-16 +date: 2023-06-18 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 4070d924f8691..536bbfb0dc0f3 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-06-16 +date: 2023-06-18 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 38b24f47526f4..0c07f784240e5 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-06-16 +date: 2023-06-18 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 7200b53685a77..fcfd1d36d8e33 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-06-16 +date: 2023-06-18 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 5932353b1e226..50dfc740dbdad 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index c5de418e60071..9a4a21797b7b4 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-06-16 +date: 2023-06-18 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 cbbee79da6cf3..9607716979b16 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-06-16 +date: 2023-06-18 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 f789b0e6000da..6b889e6c688fe 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-06-16 +date: 2023-06-18 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 d348bae2b1255..ac7b8e5075458 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-06-16 +date: 2023-06-18 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 cfa5297bbb38a..436d9b85ffe82 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-06-16 +date: 2023-06-18 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 3e5b749a27938..f83353ebee4eb 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-06-16 +date: 2023-06-18 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 dcc3b70674eca..250fc152c0183 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-06-16 +date: 2023-06-18 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 8be4d53350e4c..107d28b1fd7da 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-06-16 +date: 2023-06-18 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 c5e341fa36064..e10059dfc04cc 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-06-16 +date: 2023-06-18 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 b56d60b4c4427..188a1d64797ef 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-06-16 +date: 2023-06-18 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 fdf124e2dccdf..04bea936c693a 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 154d1c2270ea5..184cb0b8f6203 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 390c78ab0b042..bddc6adb2a134 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index bf3b688be59d2..962954d5466c1 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-06-16 +date: 2023-06-18 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 612ae6cd90096..fb0971cad8aeb 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-06-16 +date: 2023-06-18 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 fb1f1f306c01a..6d929bafbf9ff 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-06-16 +date: 2023-06-18 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 f40a6f283c936..e4633a966cd27 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-06-16 +date: 2023-06-18 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 dad68d86ea5bd..f75c6bc100acc 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index 8666a5b5a7d56..a1a82a8d1cf32 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-06-16 +date: 2023-06-18 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 2aa4a52881542..337f35787e537 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-06-16 +date: 2023-06-18 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 1509e96a7b8bc..8d55f17cff74d 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-06-16 +date: 2023-06-18 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 8a0754549af52..39c04ba8915dc 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-06-16 +date: 2023-06-18 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 c4743e274d0fc..73f05e549542f 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-06-16 +date: 2023-06-18 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 ff708b0974fe9..cd6fe94aa2aca 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-06-16 +date: 2023-06-18 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 c169285d5c1fa..decc3006c1ba2 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-06-16 +date: 2023-06-18 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 9e46b306dd510..a1e207b19bf12 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-06-16 +date: 2023-06-18 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 e57827a7558b0..be9a740c5d1f7 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-06-16 +date: 2023-06-18 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 a784ed25b318a..76150d6ee282d 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-06-16 +date: 2023-06-18 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 634c9b75b87f3..6b340c0bbe4f9 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-06-16 +date: 2023-06-18 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 0b749c9498ccd..898e108f68ab8 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-06-16 +date: 2023-06-18 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 c67119f52062a..5f71dd77c0248 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-06-16 +date: 2023-06-18 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 b2acad719b539..191d2e6e927ca 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-06-16 +date: 2023-06-18 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 763fda24eaf20..64f84b86ab1e1 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-06-16 +date: 2023-06-18 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 03e57eca0b7b4..aa4b5671186a4 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-06-16 +date: 2023-06-18 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 ec47a8182eddb..25ef15552a7c4 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-06-16 +date: 2023-06-18 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 a3b46272f46da..82d5d2eefa58a 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-06-16 +date: 2023-06-18 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 a79138affb03d..b1f4e7a27dce4 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index bc94635277531..cf2ffea985508 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-06-16 +date: 2023-06-18 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 11d3018d3fb16..66e61349b09cc 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-06-16 +date: 2023-06-18 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 00c96fb6b242e..705782d55ab70 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 0787ebe396223..5fd1be331f72c 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-06-16 +date: 2023-06-18 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 452b64f9c79b1..f63549ed9ad5f 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-06-16 +date: 2023-06-18 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 9bec391183afe..3852c39bb900a 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-06-16 +date: 2023-06-18 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 531ac990cf073..5c5be223db7f9 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-06-16 +date: 2023-06-18 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_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index 27ef8f5433d2b..92ab9f47e8911 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-06-16 +date: 2023-06-18 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 a5c56460da3f5..bd883f2c11c7c 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 79f26a0b2d9fa..318d752189184 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 4bcc3877a974b..d32e5ed97048f 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-06-16 +date: 2023-06-18 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 536f5f4f6f5d4..18a8f1456e597 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-06-16 +date: 2023-06-18 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_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index 6d13515bfa48a..4886bbf282200 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-06-16 +date: 2023-06-18 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 a019a967aee99..ed4ac04f5e560 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-06-16 +date: 2023-06-18 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 7f6596338f0a2..b2a72bad2bc72 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-06-16 +date: 2023-06-18 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 f30be2833bb56..04b69bd820bb1 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-06-16 +date: 2023-06-18 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 e374f05f683e4..176848e5c2101 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-06-16 +date: 2023-06-18 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 6d7bddeef5550..98b7e67ed2dc3 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-06-16 +date: 2023-06-18 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 8e8552451bb57..a0e02830991b9 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-06-16 +date: 2023-06-18 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 85e22e8086b77..06a9b7a9d3823 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-06-16 +date: 2023-06-18 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 fa3f8d32ef4e1..a89f517d65e09 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-06-16 +date: 2023-06-18 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 15513250b51e5..18f4c7d400e1c 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-06-16 +date: 2023-06-18 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 4f581cb71babb..d76c5eac8809b 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-06-16 +date: 2023-06-18 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 e2731f87ed57c..5cbce7c9dc786 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-06-16 +date: 2023-06-18 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 efd107131d599..483f981977b6f 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-06-16 +date: 2023-06-18 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 5f5510c05f5da..ea73a9921ebb6 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-06-16 +date: 2023-06-18 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 3260455ade589..7f284cfb84a3b 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-06-16 +date: 2023-06-18 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 4e55d47b91c28..e732e149915ef 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-06-16 +date: 2023-06-18 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 b0ba1334651b3..a66775b3773a8 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-06-16 +date: 2023-06-18 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 f3ac10d8f6448..8a433384db75b 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-06-16 +date: 2023-06-18 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 ce5b674e8bdd3..bc6edee58871f 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-06-16 +date: 2023-06-18 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 7aff681cefe6d..dee187b335b80 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-06-16 +date: 2023-06-18 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 722286e59224a..b5dfb590440b2 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-06-16 +date: 2023-06-18 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 c1e2b0987a2ea..47acf2929749c 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index ac025b263cf3e..59def66e954b5 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-06-16 +date: 2023-06-18 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 8f14cbed928bb..5538b82fa65bc 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 8e199c416b004..c693f71a3b857 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-06-16 +date: 2023-06-18 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 7462d4dd1e5c7..8ed3ab773e799 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-06-16 +date: 2023-06-18 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 dd45ddcff9f89..f66d94372830c 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-06-16 +date: 2023-06-18 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 595153f98f343..20f90c6c68863 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-06-16 +date: 2023-06-18 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 653a18d7e7767..465118eac9220 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-06-16 +date: 2023-06-18 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 2031090eece6d..3fad5f7d5cc33 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index b3f342da9ec4a..706dad396cdbc 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-06-16 +date: 2023-06-18 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 a9a36a1dc1820..c3666805bc23f 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 68f29c4e66fab..7f9c6b862b366 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-06-16 +date: 2023-06-18 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 d12d64653be05..03ec9bb55e957 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-06-16 +date: 2023-06-18 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 3e89a266d430f..0c0ca1891c121 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-06-16 +date: 2023-06-18 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 3cd84edbb41bd..69a779728acc8 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-06-16 +date: 2023-06-18 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 d1ea7d3802c66..f20a7c5c01a00 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-06-16 +date: 2023-06-18 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 9d7e989441fe6..f5e2dc8ffbc62 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-06-16 +date: 2023-06-18 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 f2f05a916f6fb..acb0cc3204a98 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-06-16 +date: 2023-06-18 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 bf51132398b1b..4846d5aabb7d2 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-06-16 +date: 2023-06-18 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 08249f73cb352..362a9efea4ade 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-06-16 +date: 2023-06-18 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 48de65eefa4f4..8d2049333ffd6 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-06-16 +date: 2023-06-18 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 41dca3d9f0416..96e0390e3bb91 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-06-16 +date: 2023-06-18 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 5c3f4a0401518..9d34810e76297 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-06-16 +date: 2023-06-18 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 12be71179a0ee..e64e312df6bad 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-06-16 +date: 2023-06-18 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 850b6769502fe..eac0a51b8e77a 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-06-16 +date: 2023-06-18 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 8f8a91e9f1558..c7d15f778016a 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-06-16 +date: 2023-06-18 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 68c874a75da60..11294ffe073ac 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-06-16 +date: 2023-06-18 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 e6a1d50f54f7b..1aa9429f74769 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-06-16 +date: 2023-06-18 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 b7bc650fc2aef..03211c947d2f3 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-06-16 +date: 2023-06-18 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 39162db19c6ec..37bb3cc8b66ca 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-06-16 +date: 2023-06-18 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 94cace6335474..02c0c35fb52ed 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-06-16 +date: 2023-06-18 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 8ac3c94067d5b..c8d5f1fa85ac2 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-06-16 +date: 2023-06-18 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 21f91ff3f907b..288e2ba816c2e 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-06-16 +date: 2023-06-18 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_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 5694ac9f7a811..380b1feea17e2 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-06-16 +date: 2023-06-18 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_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index 061e2560161dd..5ecd389240e6c 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-06-16 +date: 2023-06-18 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 763b8b1cb4340..4fd2e31dfe3fd 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-06-16 +date: 2023-06-18 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 c7c81c6ce6439..156eb98a9e421 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-06-16 +date: 2023-06-18 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 12e405648cc4f..414e94781b131 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-06-16 +date: 2023-06-18 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 24f9e4bfad065..c6e65bbacc935 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-06-16 +date: 2023-06-18 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 f1035d86fc50f..641bf41455cee 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-06-16 +date: 2023-06-18 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 99a48c5210568..abdb2f68b0d8b 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-06-16 +date: 2023-06-18 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 b0c924613b03f..733d73a9f7e09 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-06-16 +date: 2023-06-18 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 7dcd9f1516c27..5c441120ad607 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-06-16 +date: 2023-06-18 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 a8389531d16e0..7fd3238d54ce6 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-06-16 +date: 2023-06-18 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 d6a7d68f32d5b..32693648b38ee 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-06-16 +date: 2023-06-18 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 934a442cbccc4..f21b8ede852b0 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-06-16 +date: 2023-06-18 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 a78eae571b460..9af1b216b6038 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-06-16 +date: 2023-06-18 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 973e0da67b3dc..af01b3d9f6aa4 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-06-16 +date: 2023-06-18 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 3c653639f1af0..ab4f7dac7d412 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-06-16 +date: 2023-06-18 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 3c931bf8ac780..0705ea8f65f09 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-06-16 +date: 2023-06-18 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 b54a46beb4527..81a89d86bcbb8 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-06-16 +date: 2023-06-18 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 46b79684f3991..d70af8c3ab26b 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-06-16 +date: 2023-06-18 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 0192192b187b3..4af7b2f9b9b85 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-06-16 +date: 2023-06-18 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 f8a7d669dbe44..a718cb537cf08 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-06-16 +date: 2023-06-18 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 8ee3ed240c179..0cb30c044ef12 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-06-16 +date: 2023-06-18 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 b6b73425379ae..1838572e70c0f 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-06-16 +date: 2023-06-18 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 787bb886bf851..e388c6bb0aba8 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-06-16 +date: 2023-06-18 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 14984d90e12da..a452445d4d65f 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-06-16 +date: 2023-06-18 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 7889e70bf479f..e2302e5e2053f 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-06-16 +date: 2023-06-18 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 c242f9b15ba13..6ae4cef9fe5fc 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-06-16 +date: 2023-06-18 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 8f214f9c2552f..84f66ba3b420d 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-06-16 +date: 2023-06-18 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 84185fdacaca0..1ec307945349b 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-06-16 +date: 2023-06-18 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 330dbeedd0815..871737084edc3 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-06-16 +date: 2023-06-18 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 5b43391e5813b..36a96b33ff811 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-06-16 +date: 2023-06-18 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 d7f509d02b32c..54b8909b7fd56 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-06-16 +date: 2023-06-18 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 1baec1f11ae30..94fbda4c783ff 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-06-16 +date: 2023-06-18 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 5981372f35407..76307e9922d37 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-06-16 +date: 2023-06-18 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 36aac9188eeee..fb6fdddc9099c 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-06-16 +date: 2023-06-18 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 a990a6b052d19..f69dd6534c4cd 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-06-16 +date: 2023-06-18 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 cc20cd67a7888..171262f7a2b41 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-06-16 +date: 2023-06-18 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 baca65b128616..8e7493fb43450 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-06-16 +date: 2023-06-18 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 6a284a6c4a2af..457166b6c75d8 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-06-16 +date: 2023-06-18 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 df3e70145e1a3..55874564f07e9 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-06-16 +date: 2023-06-18 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 21861b3153d66..adfd90be9596b 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-06-16 +date: 2023-06-18 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 524e35bd37090..61eefd2656339 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-06-16 +date: 2023-06-18 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 3579bd3291f64..94b7946f50cfd 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-06-16 +date: 2023-06-18 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 d0b91c2cb18a9..7826ce1076ce7 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-06-16 +date: 2023-06-18 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 6770f3d760f6a..066e0bc895ac3 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-06-16 +date: 2023-06-18 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 08e9eaf18ed21..4b99173938dea 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-06-16 +date: 2023-06-18 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 a25fda90ec3d0..e370eaefd1b71 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-06-16 +date: 2023-06-18 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 a89dabb6d1e18..4018083aa2131 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-06-16 +date: 2023-06-18 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 54fcfc8eb9a34..c48b47a2e643e 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-06-16 +date: 2023-06-18 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 0a635c27b5ab4..d9fd88cae4488 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-06-16 +date: 2023-06-18 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 d09cc04d1d171..c7bd05480bf59 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-06-16 +date: 2023-06-18 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 be04dda89d3a1..0d82404ef600a 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-06-16 +date: 2023-06-18 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 424807bda1fad..4c20177075cc9 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-06-16 +date: 2023-06-18 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 2f1457de948d3..b29c43cad4941 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-06-16 +date: 2023-06-18 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 c651ac63d7e68..0b3669eb02fc5 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-06-16 +date: 2023-06-18 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 153fac4f47318..6f0cf427aa9a9 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-06-16 +date: 2023-06-18 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 48bddeb0859d7..5d449af746ac9 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-06-16 +date: 2023-06-18 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 8b90f5c4ee120..7bc6e8a0a2bdd 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index b1be1bc7dd730..a3e8b9aadea1c 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/url-state'] --- import kbnUrlStateObj from './kbn_url_state.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 0ebccd83459f0..e8bf2c509e949 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-06-16 +date: 2023-06-18 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 c75063a2fd540..0f6e0f1d9d875 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-06-16 +date: 2023-06-18 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 aec46e40654d0..d5bceb537700e 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-06-16 +date: 2023-06-18 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 99cff8162f432..4eaaee18e6de7 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 7fc6493922ba0..11d68427534a8 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-06-16 +date: 2023-06-18 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 a1b64b5400f0c..d6006d1ca9058 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 934abfaba326e..1f7a8e6d9da27 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-06-16 +date: 2023-06-18 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 5fd9c1c6224bf..e1db6966ab295 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-06-16 +date: 2023-06-18 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 eafc945dcabdd..e26b7507b27f4 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-06-16 +date: 2023-06-18 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 8b82f29160178..0c84c7451087a 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-06-16 +date: 2023-06-18 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 c3fa6040392b4..ccf8c64194c2a 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-06-16 +date: 2023-06-18 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 96e14e1efc74b..1bdd152106029 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-06-16 +date: 2023-06-18 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 0e2cbb74b72b7..4666dbe653b6c 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-06-16 +date: 2023-06-18 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 663091e907db3..40a8387c3cdcd 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 8e51b0553fa7b..282b1cbd28d6c 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index d0230e88b8589..d5deb417e14ae 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index e69143af922f8..a912216543958 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index b06feb6a4b34d..83b0d490821f7 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-06-16 +date: 2023-06-18 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 3d362e0d211c8..a0539db24a67e 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-06-16 +date: 2023-06-18 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 cac0b37c59673..f9cefd8106ea9 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-06-16 +date: 2023-06-18 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 d8f35c98d538d..56da7daf2b81c 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-06-16 +date: 2023-06-18 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 b9a8cdd4dc2f4..696db1a6e5612 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 33aea72e68d2b..22b9a311b33d6 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-06-16 +date: 2023-06-18 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 05cc930c1e5d7..177c96e4c016d 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 01586572e352f..1c3824de1aac9 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 959db437852e0..e1b57f33adfdb 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-06-16 +date: 2023-06-18 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 756a9c8c1c764..2e0694e84e5b3 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index 01957b46d02cf..ac10d5778600d 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -21,7 +21,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 70793 | 537 | 60630 | 1383 | +| 70795 | 537 | 60632 | 1383 | ## Plugin Directory @@ -36,7 +36,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 91 | 1 | 75 | 2 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 79 | 0 | 64 | 26 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 80 | 0 | 65 | 26 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 271 | 16 | 256 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 52 | 0 | 11 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 3 | 0 | 2 | 0 | @@ -56,7 +56,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 | 274 | 0 | 255 | 1 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 99 | 0 | 97 | 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. | 3302 | 119 | 2578 | 27 | +| | [@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. | 3303 | 119 | 2579 | 27 | | | [@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 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index af274f9e8bcaf..3a4b86c2c4cf0 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-06-16 +date: 2023-06-18 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 89342dde3491f..1e6f29b35db04 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 12894edd48f11..abe0f35c50dcc 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-06-16 +date: 2023-06-18 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 7baae2787c864..b5031004eee8c 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/reporting_export_types.mdx b/api_docs/reporting_export_types.mdx index faca1d35de068..b8c76fac03a33 100644 --- a/api_docs/reporting_export_types.mdx +++ b/api_docs/reporting_export_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reportingExportTypes title: "reportingExportTypes" image: https://source.unsplash.com/400x175/?github description: API docs for the reportingExportTypes plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reportingExportTypes'] --- import reportingExportTypesObj from './reporting_export_types.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index d6880d693140e..d01239730c257 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-06-16 +date: 2023-06-18 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 e3d422b49570f..11f7da5d113b5 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-06-16 +date: 2023-06-18 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 71b939c0df64e..5f491efc6e057 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-06-16 +date: 2023-06-18 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 f3485fd154132..2f4cd3c60ac62 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-06-16 +date: 2023-06-18 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 05c1742c46a84..3fbcc00155dab 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-06-16 +date: 2023-06-18 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 9d42755df200d..c8c3a65597411 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-06-16 +date: 2023-06-18 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 6d9bb92a141e8..db99732691490 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-06-16 +date: 2023-06-18 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 f82b18ee42dc4..32e1ba31b0d8b 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-06-16 +date: 2023-06-18 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 227d7e827efb2..615dfd6077015 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-06-16 +date: 2023-06-18 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 75468bb14aeeb..beb3cd889bdd6 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-06-16 +date: 2023-06-18 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 12b4d947258ce..71964e58bbee6 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-06-16 +date: 2023-06-18 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 8892000f95d85..f899c7c8fc3dd 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-06-16 +date: 2023-06-18 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 b5d516935041a..b4b55876e6087 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 7d3b899f9b79e..1424238d18f49 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-06-16 +date: 2023-06-18 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 852d675c37048..970ba7e7bf58a 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-06-16 +date: 2023-06-18 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 4e6096e5cd800..f7585a5919400 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/serverless_security.mdx b/api_docs/serverless_security.mdx index dccb1887beaf5..da37e8ecc44b3 100644 --- a/api_docs/serverless_security.mdx +++ b/api_docs/serverless_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSecurity title: "serverlessSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSecurity plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSecurity'] --- import serverlessSecurityObj from './serverless_security.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 4aae28b6f7bdc..3b8fae9bc880a 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-06-16 +date: 2023-06-18 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 b48acd52ae7fc..1fe0ec0756cbd 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-06-16 +date: 2023-06-18 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 03b0b31168281..9cdc226779acc 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index b0c9bdb5b0647..28ed3506d9fc4 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 3aa84a78b91dd..c9fb6819a9435 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-06-16 +date: 2023-06-18 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 c1ca28bc94fc2..1dc6547ea2e85 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-06-16 +date: 2023-06-18 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 36999d7c13258..31a6caa664a33 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-06-16 +date: 2023-06-18 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 3ba32c60cb354..cf1c97256f1a1 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-06-16 +date: 2023-06-18 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 a778bb1d95b05..6fd5b3a55f2d3 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-06-16 +date: 2023-06-18 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 c336e71f5877a..abb34f7a57828 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-06-16 +date: 2023-06-18 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 7506d05e99bfa..18b104ebdd396 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-06-16 +date: 2023-06-18 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 e74e0be56231f..42e24ee6ece95 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-06-16 +date: 2023-06-18 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 dfdd26bb7a4eb..768f748ca34bb 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 6ee92f5a513ef..2ae560cc1ca60 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-06-16 +date: 2023-06-18 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 56ef88da3a200..e80de865d4b17 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-06-16 +date: 2023-06-18 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 6207d7fc78c93..d0cdcbb31d684 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-06-16 +date: 2023-06-18 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 be718bb58463a..858d3c38c5215 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-06-16 +date: 2023-06-18 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 e6a42bb7964b3..8986386964362 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_field_list.mdx b/api_docs/unified_field_list.mdx index 76b529e3a4096..66982a46060d9 100644 --- a/api_docs/unified_field_list.mdx +++ b/api_docs/unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedFieldList title: "unifiedFieldList" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedFieldList plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedFieldList'] --- import unifiedFieldListObj from './unified_field_list.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 2b7b6d472c430..3be5c3a95c777 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-06-16 +date: 2023-06-18 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 b9af776ac190e..469df1ff12f28 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-06-16 +date: 2023-06-18 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 4e89eacae5d1e..e839f7de2276f 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 6ee693ac3e412..83c28890d21db 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-06-16 +date: 2023-06-18 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 dff68a27077ac..fc0cc452d1179 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-06-16 +date: 2023-06-18 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 517d4c4b8d019..3586c640cf2a9 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-06-16 +date: 2023-06-18 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 af406d91a5a19..56d710ee281cf 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-06-16 +date: 2023-06-18 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 9981d8c3f3db6..ef6b832d3bc37 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-06-16 +date: 2023-06-18 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 bbc4452cc82c0..538ebe9933440 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-06-16 +date: 2023-06-18 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 1085c6a4c4a5f..76310b5e48e91 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-06-16 +date: 2023-06-18 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 e5320c124db57..dc9b08ae880a2 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-06-16 +date: 2023-06-18 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 859e47fec0439..2e4d4df49717d 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-06-16 +date: 2023-06-18 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 1001199df6a3a..02f07e4707d0a 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-06-16 +date: 2023-06-18 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 c3c24cd67c0a3..191c6227e0884 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-06-16 +date: 2023-06-18 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 06bfd2b5380e2..4ff2136b80fd0 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-06-16 +date: 2023-06-18 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 9c91ae64f5217..80276e4a43418 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualization_ui_components.mdx b/api_docs/visualization_ui_components.mdx index 3007cc6fd89c6..e66d26b61c0b9 100644 --- a/api_docs/visualization_ui_components.mdx +++ b/api_docs/visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizationUiComponents title: "visualizationUiComponents" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizationUiComponents plugin -date: 2023-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizationUiComponents'] --- import visualizationUiComponentsObj from './visualization_ui_components.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 18b16e947c202..2a6ddb137a20a 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-06-16 +date: 2023-06-18 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/config/serverless.oblt.yml b/config/serverless.oblt.yml index 3725eedb79945..9f34fb10898a6 100644 --- a/config/serverless.oblt.yml +++ b/config/serverless.oblt.yml @@ -27,6 +27,14 @@ xpack.apm.serverlessOnboarding: true xpack.fleet.packages: - name: apm version: latest +## Disable APM UI components and API calls +xpack.apm.featureFlags.agentConfigurationAvailable: false +xpack.apm.featureFlags.configurableIndicesAvailable: false +xpack.apm.featureFlags.infrastructureTabAvailable: false +xpack.apm.featureFlags.infraUiAvailable: false +xpack.apm.featureFlags.migrationToFleetAvailable: false +xpack.apm.featureFlags.sourcemapApiAvailable: false +xpack.apm.featureFlags.storageExplorerAvailable: false # Specify in telemetry the project type telemetry.labels.serverless: observability diff --git a/docs/api-generated/rules/rule-apis-passthru.asciidoc b/docs/api-generated/rules/rule-apis-passthru.asciidoc index e621edeca2dd4..94353902041d1 100644 --- a/docs/api-generated/rules/rule-apis-passthru.asciidoc +++ b/docs/api-generated/rules/rule-apis-passthru.asciidoc @@ -18,7 +18,8 @@ Any modifications made to this file will be overwritten.

Alerting

    -
  • post /s/{spaceId}/api/alerting/rule/{ruleId}
  • +
  • post /s/{spaceId}/api/alerting/rule
  • +
  • post /s/{spaceId}/api/alerting/rule/{ruleId}
  • delete /s/{spaceId}/api/alerting/rule/{ruleId}
  • post /s/{spaceId}/api/alerting/rule/{ruleId}/_disable
  • post /s/{spaceId}/api/alerting/rule/{ruleId}/_enable
  • @@ -48,10 +49,246 @@ Any modifications made to this file will be overwritten.

    Alerting

    +
    + Up +
    post /s/{spaceId}/api/alerting/rule
    +
    Creates a rule with a randomly generated rule identifier. (createRule)
    +
    You must have all privileges for the appropriate Kibana features, depending on the consumer and rule_type_id of the rule you're creating. For example, you must have privileges for the Management > Stack rules feature, Analytics > Discover and Machine Learning features, Observability features, or Security features. If the rule has actions, you must also have read privileges for the Management > Actions and Connectors feature. NOTE: This API supports only token-based authentication. When you create a rule, it identifies which roles you have at that point in time. Thereafter, when the rule performs queries, it uses those security privileges. If a user with different privileges updates the rule, its behavior might change.
    + +

    Path parameters

    +
    +
    spaceId (required)
    + +
    Path Parameter — An identifier for the space. If /s/ and the identifier are omitted from the path, the default space is used. default: null
    +
    + +

    Consumes

    + This API call consumes the following media types via the Content-Type request header: +
      +
    • application/json
    • +
    + +

    Request body

    +
    +
    create_rule_request create_rule_request (required)
    + +
    Body Parameter
    + +
    + +

    Request headers

    +
    +
    kbn-xsrf (required)
    + +
    Header Parameter — Cross-site request forgery protection default: null
    + +
    + + + +

    Return type

    + + + + +

    Example data

    +
    Content-Type: application/json
    +
    {
    +  "throttle" : "10m",
    +  "created_at" : "2022-12-05T23:36:58.284Z",
    +  "api_key_created_by_user" : false,
    +  "enabled" : true,
    +  "running" : true,
    +  "notify_when" : "onActiveAlert",
    +  "next_run" : "2022-12-06T00:14:43.818Z",
    +  "updated_at" : "2022-12-05T23:36:58.284Z",
    +  "execution_status" : {
    +    "last_execution_date" : "2022-12-06T00:13:43.89Z",
    +    "last_duration" : 55,
    +    "status" : "ok"
    +  },
    +  "scheduled_task_id" : "b530fed0-74f5-11ed-9801-35303b735aef",
    +  "id" : "b530fed0-74f5-11ed-9801-35303b735aef",
    +  "consumer" : "alerts",
    +  "last_run" : {
    +    "alerts_count" : {
    +      "ignored" : 6,
    +      "new" : 1,
    +      "recovered" : 5,
    +      "active" : 0
    +    },
    +    "outcome_msg" : [ "outcome_msg", "outcome_msg" ],
    +    "outcome_order" : 5,
    +    "warning" : "warning",
    +    "outcome" : "succeeded"
    +  },
    +  "params" : {
    +    "key" : ""
    +  },
    +  "created_by" : "elastic",
    +  "muted_alert_ids" : [ "muted_alert_ids", "muted_alert_ids" ],
    +  "rule_type_id" : "monitoring_alert_cluster_health",
    +  "revision" : 2,
    +  "tags" : [ "tags", "tags" ],
    +  "api_key_owner" : "elastic",
    +  "schedule" : {
    +    "interval" : "1m"
    +  },
    +  "name" : "cluster_health_rule",
    +  "updated_by" : "elastic",
    +  "mute_all" : false,
    +  "actions" : [ {
    +    "alerts_filter" : {
    +      "timeframe" : {
    +        "hours" : {
    +          "start" : "08:00",
    +          "end" : "17:00"
    +        },
    +        "timezone" : "Europe/Madrid",
    +        "days" : [ 1, 2, 3, 4, 5 ]
    +      },
    +      "query" : {
    +        "kql" : "kql",
    +        "filters" : [ {
    +          "$state" : "{}",
    +          "meta" : {
    +            "field" : "field",
    +            "controlledBy" : "controlledBy",
    +            "negate" : true,
    +            "alias" : "alias",
    +            "index" : "index",
    +            "disabled" : true,
    +            "params" : "{}",
    +            "type" : "type",
    +            "value" : "value",
    +            "isMultiIndex" : true,
    +            "key" : "key",
    +            "group" : "group"
    +          },
    +          "query" : "{}"
    +        }, {
    +          "$state" : "{}",
    +          "meta" : {
    +            "field" : "field",
    +            "controlledBy" : "controlledBy",
    +            "negate" : true,
    +            "alias" : "alias",
    +            "index" : "index",
    +            "disabled" : true,
    +            "params" : "{}",
    +            "type" : "type",
    +            "value" : "value",
    +            "isMultiIndex" : true,
    +            "key" : "key",
    +            "group" : "group"
    +          },
    +          "query" : "{}"
    +        } ]
    +      }
    +    },
    +    "id" : "9dca3e00-74f5-11ed-9801-35303b735aef",
    +    "params" : {
    +      "key" : ""
    +    },
    +    "uuid" : "1c7a1280-f28c-4e06-96b2-e4e5f05d1d61",
    +    "connector_type_id" : ".server-log",
    +    "frequency" : {
    +      "summary" : true,
    +      "throttle" : "10m",
    +      "notify_when" : "onActiveAlert"
    +    },
    +    "group" : "default"
    +  }, {
    +    "alerts_filter" : {
    +      "timeframe" : {
    +        "hours" : {
    +          "start" : "08:00",
    +          "end" : "17:00"
    +        },
    +        "timezone" : "Europe/Madrid",
    +        "days" : [ 1, 2, 3, 4, 5 ]
    +      },
    +      "query" : {
    +        "kql" : "kql",
    +        "filters" : [ {
    +          "$state" : "{}",
    +          "meta" : {
    +            "field" : "field",
    +            "controlledBy" : "controlledBy",
    +            "negate" : true,
    +            "alias" : "alias",
    +            "index" : "index",
    +            "disabled" : true,
    +            "params" : "{}",
    +            "type" : "type",
    +            "value" : "value",
    +            "isMultiIndex" : true,
    +            "key" : "key",
    +            "group" : "group"
    +          },
    +          "query" : "{}"
    +        }, {
    +          "$state" : "{}",
    +          "meta" : {
    +            "field" : "field",
    +            "controlledBy" : "controlledBy",
    +            "negate" : true,
    +            "alias" : "alias",
    +            "index" : "index",
    +            "disabled" : true,
    +            "params" : "{}",
    +            "type" : "type",
    +            "value" : "value",
    +            "isMultiIndex" : true,
    +            "key" : "key",
    +            "group" : "group"
    +          },
    +          "query" : "{}"
    +        } ]
    +      }
    +    },
    +    "id" : "9dca3e00-74f5-11ed-9801-35303b735aef",
    +    "params" : {
    +      "key" : ""
    +    },
    +    "uuid" : "1c7a1280-f28c-4e06-96b2-e4e5f05d1d61",
    +    "connector_type_id" : ".server-log",
    +    "frequency" : {
    +      "summary" : true,
    +      "throttle" : "10m",
    +      "notify_when" : "onActiveAlert"
    +    },
    +    "group" : "default"
    +  } ]
    +}
    + +

    Produces

    + This API call produces the following media types according to the Accept request header; + the media type will be conveyed by the Content-Type response header. +
      +
    • application/json
    • +
    + +

    Responses

    +

    200

    + Indicates a successful call. + rule_response_properties +

    401

    + Authorization information is missing or invalid. + 401_response +

    404

    + Object is not found. + 404_response +
    +
    +
    Up
    post /s/{spaceId}/api/alerting/rule/{ruleId}
    -
    Creates a rule. (createRule)
    +
    Creates a rule with a specific rule identifier. (createRuleId)
    You must have all privileges for the appropriate Kibana features, depending on the consumer and rule_type_id of the rule you're creating. For example, you must have privileges for the Management > Stack rules feature, Analytics > Discover and Machine Learning features, Observability features, or Security features. If the rule has actions, you must also have read privileges for the Management > Actions and Connectors feature. NOTE: This API supports only token-based authentication. When you create a rule, it identifies which roles you have at that point in time. Thereafter, when the rule performs queries, it uses those security privileges. If a user with different privileges updates the rule, its behavior might change.

    Path parameters

    @@ -2598,11 +2835,16 @@ Any modifications made to this file will be overwritten.
    1. 401_response - Unsuccessful rule API response
    2. 404_response -
    3. +
    4. Count - Count
    5. +
    6. Count_count -
    7. +
    8. Count_criteria -
    9. +
    10. Count_logView -
    11. Legacy_create_alert_request_properties - Legacy create alert request properties
    12. Legacy_create_alert_request_properties_schedule -
    13. Legacy_update_alert_request_properties - Legacy update alert request properties
    14. Legacy_update_alert_request_properties_actions_inner -
    15. Legacy_update_alert_request_properties_schedule -
    16. +
    17. Ratio - Ratio
    18. actions_inner -
    19. actions_inner_alerts_filter -
    20. actions_inner_alerts_filter_query -
    21. @@ -2614,7 +2856,54 @@ Any modifications made to this file will be overwritten.
    22. alert_response_properties - Legacy alert response properties
    23. alert_response_properties_executionStatus -
    24. alert_response_properties_schedule -
    25. -
    26. create_rule_request - Create rule request
    27. +
    28. count_criterion - count criterion
    29. +
    30. create_anomaly_detection_alert_rule_request - Create anomaly detection rule request
    31. +
    32. create_anomaly_detection_jobs_health_rule_request - Create anomaly detection jobs health rule request
    33. +
    34. create_apm_anomaly_rule_request - Create APM anomaly rule rule request
    35. +
    36. create_apm_error_count_rule_request - Create APM error count rule request
    37. +
    38. create_apm_transaction_duration_rule_request - Create latency threshold rule request
    39. +
    40. create_apm_transaction_error_rate_rule_request - Create APM transaction error rate rule request
    41. +
    42. create_es_query_rule_request - Create Elasticsearch query rule request
    43. +
    44. create_geo_containment_rule_request - Create traacking containment rule request
    45. +
    46. create_index_threshold_rule_request - Create index threshold rule request
    47. +
    48. create_infra_inventory_rule_request - Create infra inventory rule request
    49. +
    50. create_infra_metric_anomaly_rule_request - Create infrastructure anomaly rule request
    51. +
    52. create_infra_metric_threshold_rule_request - Create infra metric threshold rule request
    53. +
    54. create_log_threshold_rule_request - Create log threshold rule request
    55. +
    56. create_monitoring_ccr_exceptions_rule_request - Create CCR read exceptions rule request
    57. +
    58. create_monitoring_cluster_health_rule_request - Create cluster health rule request
    59. +
    60. create_monitoring_cpu_usage_rule_request - Create CPU usage rule request
    61. +
    62. create_monitoring_disk_usage_rule_request - Create disk usage rule request
    63. +
    64. create_monitoring_elasticsearch_version_mismatch_rule_request - Create Elasticsearch version mismatch rule request
    65. +
    66. create_monitoring_jvm_memory_usage_rule_request - Create JVM memory usage rule request
    67. +
    68. create_monitoring_kibana_version_mismatch_rule_request - Create Kibana version mismatch rule request
    69. +
    70. create_monitoring_license_expiration_rule_request - Create license expiration rule request
    71. +
    72. create_monitoring_logstash_version_mismatch_rule_request - Create Logstash version mismatch rule request
    73. +
    74. create_monitoring_missing_data_rule_request - Create missing monitoring data rule request
    75. +
    76. create_monitoring_nodes_changed_rule_request - Create nodes changed rule request
    77. +
    78. create_monitoring_shard_size_rule_request - Create shard size rule request
    79. +
    80. create_monitoring_thread_pool_search_rejections_rule_request - Create thread pool search rejections rule request
    81. +
    82. create_monitoring_thread_pool_write_rejections_rule_request - Create thread pool write rejections rule request
    83. +
    84. create_rule_request - Create rule request body properties
    85. +
    86. create_siem_eql_rule_request - Create event correlation rule request
    87. +
    88. create_siem_indicator_rule_request - Create indicator match rule request
    89. +
    90. create_siem_ml_rule_request - Create machine learning rule request
    91. +
    92. create_siem_new_terms_rule_request - Create new terms rule request
    93. +
    94. create_siem_notifications_rule_request - Create security solution notification (legacy) rule request
    95. +
    96. create_siem_query_rule_request - Create custom query rule request
    97. +
    98. create_siem_saved_query_rule_request - Create saved query rule request
    99. +
    100. create_siem_threshold_rule_request - Create threshold rule request
    101. +
    102. create_slo_burn_rate_rule_request - Create slo burn rate rule request
    103. +
    104. create_synthetics_monitor_status_rule_request - Create synthetics monitor status rule request
    105. +
    106. create_synthetics_uptime_duration_anomaly_rule_request - Create synthetics uptime duration anomaly rule request
    107. +
    108. create_synthetics_uptime_tls_certificate_rule_request - Create TLS certificate rule request
    109. +
    110. create_synthetics_uptime_tls_rule_request - Create synthetics uptime TLS rule request
    111. +
    112. create_transform_health_rule_request - Create transform health rule request
    113. +
    114. create_uptime_monitor_status_rule_request - Create uptime monitor status rule request
    115. +
    116. custom_criterion - custom criterion
    117. +
    118. custom_criterion_customMetric_inner -
    119. +
    120. custom_criterion_customMetric_inner_oneOf -
    121. +
    122. custom_criterion_customMetric_inner_oneOf_1 -
    123. findRules_200_response -
    124. findRules_has_reference_parameter -
    125. findRules_search_fields_parameter -
    126. @@ -2641,7 +2930,27 @@ Any modifications made to this file will be overwritten.
    127. legacyGetAlertingHealth_200_response_alertingFrameworkHealth_decryptionHealth -
    128. legacyGetAlertingHealth_200_response_alertingFrameworkHealth_executionHealth -
    129. legacyGetAlertingHealth_200_response_alertingFrameworkHealth_readHealth -
    130. +
    131. non_count_criterion - non count criterion
    132. notify_when -
    133. +
    134. params_property_apm_anomaly -
    135. +
    136. params_property_apm_error_count -
    137. +
    138. params_property_apm_transaction_duration -
    139. +
    140. params_property_apm_transaction_error_rate -
    141. +
    142. params_property_infra_inventory -
    143. +
    144. params_property_infra_inventory_criteria_inner -
    145. +
    146. params_property_infra_inventory_criteria_inner_customMetric -
    147. +
    148. params_property_infra_metric_threshold -
    149. +
    150. params_property_infra_metric_threshold_criteria_inner -
    151. +
    152. params_property_log_threshold -
    153. +
    154. params_property_slo_burn_rate -
    155. +
    156. params_property_slo_burn_rate_longWindow -
    157. +
    158. params_property_slo_burn_rate_shortWindow -
    159. +
    160. params_property_synthetics_monitor_status -
    161. +
    162. params_property_synthetics_monitor_status_availability -
    163. +
    164. params_property_synthetics_monitor_status_filters -
    165. +
    166. params_property_synthetics_monitor_status_filters_oneOf -
    167. +
    168. params_property_synthetics_monitor_status_timerange -
    169. +
    170. params_property_synthetics_uptime_tls -
    171. rule_response_properties - Rule response properties
    172. rule_response_properties_execution_status -
    173. rule_response_properties_last_run -
    174. @@ -2677,41 +2986,86 @@ Any modifications made to this file will be overwritten.
    -

    Legacy_create_alert_request_properties - Legacy create alert request properties Up

    +

    Count - Count Up

    -
    actions (optional)
    -
    alertTypeId
    String The ID of the alert type that you want to call when the alert is scheduled to run.
    -
    consumer
    String The name of the application that owns the alert. This name has to match the Kibana feature name, as that dictates the required role-based access control privileges.
    -
    enabled (optional)
    Boolean Indicates if you want to run the alert on an interval basis after it is created.
    -
    name
    String A name to reference and search.
    -
    notifyWhen
    String The condition for throttling the notification.
    +
    criteria (optional)
    +
    count
    +
    timeSize
    +
    timeUnit
    Enum:
    -
    onActionGroupChange
    onActiveAlert
    onThrottleInterval
    -
    params
    Object The parameters to pass to the alert type executor params value. This will also validate against the alert type params validator, if defined.
    -
    schedule
    -
    tags (optional)
    array[String] A list of keywords to reference and search.
    -
    throttle (optional)
    String How often this alert should fire the same actions. This will prevent the alert from sending out the same notification over and over. For example, if an alert with a schedule of 1 minute stays in a triggered state for 90 minutes, setting a throttle of 10m or 1h will prevent it from sending 90 notifications during this period.
    +
    s
    m
    h
    d
    +
    logView
    +
    groupBy (optional)
    -

    Legacy_create_alert_request_properties_schedule - Up

    -
    The schedule specifying when this alert should be run. A schedule is structured such that the key specifies the format you wish to use and its value specifies the schedule.
    +

    Count_count - Up

    +
    -
    interval (optional)
    String The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute.
    +
    comparator (optional)
    +
    Enum:
    +
    more than
    more than or equals
    less than
    less than or equals
    equals
    does not equal
    matches
    does not match
    matches phrase
    does not match phrase
    +
    value (optional)
    -

    Legacy_update_alert_request_properties - Legacy update alert request properties Up

    +

    Count_criteria - Up

    -
    actions (optional)
    -
    name
    String A name to reference and search.
    -
    notifyWhen
    String The condition for throttling the notification.
    +
    field (optional)
    +
    comparator (optional)
    Enum:
    -
    onActionGroupChange
    onActiveAlert
    onThrottleInterval
    -
    params
    Object The parameters to pass to the alert type executor params value. This will also validate against the alert type params validator, if defined.
    -
    schedule
    +
    more than
    more than or equals
    less than
    less than or equals
    equals
    does not equal
    matches
    does not match
    matches phrase
    does not match phrase
    +
    value (optional)
    +
    +
    +
    +

    Count_logView - Up

    +
    +
    +
    logViewId (optional)
    +
    type (optional)
    +
    Enum:
    +
    log-view-reference
    +
    +
    +
    +

    Legacy_create_alert_request_properties - Legacy create alert request properties Up

    +
    +
    +
    actions (optional)
    +
    alertTypeId
    String The ID of the alert type that you want to call when the alert is scheduled to run.
    +
    consumer
    String The name of the application that owns the alert. This name has to match the Kibana feature name, as that dictates the required role-based access control privileges.
    +
    enabled (optional)
    Boolean Indicates if you want to run the alert on an interval basis after it is created.
    +
    name
    String A name to reference and search.
    +
    notifyWhen
    String The condition for throttling the notification.
    +
    Enum:
    +
    onActionGroupChange
    onActiveAlert
    onThrottleInterval
    +
    params
    Object The parameters to pass to the alert type executor params value. This will also validate against the alert type params validator, if defined.
    +
    schedule
    +
    tags (optional)
    array[String] A list of keywords to reference and search.
    +
    throttle (optional)
    String How often this alert should fire the same actions. This will prevent the alert from sending out the same notification over and over. For example, if an alert with a schedule of 1 minute stays in a triggered state for 90 minutes, setting a throttle of 10m or 1h will prevent it from sending 90 notifications during this period.
    +
    +
    +
    +

    Legacy_create_alert_request_properties_schedule - Up

    +
    The schedule specifying when this alert should be run. A schedule is structured such that the key specifies the format you wish to use and its value specifies the schedule.
    +
    +
    interval (optional)
    String The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute.
    +
    +
    +
    +

    Legacy_update_alert_request_properties - Legacy update alert request properties Up

    +
    +
    +
    actions (optional)
    +
    name
    String A name to reference and search.
    +
    notifyWhen
    String The condition for throttling the notification.
    +
    Enum:
    +
    onActionGroupChange
    onActiveAlert
    onThrottleInterval
    +
    params
    Object The parameters to pass to the alert type executor params value. This will also validate against the alert type params validator, if defined.
    +
    schedule
    tags (optional)
    array[String] A list of keywords to reference and search.
    throttle (optional)
    String How often this alert should fire the same actions. This will prevent the alert from sending out the same notification over and over. For example, if an alert with a schedule of 1 minute stays in a triggered state for 90 minutes, setting a throttle of 10m or 1h will prevent it from sending 90 notifications during this period.
    @@ -2733,6 +3087,20 @@ Any modifications made to this file will be overwritten.
    interval (optional)
    String The interval format specifies the interval in seconds, minutes, hours or days at which the alert should execute.
    +
    +

    Ratio - Ratio Up

    +
    +
    +
    criteria (optional)
    +
    count
    +
    timeSize
    +
    timeUnit
    +
    Enum:
    +
    s
    m
    h
    d
    +
    logView
    +
    groupBy (optional)
    +
    +

    actions_inner - Up

    @@ -2755,120 +3123,953 @@ Any modifications made to this file will be overwritten.
    -

    actions_inner_alerts_filter_query - Up

    -
    Defines a query filter that determines whether the action runs.
    +

    actions_inner_alerts_filter_query - Up

    +
    Defines a query filter that determines whether the action runs.
    +
    +
    kql (optional)
    String A filter written in Kibana Query Language (KQL).
    +
    filters (optional)
    +
    +
    +
    +

    actions_inner_alerts_filter_query_filters_inner - Up

    +
    A filter written in Elasticsearch Query Domain Specific Language (DSL) as defined in the kbn-es-query package.
    +
    +
    meta (optional)
    +
    query (optional)
    +
    Dollarstate (optional)
    +
    +
    +
    +

    actions_inner_alerts_filter_query_filters_inner_meta - Up

    +
    +
    +
    alias (optional)
    +
    controlledBy (optional)
    +
    disabled (optional)
    +
    field (optional)
    +
    group (optional)
    +
    index (optional)
    +
    isMultiIndex (optional)
    +
    key (optional)
    +
    negate (optional)
    +
    params (optional)
    +
    type (optional)
    +
    value (optional)
    +
    +
    +
    +

    actions_inner_alerts_filter_timeframe - Up

    +
    Defines a period that limits whether the action runs.
    +
    +
    days (optional)
    array[Integer] Defines the days of the week that the action can run, represented as an array of numbers. For example, 1 represents Monday. An empty array is equivalent to specifying all the days of the week.
    +
    hours (optional)
    +
    timezone (optional)
    String The ISO time zone for the hours values. Values such as UTC and UTC+1 also work but lack built-in daylight savings time support and are not recommended.
    +
    +
    +
    +

    actions_inner_alerts_filter_timeframe_hours - Up

    +
    Defines the range of time in a day that the action can run. If the start value is 00:00 and the end value is 24:00, actions be generated all day.
    +
    +
    end (optional)
    String The end of the time frame in 24-hour notation (hh:mm).
    +
    start (optional)
    String The start of the time frame in 24-hour notation (hh:mm).
    +
    +
    +
    +

    actions_inner_frequency - Up

    +
    The parameters that affect how often actions are generated. NOTE: You cannot specify these parameters when notify_when or throttle are defined at the rule level.
    +
    +
    notify_when
    +
    summary
    Boolean Indicates whether the action is a summary.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    alert_response_properties - Legacy alert response properties Up

    +
    +
    +
    actions (optional)
    +
    alertTypeId (optional)
    +
    apiKeyOwner (optional)
    +
    createdAt (optional)
    Date The date and time that the alert was created. format: date-time
    +
    createdBy (optional)
    String The identifier for the user that created the alert.
    +
    enabled (optional)
    Boolean Indicates whether the alert is currently enabled.
    +
    executionStatus (optional)
    +
    id (optional)
    String The identifier for the alert.
    +
    muteAll (optional)
    +
    mutedInstanceIds (optional)
    +
    name (optional)
    String The name of the alert.
    +
    notifyWhen (optional)
    +
    params (optional)
    +
    schedule (optional)
    +
    scheduledTaskId (optional)
    +
    tags (optional)
    +
    throttle (optional)
    +
    updatedAt (optional)
    +
    updatedBy (optional)
    String The identifier for the user that updated this alert most recently.
    +
    +
    +
    +

    alert_response_properties_executionStatus - Up

    +
    +
    +
    lastExecutionDate (optional)
    Date format: date-time
    +
    status (optional)
    +
    +
    +
    +

    alert_response_properties_schedule - Up

    +
    +
    +
    interval (optional)
    +
    +
    +
    +

    count_criterion - count criterion Up

    +
    +
    +
    threshold (optional)
    +
    comparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    timeUnit (optional)
    +
    timeSize (optional)
    +
    warningThreshold (optional)
    +
    warningComparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    aggType (optional)
    +
    Enum:
    +
    count
    +
    +
    +
    +

    create_anomaly_detection_alert_rule_request - Create anomaly detection rule request Up

    +
    A rule that checks if the anomaly detection job results contain anomalies that match the rule conditions.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an anomaly detection rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.ml.anomaly_detection_alert
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_anomaly_detection_jobs_health_rule_request - Create anomaly detection jobs health rule request Up

    +
    An rule that monitors job health and alerts if an operational issue occurred that may prevent the job from detecting anomalies.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an anomaly detection jobs health rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.ml.anomaly_detection_jobs_health
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_apm_anomaly_rule_request - Create APM anomaly rule rule request Up

    +
    A rule that detects when either the latency, throughput, or failed transaction rate of a service is anomalous.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    apm.anomaly
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_apm_error_count_rule_request - Create APM error count rule request Up

    +
    A rule that detects when the number of errors in a service exceeds a defined threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    apm.error_rate
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_apm_transaction_duration_rule_request - Create latency threshold rule request Up

    +
    A rule that detects when the latency of a specific transaction type in a service exceeds a threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    apm.transaction_duration
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_apm_transaction_error_rate_rule_request - Create APM transaction error rate rule request Up

    +
    A rule that sends notifications when the rate of transaction errors in a service exceeds a threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    apm.transaction_error_rate
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_es_query_rule_request - Create Elasticsearch query rule request Up

    +
    A rule that runs a user-configured query, compares the number of matches to a configured threshold, and schedules actions to run when the threshold condition is met.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an Elasticsearch query rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    .es-query
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_geo_containment_rule_request - Create traacking containment rule request Up

    +
    A rule that runs an Elasticsearch query over indices to determine whether any documents are currently contained within any boundaries from the specified boundary index. In the event that an entity is contained within a boundary, an alert may be generated.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an tracking containment rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    .geo-containment
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_index_threshold_rule_request - Create index threshold rule request Up

    +
    A rule that runs an Elasticsearch query, aggregates field values from documents, compares them to threshold values, and schedules actions to run when the thresholds are met.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an index threshold rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    .index-threshold
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_infra_inventory_rule_request - Create infra inventory rule request Up

    +
    A rule that sends notifications when a metric has reached or exceeded a value for a specific resource or a group of resources within your infrastructure.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    metrics.alert.inventory.threshold
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_infra_metric_anomaly_rule_request - Create infrastructure anomaly rule request Up

    +
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an infrastructure anomaly rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    metrics.alert.anomaly
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_infra_metric_threshold_rule_request - Create infra metric threshold rule request Up

    +
    A rule that sends notifications when a metric has reached or exceeded a value for a specific time period.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    metrics.alert.threshold
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_log_threshold_rule_request - Create log threshold rule request Up

    +
    A rule that detects when a log aggregation exceeds a threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    logs.alert.document.count
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_ccr_exceptions_rule_request - Create CCR read exceptions rule request Up

    +
    A rule that detects cross-cluster replication (CCR) read exceptions.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a CCR read exceptions rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_ccr_read_exceptions
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_cluster_health_rule_request - Create cluster health rule request Up

    +
    A rule that detects when the health of the cluster changes.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a cluster health rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_cluster_health
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_cpu_usage_rule_request - Create CPU usage rule request Up

    +
    A rule that detects when the CPU load for a node is consistently high.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a CPU usage rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_cpu_usage
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_disk_usage_rule_request - Create disk usage rule request Up

    +
    A rule that detects when the disk usage for a node is consistently high.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a disk usage rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_disk_usage
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_elasticsearch_version_mismatch_rule_request - Create Elasticsearch version mismatch rule request Up

    +
    A rule that detects when the cluster has multipe versions of Elasticsearch.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a Elasticsearch version mismatch rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_elasticsearch_version_mismatch
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_jvm_memory_usage_rule_request - Create JVM memory usage rule request Up

    +
    A rule that detects when a node reports high memory usage.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a JVM memory usage rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_jvm_memory_usage
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_kibana_version_mismatch_rule_request - Create Kibana version mismatch rule request Up

    +
    A rule that detects when the cluster has multiple versions of Kibana.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a Kibana version mismatch rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_kibana_version_mismatch
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_license_expiration_rule_request - Create license expiration rule request Up

    +
    A rule that detects when the cluster license is about to expire.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a license expiration rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_license_expiration
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_logstash_version_mismatch_rule_request - Create Logstash version mismatch rule request Up

    +
    A rule that detects when the cluster has multiple versions of Logstash.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a Logstash version mismatch rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_logstash_version_mismatch
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_missing_data_rule_request - Create missing monitoring data rule request Up

    +
    A rule that detects when monitoring data is missing.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a missing monitoring data rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_missing_monitoring_data
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_nodes_changed_rule_request - Create nodes changed rule request Up

    +
    A rule that detects when nodes are added, removed, or restarted.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a nodes changed rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_nodes_changed
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_shard_size_rule_request - Create shard size rule request Up

    +
    A rule that detects when the average shard size is larger than a threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a shard size rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_shard_size
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_thread_pool_search_rejections_rule_request - Create thread pool search rejections rule request Up

    +
    A rule that detects when the number of rejections in the thread pool exceeds a threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a thread pool search rejections rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_thread_pool_search_rejections
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_monitoring_thread_pool_write_rejections_rule_request - Create thread pool write rejections rule request Up

    +
    A rule that detects when the number of rejections in the write thread pool exceeds a threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a thread pool write rejections rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    monitoring_alert_thread_pool_write_rejections
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_rule_request - Create rule request body properties Up

    +
    The properties vary depending on the rule type.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.uptime.alerts.monitorStatus
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_eql_rule_request - Create event correlation rule request Up

    +
    A rule that uses Event Query Language (EQL) to match events, generate sequences, and stack data.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an event correlation rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.eqlRule
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_indicator_rule_request - Create indicator match rule request Up

    +
    A rule that uses indicators from intelligence sources to detect matching events and alerts.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for an indicator match rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.indicatorRule
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_ml_rule_request - Create machine learning rule request Up

    +
    A rule that detects when a machine learning job discovers an anomaly above the defined threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a machine learning rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.mlRule
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_new_terms_rule_request - Create new terms rule request Up

    +
    A rule that finds documents with values that appear for the first time.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a new terms rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.newTermsRule
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_notifications_rule_request - Create security solution notification (legacy) rule request Up

    +
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a notification rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.notifications
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_query_rule_request - Create custom query rule request Up

    +
    A rule that uses KQL or Lucene to detect issues across indices.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a custom query rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.queryRule
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_saved_query_rule_request - Create saved query rule request Up

    +
    A rule that searches the defined indices and creates an alert when a document matches the saved search.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a saved query rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.savedQueryRule
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_siem_threshold_rule_request - Create threshold rule request Up

    +
    A rule that aggregates query results to detect when the number of matches exceeds a threshold.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a threshold rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    siem.thresholdRule
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_slo_burn_rate_rule_request - Create slo burn rate rule request Up

    +
    A rule that detects when the burn rate is above a defined threshold for two different lookback periods. The two periods are a long period and a short period that is 1/12th of the long period. For each lookback period, the burn rate is computed as the error rate divided by the error budget. When the burn rates for both periods surpass the threshold, an alert occurs.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    slo.rules.burnRate
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_synthetics_monitor_status_rule_request - Create synthetics monitor status rule request Up

    +
    A rule that detects when a monitor is down or an availability threshold is breached.
    +
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for the synthetics monitor status rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.synthetics.alerts.monitorStatus
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    +
    +
    +

    create_synthetics_uptime_duration_anomaly_rule_request - Create synthetics uptime duration anomaly rule request Up

    +
    A rule that detects response durations for all of the geographic locations of each monitor. When a monitor runs for an unusual amount of time, at a particular time, an anomaly is recorded.
    -
    kql (optional)
    String A filter written in Kibana Query Language (KQL).
    -
    filters (optional)
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for the uptime duration anomaly rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.uptime.alerts.durationAnomaly
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    -

    actions_inner_alerts_filter_query_filters_inner - Up

    -
    A filter written in Elasticsearch Query Domain Specific Language (DSL) as defined in the kbn-es-query package.
    +

    create_synthetics_uptime_tls_certificate_rule_request - Create TLS certificate rule request Up

    +
    A rule that detects when a monitor has a TLS certificate expiring or when it exceeds an age limit.
    -
    meta (optional)
    -
    query (optional)
    -
    Dollarstate (optional)
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a TLS certificate rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.uptime.alerts.tlsCertificate
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    -

    actions_inner_alerts_filter_query_filters_inner_meta - Up

    +

    create_synthetics_uptime_tls_rule_request - Create synthetics uptime TLS rule request Up

    -
    alias (optional)
    -
    controlledBy (optional)
    -
    disabled (optional)
    -
    field (optional)
    -
    group (optional)
    -
    index (optional)
    -
    isMultiIndex (optional)
    -
    key (optional)
    -
    negate (optional)
    -
    params (optional)
    -
    type (optional)
    -
    value (optional)
    -
    -
    -
    -

    actions_inner_alerts_filter_timeframe - Up

    -
    Defines a period that limits whether the action runs.
    -
    -
    days (optional)
    array[Integer] Defines the days of the week that the action can run, represented as an array of numbers. For example, 1 represents Monday. An empty array is equivalent to specifying all the days of the week.
    -
    hours (optional)
    -
    timezone (optional)
    String The ISO time zone for the hours values. Values such as UTC and UTC+1 also work but lack built-in daylight savings time support and are not recommended.
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.uptime.alerts.tls
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    -

    actions_inner_alerts_filter_timeframe_hours - Up

    -
    Defines the range of time in a day that the action can run. If the start value is 00:00 and the end value is 24:00, actions be generated all day.
    +

    create_transform_health_rule_request - Create transform health rule request Up

    +
    A rule that monitors transforms health and alerts if an operational issue occurred.
    -
    end (optional)
    String The end of the time frame in 24-hour notation (hh:mm).
    -
    start (optional)
    String The start of the time frame in 24-hour notation (hh:mm).
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    map[String, oas_any_type_not_mapped] The parameters for a transform health rule.
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    transform_health
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    +
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    -

    actions_inner_frequency - Up

    -
    The parameters that affect how often actions are generated. NOTE: You cannot specify these parameters when notify_when or throttle are defined at the rule level.
    +

    create_uptime_monitor_status_rule_request - Create uptime monitor status rule request Up

    +
    A rule that detects monitor errors and outages.
    -
    notify_when
    -
    summary
    Boolean Indicates whether the action is a summary.
    +
    actions (optional)
    +
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    +
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    +
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    +
    notify_when (optional)
    +
    params
    +
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run.
    +
    Enum:
    +
    xpack.uptime.alerts.monitorStatus
    +
    schedule
    +
    tags (optional)
    array[String] The tags for the rule.
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    -

    alert_response_properties - Legacy alert response properties Up

    +

    custom_criterion - custom criterion Up

    -
    actions (optional)
    -
    alertTypeId (optional)
    -
    apiKeyOwner (optional)
    -
    createdAt (optional)
    Date The date and time that the alert was created. format: date-time
    -
    createdBy (optional)
    String The identifier for the user that created the alert.
    -
    enabled (optional)
    Boolean Indicates whether the alert is currently enabled.
    -
    executionStatus (optional)
    -
    id (optional)
    String The identifier for the alert.
    -
    muteAll (optional)
    -
    mutedInstanceIds (optional)
    -
    name (optional)
    String The name of the alert.
    -
    notifyWhen (optional)
    -
    params (optional)
    -
    schedule (optional)
    -
    scheduledTaskId (optional)
    -
    tags (optional)
    -
    throttle (optional)
    -
    updatedAt (optional)
    -
    updatedBy (optional)
    String The identifier for the user that updated this alert most recently.
    +
    threshold (optional)
    +
    comparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    timeUnit (optional)
    +
    timeSize (optional)
    +
    warningThreshold (optional)
    +
    warningComparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    aggType (optional)
    +
    Enum:
    +
    custom
    +
    customMetric (optional)
    +
    equation (optional)
    +
    label (optional)
    -

    alert_response_properties_executionStatus - Up

    +

    custom_criterion_customMetric_inner - Up

    -
    lastExecutionDate (optional)
    Date format: date-time
    -
    status (optional)
    +
    name (optional)
    +
    aggType (optional)
    +
    Enum:
    +
    count
    +
    field (optional)
    +
    filter (optional)
    -

    alert_response_properties_schedule - Up

    +

    custom_criterion_customMetric_inner_oneOf - Up

    -
    interval (optional)
    +
    name (optional)
    +
    aggType (optional)
    +
    Enum:
    +
    avg
    sum
    max
    min
    cardinality
    +
    field (optional)
    -

    create_rule_request - Create rule request Up

    -
    The create rule API request body varies depending on the type of rule and actions.
    +

    custom_criterion_customMetric_inner_oneOf_1 - Up

    +
    -
    actions (optional)
    -
    consumer
    String The name of the application or feature that owns the rule. For example: alerts, apm, discover, infrastructure, logs, metrics, ml, monitoring, securitySolution, siem, stackAlerts, or uptime.
    -
    enabled (optional)
    Boolean Indicates whether you want to run the rule on an interval basis after it is created.
    -
    name
    String The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
    -
    notify_when (optional)
    -
    params
    map[String, oas_any_type_not_mapped] The parameters for the rule.
    -
    rule_type_id
    String The ID of the rule type that you want to call when the rule is scheduled to run. For example, .es-query, .index-threshold, logs.alert.document.count, monitoring_alert_cluster_health, siem.thresholdRule, or xpack.ml.anomaly_detection_alert.
    -
    schedule
    -
    tags (optional)
    array[String] The tags for the rule.
    -
    throttle (optional)
    String The throttle interval, which defines how often an alert generates repeated actions. It is applicable only if notify_when is set to onThrottleInterval. It is specified in seconds, minutes, hours, or days.
    +
    name (optional)
    +
    aggType (optional)
    +
    Enum:
    +
    count
    +
    filter (optional)
    @@ -3128,12 +4329,296 @@ Any modifications made to this file will be overwritten.
    timestamp (optional)
    Date format: date-time
    +
    +

    non_count_criterion - non count criterion Up

    +
    +
    +
    threshold (optional)
    +
    comparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    timeUnit (optional)
    +
    timeSize (optional)
    +
    warningThreshold (optional)
    +
    warningComparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    metric (optional)
    +
    aggType (optional)
    +
    Enum:
    +
    avg
    max
    min
    cardinality
    rate
    count
    sum
    p95
    p99
    custom
    +
    +

    notify_when - Up

    Indicates how often alerts generate actions. Valid values include: onActionGroupChange: Actions run when the alert status changes; onActiveAlert: Actions run when the alert becomes active and at each check interval while the rule conditions are met; onThrottleInterval: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met.
    +
    +

    params_property_apm_anomaly - Up

    +
    +
    +
    serviceName (optional)
    String The service name from APM
    +
    transactionType (optional)
    String The transaction type from APM
    +
    windowSize
    BigDecimal The window size
    +
    windowUnit
    String The window size unit
    +
    Enum:
    +
    m
    h
    d
    +
    environment
    String The environment from APM
    +
    anomalySeverityType
    String The anomaly threshold value
    +
    Enum:
    +
    critical
    major
    minor
    warning
    +
    +
    +
    +

    params_property_apm_error_count - Up

    +
    +
    +
    serviceName (optional)
    String The service name from APM
    +
    windowSize
    BigDecimal The window size
    +
    windowUnit
    String The window size unit
    +
    Enum:
    +
    m
    h
    d
    +
    environment
    String The environment from APM
    +
    threshold
    BigDecimal The error count threshold value
    +
    groupBy (optional)
    +
    Enum:
    + +
    errorGroupingKey (optional)
    +
    +
    +
    +

    params_property_apm_transaction_duration - Up

    +
    +
    +
    serviceName (optional)
    String The service name from APM
    +
    transactionType (optional)
    String The transaction type from APM
    +
    transactionName (optional)
    String The transaction name from APM
    +
    windowSize
    BigDecimal The window size
    +
    windowUnit
    String ç
    +
    Enum:
    +
    m
    h
    d
    +
    environment
    +
    threshold
    BigDecimal The latency threshold value
    +
    groupBy (optional)
    +
    Enum:
    + +
    aggregationType
    +
    Enum:
    +
    avg
    95th
    99th
    +
    +
    +
    +

    params_property_apm_transaction_error_rate - Up

    +
    +
    +
    serviceName (optional)
    String The service name from APM
    +
    transactionType (optional)
    String The transaction type from APM
    +
    transactionName (optional)
    String The transaction name from APM
    +
    windowSize
    BigDecimal The window size
    +
    windowUnit
    String The window size unit
    +
    Enum:
    +
    m
    h
    d
    +
    environment
    String The environment from APM
    +
    threshold
    BigDecimal The error rate threshold value
    +
    groupBy (optional)
    +
    Enum:
    + +
    +
    +
    +

    params_property_infra_inventory - Up

    +
    +
    +
    criteria (optional)
    +
    filterQuery (optional)
    +
    filterQueryText (optional)
    +
    nodeType (optional)
    +
    Enum:
    +
    host
    pod
    container
    awsEC2
    awsS3
    awsSQS
    awsRDS
    +
    sourceId (optional)
    +
    alertOnNoData (optional)
    +
    +
    +
    +

    params_property_infra_inventory_criteria_inner - Up

    +
    +
    +
    metric (optional)
    +
    Enum:
    +
    count
    cpu
    diskLatency
    load
    memory
    memoryTotal
    tx
    rx
    logRate
    diskIOReadBytes
    diskIOWriteBytes
    s3TotalRequests
    s3NumberOfObjects
    s3BucketSize
    s3DownloadBytes
    s3UploadBytes
    rdsConnections
    rdsQueriesExecuted
    rdsActiveTransactions
    rdsLatency
    sqsMessagesVisible
    sqsMessagesDelayed
    sqsMessagesSent
    sqsMessagesEmpty
    sqsOldestMessage
    custom
    +
    timeSize (optional)
    +
    timeUnit (optional)
    +
    Enum:
    +
    s
    m
    h
    d
    +
    sourceId (optional)
    +
    threshold (optional)
    +
    comparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    customMetric (optional)
    +
    warningThreshold (optional)
    +
    warningComparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    +
    +
    +

    params_property_infra_inventory_criteria_inner_customMetric - Up

    +
    +
    +
    type (optional)
    +
    Enum:
    +
    custom
    +
    field (optional)
    +
    aggregation (optional)
    +
    Enum:
    +
    avg
    max
    min
    rate
    +
    id (optional)
    +
    label (optional)
    +
    +
    +
    +

    params_property_infra_metric_threshold - Up

    +
    +
    +
    criteria (optional)
    +
    groupBy (optional)
    +
    filterQuery (optional)
    +
    sourceId (optional)
    +
    alertOnNoData (optional)
    +
    alertOnGroupDisappear (optional)
    +
    +
    +
    +

    params_property_infra_metric_threshold_criteria_inner - Up

    +
    +
    +
    threshold (optional)
    +
    comparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    timeUnit (optional)
    +
    timeSize (optional)
    +
    warningThreshold (optional)
    +
    warningComparator (optional)
    +
    Enum:
    +
    <
    <=
    >
    >=
    between
    outside
    +
    metric (optional)
    +
    aggType (optional)
    +
    Enum:
    +
    custom
    +
    customMetric (optional)
    +
    equation (optional)
    +
    label (optional)
    +
    +
    +
    +

    params_property_log_threshold - Up

    +
    +
    +
    criteria (optional)
    +
    count
    +
    timeSize
    +
    timeUnit
    +
    Enum:
    +
    s
    m
    h
    d
    +
    logView
    +
    groupBy (optional)
    +
    +
    +
    +

    params_property_slo_burn_rate - Up

    +
    +
    +
    sloId (optional)
    String The SLO identifier used by the rule
    +
    burnRateThreshold (optional)
    BigDecimal The burn rate threshold used to trigger the alert
    +
    maxBurnRateThreshold (optional)
    BigDecimal The maximum burn rate threshold value defined by the SLO error budget
    +
    longWindow (optional)
    +
    shortWindow (optional)
    +
    +
    +
    +

    params_property_slo_burn_rate_longWindow - Up

    +
    The duration of the long window used to compute the burn rate
    +
    +
    value (optional)
    BigDecimal The duration value
    +
    unit (optional)
    String The duration unit
    +
    +
    +
    +

    params_property_slo_burn_rate_shortWindow - Up

    +
    The duration of the short window used to compute the burn rate
    +
    +
    value (optional)
    BigDecimal The duration value
    +
    unit (optional)
    String The duration unit
    +
    +
    +
    +

    params_property_synthetics_monitor_status - Up

    +
    +
    +
    availability (optional)
    +
    filters (optional)
    +
    locations (optional)
    +
    numTimes
    +
    search (optional)
    +
    shouldCheckStatus
    +
    shouldCheckAvailability
    +
    timerangeCount (optional)
    +
    timerangeUnit (optional)
    +
    timerange (optional)
    +
    version (optional)
    +
    isAutoGenerated (optional)
    +
    +
    +
    +

    params_property_synthetics_monitor_status_availability - Up

    +
    +
    +
    range (optional)
    +
    rangeUnit (optional)
    +
    threshold (optional)
    +
    +
    +
    +

    params_property_synthetics_monitor_status_filters - Up

    +
    +
    +
    monitorPeriodtype (optional)
    +
    observerPeriodgeoPeriodname (optional)
    +
    tags (optional)
    +
    urlPeriodport (optional)
    +
    +
    +
    +

    params_property_synthetics_monitor_status_filters_oneOf - Up

    +
    +
    +
    monitorPeriodtype (optional)
    +
    observerPeriodgeoPeriodname (optional)
    +
    tags (optional)
    +
    urlPeriodport (optional)
    +
    +
    + +
    +

    params_property_synthetics_uptime_tls - Up

    +
    +
    +
    search (optional)
    +
    certExpirationThreshold (optional)
    +
    certAgeThreshold (optional)
    +
    +

    rule_response_properties - Rule response properties Up

    diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 954cf3c69d308..31d7fe690cfe3 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -674,7 +674,7 @@ Elastic. |{kib-repo}blob/{branch}/x-pack/plugins/profiling/README.md[profiling] -|undefined +|Universal Profiling provides fleet-wide, whole-system, continuous profiling with zero instrumentation. Get a comprehensive understanding of what lines of code are consuming compute resources throughout your entire fleet by visualizing your data in Kibana using the flamegraph, stacktraces, and top functions views. |{kib-repo}blob/{branch}/x-pack/plugins/remote_clusters/README.md[remoteClusters] diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx new file mode 100644 index 0000000000000..08ea2bcd5ba58 --- /dev/null +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.test.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { EuiHeader } from '@elastic/eui'; +import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; +import { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; +import * as Rx from 'rxjs'; +import { ProjectHeader, Props as ProjectHeaderProps } from './header'; + +const mockApplication = applicationServiceMock.createInternalStartContract(); + +describe('Header', () => { + const mockProps: Omit = { + application: mockApplication, + breadcrumbs$: Rx.of([]), + actionMenu$: Rx.of(undefined), + kibanaDocLink: 'app/help/doclinks', + globalHelpExtensionMenuLinks$: Rx.of([]), + helpExtension$: Rx.of(undefined), + helpSupportUrl$: Rx.of('app/help'), + homeHref$: Rx.of('app/home'), + kibanaVersion: '8.9', + loadingCount$: Rx.of(0), + navControlsLeft$: Rx.of([]), + navControlsCenter$: Rx.of([]), + navControlsRight$: Rx.of([]), + prependBasePath: (str) => `hello/world/${str}`, + }; + + it('renders', async () => { + render( + + Hello, world! + + ); + + expect(await screen.findByTestId('toggleNavButton')).toBeVisible(); + expect(await screen.findByText('Hello, world!')).toBeVisible(); + }); + + it('can collapse and uncollapse', async () => { + render( + + Hello, goodbye! + + ); + + expect(await screen.findByTestId('toggleNavButton')).toBeVisible(); + expect(await screen.findByText('Hello, goodbye!')).toBeVisible(); // title is shown + + const toggleNav = async () => { + fireEvent.click(await screen.findByTestId('toggleNavButton')); // click + + expect(screen.queryAllByText('Hello, goodbye!')).toHaveLength(0); // title is not shown + + fireEvent.click(await screen.findByTestId('toggleNavButton')); // click again + + expect(await screen.findByText('Hello, goodbye!')).toBeVisible(); // title is shown + }; + + await toggleNav(); + await toggleNav(); + await toggleNav(); + }); +}); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx index 40237da8bcc71..1c36084a34cef 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx @@ -84,7 +84,7 @@ const headerStrings = { }, }; -interface Props { +export interface Props { breadcrumbs$: Observable; actionMenu$: Observable; kibanaDocLink: string; @@ -169,18 +169,6 @@ export const ProjectHeader = ({ const toggleCollapsibleNavRef = createRef void }>(); const headerActionMenuMounter = useHeaderActionMenuMounter(observables.actionMenu$); - const handleCloseNav = useCallback(() => { - setIsOpen(false); - if (toggleCollapsibleNavRef.current) { - toggleCollapsibleNavRef.current.focus(); - } - }, [setIsOpen, toggleCollapsibleNavRef]); - - const handleToggleNavButtonClick = useCallback( - () => setIsOpen((prevIsOpen) => !prevIsOpen), - [setIsOpen] - ); - return ( <> @@ -190,12 +178,17 @@ export const ProjectHeader = ({ { + setIsOpen(false); + if (toggleCollapsibleNavRef.current) { + toggleCollapsibleNavRef.current.focus(); + } + }} button={ setIsOpen(!isOpen)} aria-expanded={isOpen!} aria-pressed={isOpen!} aria-controls={navId} diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts index 51f7f29e9683a..860284a892fb1 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts @@ -9,6 +9,7 @@ import { Subject, Observable, firstValueFrom, of } from 'rxjs'; import { filter, take, switchMap } from 'rxjs/operators'; import type { Logger } from '@kbn/logging'; +import { stripVersionQualifier } from '@kbn/std'; import type { ServiceStatus } from '@kbn/core-status-common'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; import type { DocLinksServiceStart } from '@kbn/core-doc-links-server'; @@ -106,9 +107,7 @@ export class SavedObjectsService constructor(private readonly coreContext: CoreContext) { this.logger = coreContext.logger.get('savedobjects-service'); - this.kibanaVersion = SavedObjectsService.stripVersionQualifier( - this.coreContext.env.packageInfo.version - ); + this.kibanaVersion = stripVersionQualifier(this.coreContext.env.packageInfo.version); } public async setup(setupDeps: SavedObjectsSetupDeps): Promise { @@ -384,12 +383,4 @@ export class SavedObjectsService nodeRoles: nodeInfo.roles, }); } - - /** - * Coerce a semver-like string (x.y.z-SNAPSHOT) or prerelease version (x.y.z-alpha) - * to regular semver (x.y.z). - */ - private static stripVersionQualifier(version: string) { - return version.split('-')[0]; - } } diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/tsconfig.json b/packages/core/saved-objects/core-saved-objects-server-internal/tsconfig.json index 7f6d935a488b7..bd5c290172794 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/tsconfig.json +++ b/packages/core/saved-objects/core-saved-objects-server-internal/tsconfig.json @@ -46,6 +46,7 @@ "@kbn/utils", "@kbn/core-http-router-server-internal", "@kbn/logging-mocks", + "@kbn/std", ], "exclude": [ "target/**/*", diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.test.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.test.ts index bc6e427cd2a57..ba7fd1b682f27 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.test.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.test.ts @@ -46,6 +46,59 @@ describe('getUpgradeableConfig', () => { expect(result).toEqual(savedConfig); }); + it('uses the latest config when multiple are found', async () => { + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.find.mockResolvedValue({ + saved_objects: [ + { id: '7.2.0', attributes: 'foo' }, + { id: '7.3.0', attributes: 'foo' }, + ], + } as SavedObjectsFindResponse); + + const result = await getUpgradeableConfig({ + savedObjectsClient, + version: '7.5.0', + type: 'config', + }); + expect(result!.id).toBe('7.3.0'); + }); + + it('uses the latest config when multiple are found with rc qualifier', async () => { + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.find.mockResolvedValue({ + saved_objects: [ + { id: '7.2.0', attributes: 'foo' }, + { id: '7.3.0', attributes: 'foo' }, + { id: '7.5.0-rc1', attributes: 'foo' }, + ], + } as SavedObjectsFindResponse); + + const result = await getUpgradeableConfig({ + savedObjectsClient, + version: '7.5.0', + type: 'config', + }); + expect(result!.id).toBe('7.5.0-rc1'); + }); + + it('ignores documents with malformed ids', async () => { + const savedObjectsClient = savedObjectsClientMock.create(); + savedObjectsClient.find.mockResolvedValue({ + saved_objects: [ + { id: 'not-a-semver', attributes: 'foo' }, + { id: '7.2.0', attributes: 'foo' }, + { id: '7.3.0', attributes: 'foo' }, + ], + } as SavedObjectsFindResponse); + + const result = await getUpgradeableConfig({ + savedObjectsClient, + version: '7.5.0', + type: 'config', + }); + expect(result!.id).toBe('7.3.0'); + }); + it('finds saved config with RC version === Kibana version', async () => { const savedConfig = { id: '7.5.0-rc1', attributes: 'foo' }; const savedObjectsClient = savedObjectsClientMock.create(); diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.ts index 18479db1ebd28..ad7572095796e 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/create_or_upgrade_saved_config/get_upgradeable_config.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ -import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import Semver from 'semver'; +import type { + SavedObjectsClientContract, + SavedObjectsFindResult, +} from '@kbn/core-saved-objects-api-server'; import type { ConfigAttributes } from '../saved_objects'; import { isConfigVersionUpgradeable } from './is_config_version_upgradeable'; @@ -47,11 +51,26 @@ export async function getUpgradeableConfig({ }); // try to find a config that we can upgrade - const findResult = savedConfigs.find((savedConfig) => + const matchingResults = savedConfigs.filter((savedConfig) => isConfigVersionUpgradeable(savedConfig.id, version) ); - if (findResult) { - return { id: findResult.id, attributes: findResult.attributes }; + const mostRecentConfig = getMostRecentConfig(matchingResults); + if (mostRecentConfig) { + return { id: mostRecentConfig.id, attributes: mostRecentConfig.attributes }; } return null; } + +const getMostRecentConfig = ( + results: Array> +): SavedObjectsFindResult | undefined => { + return results.reduce | undefined>( + (mostRecent, current) => { + if (!mostRecent) { + return current; + } + return Semver.gt(mostRecent.id, current.id) ? mostRecent : current; + }, + undefined + ); +}; diff --git a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts index e4dabb6b50f46..473e7569e2179 100644 --- a/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts +++ b/packages/core/ui-settings/core-ui-settings-server-internal/src/ui_settings_service.ts @@ -10,6 +10,7 @@ import { firstValueFrom, Observable } from 'rxjs'; import { mapToObject } from '@kbn/std'; import type { Logger } from '@kbn/logging'; +import { stripVersionQualifier } from '@kbn/std'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; import type { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; @@ -32,6 +33,7 @@ export interface SetupDeps { http: InternalHttpServiceSetup; savedObjects: InternalSavedObjectsServiceSetup; } + type ClientType = T extends 'global' ? UiSettingsGlobalClient : T extends 'namespace' @@ -109,7 +111,7 @@ export class UiSettingsService const isNamespaceScope = scope === 'namespace'; const options = { type: (isNamespaceScope ? 'config' : 'config-global') as 'config' | 'config-global', - id: version, + id: stripVersionQualifier(version), buildNum, savedObjectsClient, defaults: isNamespaceScope diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts index 7c0041ca46221..a63eca8c9215d 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts @@ -6,12 +6,17 @@ * Side Public License, v 1. */ -import type { deleteSavedObjectIndices } from './kibana_index'; +import type { cleanSavedObjectIndices, deleteSavedObjectIndices } from './kibana_index'; -export const mockdeleteSavedObjectIndices = jest.fn() as jest.MockedFunction< +export const mockCleanSavedObjectIndices = jest.fn() as jest.MockedFunction< + typeof cleanSavedObjectIndices +>; + +export const mockDeleteSavedObjectIndices = jest.fn() as jest.MockedFunction< typeof deleteSavedObjectIndices >; jest.mock('./kibana_index', () => ({ - deleteSavedObjectIndices: mockdeleteSavedObjectIndices, + cleanSavedObjectIndices: mockCleanSavedObjectIndices, + deleteSavedObjectIndices: mockDeleteSavedObjectIndices, })); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts index 9e1caf53eb06b..3940146cbfe85 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts @@ -6,7 +6,10 @@ * Side Public License, v 1. */ -import { mockdeleteSavedObjectIndices } from './create_index_stream.test.mock'; +import { + mockCleanSavedObjectIndices, + mockDeleteSavedObjectIndices, +} from './create_index_stream.test.mock'; import sinon from 'sinon'; import Chance from 'chance'; @@ -28,7 +31,8 @@ const chance = new Chance(); const log = createStubLogger(); beforeEach(() => { - mockdeleteSavedObjectIndices.mockClear(); + mockCleanSavedObjectIndices.mockClear(); + mockDeleteSavedObjectIndices.mockClear(); }); describe('esArchiver: createCreateIndexStream()', () => { @@ -199,25 +203,25 @@ describe('esArchiver: createCreateIndexStream()', () => { it('does not delete Kibana indices for indexes that do not start with .kibana', async () => { await doTest('.foo'); - expect(mockdeleteSavedObjectIndices).not.toHaveBeenCalled(); + expect(mockDeleteSavedObjectIndices).not.toHaveBeenCalled(); }); it('deletes Kibana indices at most once for indices that start with .kibana', async () => { // If we are loading the main Kibana index, we should delete all Kibana indices for backwards compatibility reasons. await doTest('.kibana_7.16.0_001', '.kibana_task_manager_7.16.0_001'); - expect(mockdeleteSavedObjectIndices).toHaveBeenCalledTimes(1); - expect(mockdeleteSavedObjectIndices).toHaveBeenCalledWith( - expect.not.objectContaining({ onlyTaskManager: true }) + expect(mockDeleteSavedObjectIndices).toHaveBeenCalledTimes(1); + expect(mockDeleteSavedObjectIndices).toHaveBeenCalledWith( + expect.not.objectContaining({ index: '.kibana_task_manager_7.16.0_001' }) ); }); - it('deletes Kibana task manager index at most once, using onlyTaskManager: true', async () => { + it('deletes Kibana task manager index at most once', async () => { // If we are loading the Kibana task manager index, we should only delete that index, not any other Kibana indices. await doTest('.kibana_task_manager_7.16.0_001', '.kibana_task_manager_7.16.0_002'); - expect(mockdeleteSavedObjectIndices).toHaveBeenCalledTimes(1); - expect(mockdeleteSavedObjectIndices).toHaveBeenCalledWith( + expect(mockDeleteSavedObjectIndices).toHaveBeenCalledTimes(1); + expect(mockDeleteSavedObjectIndices).toHaveBeenCalledWith( expect.objectContaining({ onlyTaskManager: true }) ); }); @@ -227,18 +231,63 @@ describe('esArchiver: createCreateIndexStream()', () => { // So, we first delete only the Kibana task manager indices, then we wind up deleting all Kibana indices. await doTest('.kibana_task_manager_7.16.0_001', '.kibana_7.16.0_001'); - expect(mockdeleteSavedObjectIndices).toHaveBeenCalledTimes(2); - expect(mockdeleteSavedObjectIndices).toHaveBeenNthCalledWith( + expect(mockDeleteSavedObjectIndices).toHaveBeenCalledTimes(2); + expect(mockDeleteSavedObjectIndices).toHaveBeenNthCalledWith( 1, expect.objectContaining({ onlyTaskManager: true }) ); - expect(mockdeleteSavedObjectIndices).toHaveBeenNthCalledWith( + expect(mockDeleteSavedObjectIndices).toHaveBeenNthCalledWith( 2, - expect.not.objectContaining({ onlyTaskManager: true }) + expect.not.objectContaining({ index: expect.any(String) }) ); }); }); + describe('saved object cleanup', () => { + describe('when saved object documents are found', () => { + it('cleans the corresponding saved object indices', async () => { + const client = createStubClient(); + const stats = createStubStats(); + await createPromiseFromStreams([ + createListStream([ + createStubDocRecord('.kibana_task_manager', 1), + createStubDocRecord('.kibana_alerting_cases', 2), + createStubDocRecord('.kibana', 3), + ]), + createCreateIndexStream({ client, stats, log }), + ]); + + expect(mockCleanSavedObjectIndices).toHaveBeenCalledTimes(2); + + expect(mockCleanSavedObjectIndices).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ index: '.kibana_task_manager' }) + ); + expect(mockCleanSavedObjectIndices).toHaveBeenNthCalledWith( + 2, + expect.not.objectContaining({ index: expect.any(String) }) + ); + }); + }); + + describe('when saved object documents are not found', () => { + it('does not clean any indices', async () => { + const client = createStubClient(); + const stats = createStubStats(); + await createPromiseFromStreams([ + createListStream([ + createStubDocRecord('.foo', 1), + createStubDocRecord('.bar', 2), + createStubDocRecord('.baz', 3), + ]), + createCreateIndexStream({ client, stats, log }), + ]); + + expect(mockCleanSavedObjectIndices).not.toHaveBeenCalled(); + }); + }); + }); + describe('docsOnly = true', () => { it('passes through "hit" records without attempting to create indices', async () => { const client = createStubClient(); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts index 5b6245407f23f..154c471a07def 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts @@ -19,7 +19,7 @@ import { TASK_MANAGER_SAVED_OBJECT_INDEX, } from '@kbn/core-saved-objects-server'; import { Stats } from '../stats'; -import { deleteSavedObjectIndices } from './kibana_index'; +import { cleanSavedObjectIndices, deleteSavedObjectIndices } from './kibana_index'; import { deleteIndex } from './delete_index'; import { deleteDataStream } from './delete_data_stream'; import { ES_CLIENT_HEADERS } from '../../client_headers'; @@ -50,14 +50,36 @@ export function createCreateIndexStream({ // If we're trying to import Kibana index docs, we need to ensure that // previous indices are removed so we're starting w/ a clean slate for // migrations. This only needs to be done once per archive load operation. - let kibanaIndexAlreadyDeleted = false; + let kibanaIndicesAlreadyDeleted = false; let kibanaTaskManagerIndexAlreadyDeleted = false; + // if we detect saved object documents defined in the data.json, we will cleanup their indices + let kibanaIndicesAlreadyCleaned = false; + let kibanaTaskManagerIndexAlreadyCleaned = false; + async function handleDoc(stream: Readable, record: DocRecord) { - if (skipDocsFromIndices.has(record.value.index)) { + const index = record.value.index; + + if (skipDocsFromIndices.has(index)) { return; } + if (!skipExisting) { + if (index?.startsWith(TASK_MANAGER_SAVED_OBJECT_INDEX)) { + if (!kibanaTaskManagerIndexAlreadyDeleted && !kibanaTaskManagerIndexAlreadyCleaned) { + await cleanSavedObjectIndices({ client, stats, log, index }); + kibanaTaskManagerIndexAlreadyCleaned = true; + log.debug(`Cleaned saved object index [${index}]`); + } + } else if (index?.startsWith(MAIN_SAVED_OBJECT_INDEX)) { + if (!kibanaIndicesAlreadyDeleted && !kibanaIndicesAlreadyCleaned) { + await cleanSavedObjectIndices({ client, stats, log }); + kibanaIndicesAlreadyCleaned = kibanaTaskManagerIndexAlreadyCleaned = true; + log.debug(`Cleaned all saved object indices`); + } + } + } + stream.push(record); } @@ -109,12 +131,14 @@ export function createCreateIndexStream({ async function attemptToCreate(attemptNumber = 1) { try { - if (isKibana && !kibanaIndexAlreadyDeleted) { + if (isKibana && !kibanaIndicesAlreadyDeleted) { await deleteSavedObjectIndices({ client, stats, log }); // delete all .kibana* indices - kibanaIndexAlreadyDeleted = kibanaTaskManagerIndexAlreadyDeleted = true; + kibanaIndicesAlreadyDeleted = kibanaTaskManagerIndexAlreadyDeleted = true; + log.debug(`Deleted all saved object indices`); } else if (isKibanaTaskManager && !kibanaTaskManagerIndexAlreadyDeleted) { await deleteSavedObjectIndices({ client, stats, onlyTaskManager: true, log }); // delete only .kibana_task_manager* indices kibanaTaskManagerIndexAlreadyDeleted = true; + log.debug(`Deleted saved object index [${index}]`); } await client.indices.create( @@ -137,7 +161,11 @@ export function createCreateIndexStream({ err?.body?.error?.reason?.includes('index exists with the same name as the alias') && attemptNumber < 3 ) { - kibanaIndexAlreadyDeleted = false; + kibanaTaskManagerIndexAlreadyDeleted = false; + if (isKibana) { + kibanaIndicesAlreadyDeleted = false; + } + const aliasStr = inspect(aliases); log.info( `failed to create aliases [${aliasStr}] because ES indicated an index/alias already exists, trying again` diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.test.ts index 4917deab542d4..72cab1b506332 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.test.ts @@ -6,6 +6,8 @@ * Side Public License, v 1. */ +import { mockCleanSavedObjectIndices } from './create_index_stream.test.mock'; + import sinon from 'sinon'; import { createListStream, createPromiseFromStreams } from '@kbn/utils'; @@ -22,6 +24,10 @@ import { const log = createStubLogger(); +beforeEach(() => { + mockCleanSavedObjectIndices.mockClear(); +}); + describe('esArchiver: createDeleteIndexStream()', () => { it('deletes the index without checking if it exists', async () => { const stats = createStubStats(); diff --git a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts index f9b04b447f124..30ec3a4d58801 100644 --- a/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/delete_index_stream.ts @@ -10,13 +10,20 @@ import { Transform } from 'stream'; import type { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/tooling-log'; -import { MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import { + MAIN_SAVED_OBJECT_INDEX, + TASK_MANAGER_SAVED_OBJECT_INDEX, +} from '@kbn/core-saved-objects-server'; import { Stats } from '../stats'; import { deleteIndex } from './delete_index'; import { cleanSavedObjectIndices } from './kibana_index'; import { deleteDataStream } from './delete_data_stream'; export function createDeleteIndexStream(client: Client, stats: Stats, log: ToolingLog) { + // if we detect saved object documents defined in the data.json, we will cleanup their indices + let kibanaIndicesAlreadyCleaned = false; + let kibanaTaskManagerIndexAlreadyCleaned = false; + return new Transform({ readableObjectMode: true, writableObjectMode: true, @@ -29,8 +36,18 @@ export function createDeleteIndexStream(client: Client, stats: Stats, log: Tooli if (record.type === 'index') { const { index } = record.value; - if (index.startsWith(MAIN_SAVED_OBJECT_INDEX)) { - await cleanSavedObjectIndices({ client, stats, log }); + if (index.startsWith(TASK_MANAGER_SAVED_OBJECT_INDEX)) { + if (!kibanaTaskManagerIndexAlreadyCleaned) { + await cleanSavedObjectIndices({ client, stats, index, log }); + kibanaTaskManagerIndexAlreadyCleaned = true; + log.debug(`Cleaned saved object index [${index}]`); + } + } else if (index.startsWith(MAIN_SAVED_OBJECT_INDEX)) { + if (!kibanaIndicesAlreadyCleaned) { + await cleanSavedObjectIndices({ client, stats, log }); + kibanaIndicesAlreadyCleaned = kibanaTaskManagerIndexAlreadyCleaned = true; + log.debug(`Cleaned all saved object indices`); + } } else { await deleteIndex({ client, stats, log, index }); } diff --git a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts index d45f9e67737a2..80ce9d3aa41db 100644 --- a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts @@ -50,7 +50,6 @@ export async function deleteSavedObjectIndices({ headers: ES_CLIENT_HEADERS, } ); - await deleteIndex({ client, stats, @@ -111,15 +110,17 @@ export async function cleanSavedObjectIndices({ client, stats, log, + index = ALL_SAVED_OBJECT_INDICES, }: { client: Client; stats: Stats; log: ToolingLog; + index?: string | string[]; }) { while (true) { const resp = await client.deleteByQuery( { - index: ALL_SAVED_OBJECT_INDICES, + index, body: { query: { bool: { diff --git a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap index 2f57d74cf995e..462700420738f 100644 --- a/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap +++ b/packages/kbn-guided-onboarding/src/components/landing_page/__snapshots__/guide_cards.test.tsx.snap @@ -219,6 +219,33 @@ exports[`guide cards snapshots should render all cards 1`] = ` size="m" /> + + + + { it('should post the stringified given attributes', async () => { await createQuery(savedQueryAttributes); expect(http.post).toBeCalled(); - expect(http.post).toHaveBeenCalledWith('/api/saved_query/_create', { + expect(http.post).toHaveBeenCalledWith(`${SAVED_QUERY_BASE_URL}/_create`, { body: '{"title":"foo","description":"bar","query":{"language":"kuery","query":"response:200"},"filters":[]}', + version, }); }); }); @@ -53,8 +57,9 @@ describe('saved query service', () => { it('should put the ID & stringified given attributes', async () => { await updateQuery('foo', savedQueryAttributes); expect(http.put).toBeCalled(); - expect(http.put).toHaveBeenCalledWith('/api/saved_query/foo', { + expect(http.put).toHaveBeenCalledWith(`${SAVED_QUERY_BASE_URL}/foo`, { body: '{"title":"foo","description":"bar","query":{"language":"kuery","query":"response:200"},"filters":[]}', + version, }); }); }); @@ -67,7 +72,7 @@ describe('saved query service', () => { }); const result = await getAllSavedQueries(); expect(http.post).toBeCalled(); - expect(http.post).toHaveBeenCalledWith('/api/saved_query/_all'); + expect(http.post).toHaveBeenCalledWith(`${SAVED_QUERY_BASE_URL}/_all`, { version }); expect(result).toEqual([{ attributes: savedQueryAttributes }]); }); }); @@ -80,8 +85,9 @@ describe('saved query service', () => { }); const result = await findSavedQueries(); expect(http.post).toBeCalled(); - expect(http.post).toHaveBeenCalledWith('/api/saved_query/_find', { + expect(http.post).toHaveBeenCalledWith(`${SAVED_QUERY_BASE_URL}/_find`, { body: '{"page":1,"perPage":50,"search":""}', + version, }); expect(result).toEqual({ queries: [{ attributes: savedQueryAttributes }], @@ -94,7 +100,7 @@ describe('saved query service', () => { it('should get the given ID', async () => { await getSavedQuery('my_id'); expect(http.get).toBeCalled(); - expect(http.get).toHaveBeenCalledWith('/api/saved_query/my_id'); + expect(http.get).toHaveBeenCalledWith(`${SAVED_QUERY_BASE_URL}/my_id`, { version }); }); }); @@ -102,7 +108,7 @@ describe('saved query service', () => { it('should delete the given ID', async () => { await deleteSavedQuery('my_id'); expect(http.delete).toBeCalled(); - expect(http.delete).toHaveBeenCalledWith('/api/saved_query/my_id'); + expect(http.delete).toHaveBeenCalledWith(`${SAVED_QUERY_BASE_URL}/my_id`, { version }); }); }); @@ -110,7 +116,7 @@ describe('saved query service', () => { it('should get the total', async () => { await getSavedQueryCount(); expect(http.get).toBeCalled(); - expect(http.get).toHaveBeenCalledWith('/api/saved_query/_count'); + expect(http.get).toHaveBeenCalledWith(`${SAVED_QUERY_BASE_URL}/_count`, { version }); }); }); }); diff --git a/src/plugins/data/public/query/saved_query/saved_query_service.ts b/src/plugins/data/public/query/saved_query/saved_query_service.ts index fd643a33dd103..09afd75470dd0 100644 --- a/src/plugins/data/public/query/saved_query/saved_query_service.ts +++ b/src/plugins/data/public/query/saved_query/saved_query_service.ts @@ -9,18 +9,23 @@ import { HttpStart } from '@kbn/core/public'; import { SavedQuery } from './types'; import type { SavedQueryAttributes } from '../../../common'; +import { SAVED_QUERY_BASE_URL } from '../../../common/constants'; + +const version = '1'; export const createSavedQueryService = (http: HttpStart) => { const createQuery = async (attributes: SavedQueryAttributes, { overwrite = false } = {}) => { - const savedQuery = await http.post('/api/saved_query/_create', { + const savedQuery = await http.post(`${SAVED_QUERY_BASE_URL}/_create`, { body: JSON.stringify(attributes), + version, }); return savedQuery; }; const updateQuery = async (id: string, attributes: SavedQueryAttributes) => { - const savedQuery = await http.put(`/api/saved_query/${id}`, { + const savedQuery = await http.put(`${SAVED_QUERY_BASE_URL}/${id}`, { body: JSON.stringify(attributes), + version, }); return savedQuery; }; @@ -28,7 +33,8 @@ export const createSavedQueryService = (http: HttpStart) => { // we have to tell the saved objects client how many to fetch, otherwise it defaults to fetching 20 per page const getAllSavedQueries = async (): Promise => { const { savedQueries } = await http.post<{ savedQueries: SavedQuery[] }>( - '/api/saved_query/_all' + `${SAVED_QUERY_BASE_URL}/_all`, + { version } ); return savedQueries; }; @@ -42,23 +48,24 @@ export const createSavedQueryService = (http: HttpStart) => { const { total, savedQueries: queries } = await http.post<{ savedQueries: SavedQuery[]; total: number; - }>('/api/saved_query/_find', { + }>(`${SAVED_QUERY_BASE_URL}/_find`, { body: JSON.stringify({ page, perPage, search }), + version, }); return { total, queries }; }; const getSavedQuery = (id: string): Promise => { - return http.get(`/api/saved_query/${id}`); + return http.get(`${SAVED_QUERY_BASE_URL}/${id}`, { version }); }; const deleteSavedQuery = (id: string) => { - return http.delete<{}>(`/api/saved_query/${id}`); + return http.delete<{}>(`${SAVED_QUERY_BASE_URL}/${id}`, { version }); }; const getSavedQueryCount = async (): Promise => { - return http.get('/api/saved_query/_count'); + return http.get(`${SAVED_QUERY_BASE_URL}/_count`, { version }); }; return { diff --git a/src/plugins/data/server/query/route_types.ts b/src/plugins/data/server/query/route_types.ts new file mode 100644 index 0000000000000..656d52dad9fa7 --- /dev/null +++ b/src/plugins/data/server/query/route_types.ts @@ -0,0 +1,129 @@ +/* + * Copyright 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 { SerializableRecord } from '@kbn/utility-types'; + +/* + * These types are used to define the shape of the response from the saved query API + * separate but similar to other types to draw attention to REST api return changes + */ + +interface MatchAllFilterMetaRestResponse extends FilterMetaRestResponse, SerializableRecord { + field: string; + formattedValue: string; +} + +type PhrasesFilterMetaRestResponse = FilterMetaRestResponse & { + params: PhraseFilterValue[]; // The unformatted values + field?: string; +}; + +interface RangeFilterParamsRestResponse extends SerializableRecord { + from?: number | string; + to?: number | string; + gt?: number | string; + lt?: number | string; + gte?: number | string; + lte?: number | string; + format?: string; +} + +type RangeFilterMetaRestResponse = FilterMetaRestResponse & { + params?: RangeFilterParamsRestResponse; + field?: string; + formattedValue?: string; + type: 'range'; +}; + +type PhraseFilterValue = string | number | boolean; + +interface PhraseFilterMetaParamsRestResponse extends SerializableRecord { + query: PhraseFilterValue; // The unformatted value +} + +type PhraseFilterMetaRestResponse = FilterMetaRestResponse & { + params?: PhraseFilterMetaParamsRestResponse; + field?: string; + index?: string; +}; + +type FilterMetaParamsRestResponse = + | FilterRestResponse + | FilterRestResponse[] + | RangeFilterMetaRestResponse + | RangeFilterParamsRestResponse + | PhraseFilterMetaRestResponse + | PhraseFilterMetaParamsRestResponse + | PhrasesFilterMetaRestResponse + | MatchAllFilterMetaRestResponse + | string + | string[] + | boolean + | boolean[] + | number + | number[]; + +interface QueryRestResponse { + query: string | { [key: string]: any }; + language: string; +} + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type FilterMetaRestResponse = { + alias?: string | null; + disabled?: boolean; + negate?: boolean; + // controlledBy is there to identify who owns the filter + controlledBy?: string; + // allows grouping of filters + group?: string; + // index and type are optional only because when you create a new filter, there are no defaults + index?: string; + isMultiIndex?: boolean; + type?: string; + key?: string; + params?: FilterMetaParamsRestResponse; + value?: string; +}; + +type FilterStateStoreRestResponse = 'appState' | 'globalState'; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type FilterRestResponse = { + $state?: { + store: FilterStateStoreRestResponse; + }; + meta: FilterMetaRestResponse; + query?: Record; +}; + +interface RefreshIntervalRestResponse { + pause: boolean; + value: number; +} + +interface TimeRangeRestResponse { + from: string; + to: string; + mode?: 'absolute' | 'relative'; +} + +type SavedQueryTimeFilterRestResponse = TimeRangeRestResponse & { + refreshInterval: RefreshIntervalRestResponse; +}; + +export interface SavedQueryRestResponse { + id: string; + attributes: { + filters: FilterRestResponse[]; + title: string; + description: string; + query: QueryRestResponse; + timefilter?: SavedQueryTimeFilterRestResponse | undefined; + }; +} diff --git a/src/plugins/data/server/query/routes.ts b/src/plugins/data/server/query/routes.ts index 16f5d8f9955a7..a092a32d321a5 100644 --- a/src/plugins/data/server/query/routes.ts +++ b/src/plugins/data/server/query/routes.ts @@ -9,8 +9,9 @@ import { schema } from '@kbn/config-schema'; import { CoreSetup } from '@kbn/core/server'; import { SavedQueryRouteHandlerContext } from './route_handler_context'; +import { SavedQueryRestResponse } from './route_types'; +import { SAVED_QUERY_BASE_URL } from '../../common/constants'; -const SAVED_QUERY_PATH = '/api/saved_query'; const SAVED_QUERY_ID_CONFIG = schema.object({ id: schema.string(), }); @@ -25,20 +26,35 @@ const SAVED_QUERY_ATTRS_CONFIG = schema.object({ timefilter: schema.maybe(schema.any()), }); +const savedQueryResponseSchema = schema.object({ + id: schema.string(), + attributes: SAVED_QUERY_ATTRS_CONFIG, +}); + +const access = 'internal'; +const version = '1'; + export function registerSavedQueryRoutes({ http }: CoreSetup): void { const router = http.createRouter(); - router.post( + router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_create`, access }).addVersion( { - path: `${SAVED_QUERY_PATH}/_create`, + version, validate: { - body: SAVED_QUERY_ATTRS_CONFIG, + request: { + body: SAVED_QUERY_ATTRS_CONFIG, + }, + response: { + 200: { + body: savedQueryResponseSchema, + }, + }, }, }, async (context, request, response) => { try { const savedQuery = await context.savedQuery; - const body = await savedQuery.create(request.body); + const body: SavedQueryRestResponse = await savedQuery.create(request.body); return response.ok({ body }); } catch (e) { // TODO: Handle properly @@ -47,19 +63,26 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void { } ); - router.put( + router.versioned.put({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion( { - path: `${SAVED_QUERY_PATH}/{id}`, + version, validate: { - params: SAVED_QUERY_ID_CONFIG, - body: SAVED_QUERY_ATTRS_CONFIG, + request: { + params: SAVED_QUERY_ID_CONFIG, + body: SAVED_QUERY_ATTRS_CONFIG, + }, + response: { + 200: { + body: savedQueryResponseSchema, + }, + }, }, }, async (context, request, response) => { const { id } = request.params; try { const savedQuery = await context.savedQuery; - const body = await savedQuery.update(id, request.body); + const body: SavedQueryRestResponse = await savedQuery.update(id, request.body); return response.ok({ body }); } catch (e) { // TODO: Handle properly @@ -68,18 +91,25 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void { } ); - router.get( + router.versioned.get({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion( { - path: `${SAVED_QUERY_PATH}/{id}`, + version, validate: { - params: SAVED_QUERY_ID_CONFIG, + request: { + params: SAVED_QUERY_ID_CONFIG, + }, + response: { + 200: { + body: savedQueryResponseSchema, + }, + }, }, }, async (context, request, response) => { const { id } = request.params; try { const savedQuery = await context.savedQuery; - const body = await savedQuery.get(id); + const body: SavedQueryRestResponse = await savedQuery.get(id); return response.ok({ body }); } catch (e) { // TODO: Handle properly @@ -88,15 +118,22 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void { } ); - router.get( + router.versioned.get({ path: `${SAVED_QUERY_BASE_URL}/_count`, access }).addVersion( { - path: `${SAVED_QUERY_PATH}/_count`, - validate: {}, + version, + validate: { + request: {}, + response: { + 200: { + body: schema.number(), + }, + }, + }, }, async (context, request, response) => { try { const savedQuery = await context.savedQuery; - const count = await savedQuery.count(); + const count: number = await savedQuery.count(); return response.ok({ body: `${count}` }); } catch (e) { // TODO: Handle properly @@ -105,21 +142,32 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void { } ); - router.post( + router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_find`, access }).addVersion( { - path: `${SAVED_QUERY_PATH}/_find`, + version, validate: { - body: schema.object({ - search: schema.string({ defaultValue: '' }), - perPage: schema.number({ defaultValue: 50 }), - page: schema.number({ defaultValue: 1 }), - }), + request: { + body: schema.object({ + search: schema.string({ defaultValue: '' }), + perPage: schema.number({ defaultValue: 50 }), + page: schema.number({ defaultValue: 1 }), + }), + }, + response: { + 200: { + body: schema.object({ + total: schema.number(), + savedQueries: schema.arrayOf(savedQueryResponseSchema), + }), + }, + }, }, }, async (context, request, response) => { try { const savedQuery = await context.savedQuery; - const body = await savedQuery.find(request.body); + const body: { total: number; savedQueries: SavedQueryRestResponse[] } = + await savedQuery.find(request.body); return response.ok({ body }); } catch (e) { // TODO: Handle properly @@ -128,15 +176,26 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void { } ); - router.post( + router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_all`, access }).addVersion( { - path: `${SAVED_QUERY_PATH}/_all`, - validate: {}, + version, + validate: { + request: {}, + response: { + 200: { + body: schema.object({ + total: schema.number(), + savedQueries: schema.arrayOf(savedQueryResponseSchema), + }), + }, + }, + }, }, async (context, request, response) => { try { const savedQuery = await context.savedQuery; - const body = await savedQuery.getAll(); + const body: { total: number; savedQueries: SavedQueryRestResponse[] } = + await savedQuery.getAll(); return response.ok({ body }); } catch (e) { // TODO: Handle properly @@ -145,19 +204,26 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void { } ); - router.delete( + router.versioned.delete({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion( { - path: `${SAVED_QUERY_PATH}/{id}`, + version, validate: { - params: SAVED_QUERY_ID_CONFIG, + request: { + params: SAVED_QUERY_ID_CONFIG, + }, + response: { + 200: { + body: schema.never(), + }, + }, }, }, async (context, request, response) => { const { id } = request.params; try { const savedQuery = await context.savedQuery; - const body = await savedQuery.delete(id); - return response.ok({ body }); + await savedQuery.delete(id); + return response.ok(); } catch (e) { // TODO: Handle properly return response.customError(e); diff --git a/src/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts b/src/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts index 014e57b41d2b1..10f04d05feea0 100644 --- a/src/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts +++ b/src/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts @@ -7,7 +7,7 @@ */ import { pipe, forEach } from 'lodash/fp'; -import { escapeKuery, KueryNode, nodeBuilder, nodeTypes } from '@kbn/es-query'; +import { KueryNode, nodeBuilder, nodeTypes } from '@kbn/es-query'; import { getFlattenedObject } from '@kbn/std'; @@ -44,7 +44,7 @@ export function filterArgsToKuery({ .map((value) => nodeBuilder.is( `${attrPrefix}.${fieldName}`, - isWildcard ? nodeTypes.wildcard.buildNode(value) : escapeKuery(value) + isWildcard ? nodeTypes.wildcard.buildNode(value) : value ) ); kueryExpressions.push(nodeBuilder.or(orExpressions)); @@ -56,10 +56,7 @@ export function filterArgsToKuery({ const andExpressions = values .filter(Boolean) .map((value) => - nodeTypes.function.buildNode( - 'not', - nodeBuilder.is(`${attrPrefix}.${fieldName}`, escapeKuery(value)) - ) + nodeTypes.function.buildNode('not', nodeBuilder.is(`${attrPrefix}.${fieldName}`, value)) ); kueryExpressions.push(nodeBuilder.and(andExpressions)); } diff --git a/src/plugins/files/server/file_share_service/internal_file_share_service.ts b/src/plugins/files/server/file_share_service/internal_file_share_service.ts index beef345cc8510..246dad5699f6d 100644 --- a/src/plugins/files/server/file_share_service/internal_file_share_service.ts +++ b/src/plugins/files/server/file_share_service/internal_file_share_service.ts @@ -13,7 +13,7 @@ import { ISavedObjectsRepository, SavedObjectsErrorHelpers, } from '@kbn/core/server'; -import { nodeBuilder, escapeKuery } from '@kbn/es-query'; +import { nodeBuilder } from '@kbn/es-query'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import type { Pagination, @@ -232,7 +232,7 @@ export class InternalFileShareService implements FileShareServiceStart { saved_objects: [share], } = await this.savedObjects.find({ type: this.savedObjectsType, - filter: nodeBuilder.is(`${this.savedObjectsType}.attributes.token`, escapeKuery(token)), + filter: nodeBuilder.is(`${this.savedObjectsType}.attributes.token`, token), }); if (!share) { diff --git a/src/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts b/src/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts index 3d4398e67f002..6fe0986e42df9 100644 --- a/src/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts +++ b/src/plugins/files/server/routes/file_kind/integration_tests/file_kind_http.test.ts @@ -172,6 +172,23 @@ describe('File kind HTTP API', () => { expect(files3.length).toBe(2); }); + test('can filter by mime type with special characters', async () => { + await createFile({ name: 'test', mimeType: 'image/x:123' }); + await createFile({ name: 'test 2', mimeType: 'text/html' }); + + const { + body: { files }, + } = await request + .post(root, `/api/files/files/${fileKind}/list`) + .send({ + mimeType: 'image/x:123', + }) + .expect(200); + + expect(files.length).toBe(1); + expect(files[0]).toMatchObject({ name: 'test' }); + }); + test('can filter by file extension', async () => { await createFile({ name: 'test', mimeType: 'image/png' }); await createFile({ name: 'test 2', mimeType: 'text/html' }); diff --git a/src/plugins/management/kibana.jsonc b/src/plugins/management/kibana.jsonc index 930c566b80655..b180cd74fa3d3 100644 --- a/src/plugins/management/kibana.jsonc +++ b/src/plugins/management/kibana.jsonc @@ -10,8 +10,7 @@ "share" ], "optionalPlugins": [ - "home", - "cloudChatProvider" + "home" ], "requiredBundles": [ "kibanaReact", diff --git a/src/plugins/management/public/components/management_app/management_app.tsx b/src/plugins/management/public/components/management_app/management_app.tsx index 51289c0fbf791..50ab45a867c98 100644 --- a/src/plugins/management/public/components/management_app/management_app.tsx +++ b/src/plugins/management/public/components/management_app/management_app.tsx @@ -16,7 +16,6 @@ import { AppMountParameters, ChromeBreadcrumb, ScopedHistory } from '@kbn/core/p import { reactRouterNavigate, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { KibanaPageTemplate, KibanaPageTemplateProps } from '@kbn/shared-ux-page-kibana-template'; -import type { CloudChatProviderPluginStart } from '@kbn/cloud-chat-provider-plugin/public'; import useObservable from 'react-use/lib/useObservable'; import { ManagementSection, @@ -39,11 +38,10 @@ export interface ManagementAppDependencies { kibanaVersion: string; setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; isSidebarEnabled$: BehaviorSubject; - cloudChat?: CloudChatProviderPluginStart; } export const ManagementApp = ({ dependencies, history, theme$ }: ManagementAppProps) => { - const { setBreadcrumbs, isSidebarEnabled$, cloudChat } = dependencies; + const { setBreadcrumbs, isSidebarEnabled$ } = dependencies; const [selectedId, setSelectedId] = useState(''); const [sections, setSections] = useState(); const isSidebarEnabled = useObservable(isSidebarEnabled$); @@ -116,7 +114,6 @@ export const ManagementApp = ({ dependencies, history, theme$ }: ManagementAppPr dependencies={dependencies} /> - {cloudChat?.Chat ? : null} ); diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index edb6bd55fc49b..578ae13a79c32 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -10,7 +10,6 @@ import { i18n } from '@kbn/i18n'; import { BehaviorSubject } from 'rxjs'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import { HomePublicPluginSetup } from '@kbn/home-plugin/public'; -import { CloudChatProviderPluginStart } from '@kbn/cloud-chat-provider-plugin/public'; import { CoreSetup, CoreStart, @@ -40,7 +39,6 @@ interface ManagementSetupDependencies { interface ManagementStartDependencies { share: SharePluginStart; - cloudChatProvider?: CloudChatProviderPluginStart; } export class ManagementPlugin @@ -113,14 +111,13 @@ export class ManagementPlugin updater$: this.appUpdater, async mount(params: AppMountParameters) { const { renderApp } = await import('./application'); - const [coreStart, plugins] = await core.getStartServices(); + const [coreStart] = await core.getStartServices(); return renderApp(params, { sections: getSectionsServiceStartPrivate(), kibanaVersion, setBreadcrumbs: coreStart.chrome.setBreadcrumbs, isSidebarEnabled$: managementPlugin.isSidebarEnabled$, - cloudChat: plugins.cloudChatProvider, }); }, }); diff --git a/src/plugins/management/tsconfig.json b/src/plugins/management/tsconfig.json index ff1289aa55356..10fd10492bea2 100644 --- a/src/plugins/management/tsconfig.json +++ b/src/plugins/management/tsconfig.json @@ -19,8 +19,7 @@ "@kbn/i18n", "@kbn/i18n-react", "@kbn/shared-ux-page-kibana-template", - "@kbn/shared-ux-router", - "@kbn/cloud-chat-provider-plugin", + "@kbn/shared-ux-router" ], "exclude": [ "target/**/*", diff --git a/src/plugins/telemetry/server/routes/index.ts b/src/plugins/telemetry/server/routes/index.ts index 8b73c8d76c4ec..5a47b4a00ac18 100644 --- a/src/plugins/telemetry/server/routes/index.ts +++ b/src/plugins/telemetry/server/routes/index.ts @@ -35,6 +35,6 @@ export function registerRoutes(options: RegisterRoutesParams) { registerTelemetryConfigRoutes(options); registerTelemetryUsageStatsRoutes(router, telemetryCollectionManager, isDev, getSecurity); registerTelemetryOptInStatsRoutes(router, telemetryCollectionManager); - registerTelemetryUserHasSeenNotice(router); + registerTelemetryUserHasSeenNotice(router, options.currentKibanaVersion); registerTelemetryLastReported(router, savedObjectsInternalClient$); } diff --git a/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts b/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts index eeac24c0f5a07..d9cb0b981b0a9 100644 --- a/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts +++ b/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts @@ -15,7 +15,7 @@ import { updateTelemetrySavedObject, } from '../saved_objects'; -export function registerTelemetryUserHasSeenNotice(router: IRouter) { +export function registerTelemetryUserHasSeenNotice(router: IRouter, currentKibanaVersion: string) { router.put( { path: '/api/telemetry/v2/userHasSeenNotice', @@ -31,6 +31,9 @@ export function registerTelemetryUserHasSeenNotice(router: IRouter) { const updatedAttributes: TelemetrySavedObjectAttributes = { ...telemetrySavedObject, userHasSeenNotice: true, + // We need to store that the user was notified in this version. + // Otherwise, it'll continuously show the banner if previously opted-out. + lastVersionChecked: currentKibanaVersion, }; await updateTelemetrySavedObject(soClient, updatedAttributes); diff --git a/src/plugins/visualization_ui_components/public/components/dimension_buttons/constants.ts b/src/plugins/visualization_ui_components/public/components/dimension_buttons/constants.ts new file mode 100644 index 0000000000000..7594cfa11b256 --- /dev/null +++ b/src/plugins/visualization_ui_components/public/components/dimension_buttons/constants.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; + +export const emptyTitleText = i18n.translate('visualizationUiComponents.emptyTitle', { + defaultMessage: '[Untitled]', +}); diff --git a/src/plugins/visualization_ui_components/public/components/dimension_buttons/dimension_button.test.tsx b/src/plugins/visualization_ui_components/public/components/dimension_buttons/dimension_button.test.tsx new file mode 100644 index 0000000000000..0f83694f06d8d --- /dev/null +++ b/src/plugins/visualization_ui_components/public/components/dimension_buttons/dimension_button.test.tsx @@ -0,0 +1,50 @@ +/* + * Copyright 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 { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; +import React from 'react'; +import { DimensionButton, DimensionButtonProps } from './dimension_button'; + +describe('DimensionButton', () => { + function getDefaultProps(): Omit { + return { + groupLabel: 'myGroup', + onClick: jest.fn(), + onRemoveClick: jest.fn(), + accessorConfig: { columnId: '1' }, + message: undefined, + }; + } + it('should fallback to the empty title if the dimension label is made of an empty string', () => { + render( + +
    + + ); + expect(screen.getByTitle('Edit [Untitled] configuration')).toBeInTheDocument(); + }); + + it('should fallback to the empty title if the dimension label is made up of whitespaces only', () => { + render( + +
    + + ); + expect(screen.getByTitle('Edit [Untitled] configuration')).toBeInTheDocument(); + }); + + it('should not fallback to the empty title if the dimension label has also valid chars beside whitespaces', () => { + render( + +
    + + ); + expect(screen.getByTitle('Edit aaa configuration')).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/visualization_ui_components/public/components/dimension_buttons/dimension_button.tsx b/src/plugins/visualization_ui_components/public/components/dimension_buttons/dimension_button.tsx index 7c9cbb881c2f3..44b158f43cf40 100644 --- a/src/plugins/visualization_ui_components/public/components/dimension_buttons/dimension_button.tsx +++ b/src/plugins/visualization_ui_components/public/components/dimension_buttons/dimension_button.tsx @@ -21,13 +21,27 @@ import { euiThemeVars } from '@kbn/ui-theme'; import { DimensionButtonIcon } from './dimension_button_icon'; import { PaletteIndicator } from './palette_indicator'; import type { AccessorConfig, Message } from './types'; +import { emptyTitleText } from './constants'; const triggerLinkA11yText = (label: string) => i18n.translate('visualizationUiComponents.dimensionButton.editConfig', { defaultMessage: 'Edit {label} configuration', - values: { label }, + values: { + label: label.trim().length ? label : emptyTitleText, + }, }); +export interface DimensionButtonProps { + className?: string; + groupLabel: string; + children: React.ReactElement; + onClick: (id: string) => void; + onRemoveClick: (id: string) => void; + accessorConfig: AccessorConfig; + label: string; + message?: Message; +} + export function DimensionButton({ groupLabel, children, @@ -37,16 +51,7 @@ export function DimensionButton({ label, message, ...otherProps // from Drag&Drop integration -}: { - className?: string; - groupLabel: string; - children: React.ReactElement; - onClick: (id: string) => void; - onRemoveClick: (id: string) => void; - accessorConfig: AccessorConfig; - label: string; - message?: Message; -}) { +}: DimensionButtonProps) { return (
    { + it('should fallback to the empty title if the dimension label is made of an empty string', () => { + render(); + expect(screen.queryByText('[Untitled]')).toBeInTheDocument(); + }); + + it('should fallback to the empty title if the dimension label is made up of whitespaces only', () => { + render(); + expect(screen.queryByText('[Untitled]')).toBeInTheDocument(); + }); + + it('should not fallback to the empty title if the dimension label has also valid chars beside whitespaces', () => { + render(); + expect(screen.queryByText('aaa')).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/visualization_ui_components/public/components/dimension_buttons/trigger.tsx b/src/plugins/visualization_ui_components/public/components/dimension_buttons/trigger.tsx index c050582332b05..622faac8f766c 100644 --- a/src/plugins/visualization_ui_components/public/components/dimension_buttons/trigger.tsx +++ b/src/plugins/visualization_ui_components/public/components/dimension_buttons/trigger.tsx @@ -9,9 +9,10 @@ import { EuiText, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { EuiTextProps } from '@elastic/eui/src/components/text/text'; +import type { EuiTextProps } from '@elastic/eui/src/components/text/text'; import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; +import { emptyTitleText } from './constants'; export const defaultDimensionTriggerTooltip = (

    @@ -36,6 +37,10 @@ export const DimensionTrigger = ({ color?: EuiTextProps['color']; dataTestSubj?: string; }) => { + let safeLabel = label; + if (typeof label === 'string') { + safeLabel = label?.trim().length > 0 ? label : emptyTitleText; + } return ( - {label} + {safeLabel} diff --git a/src/plugins/visualization_ui_components/public/index.ts b/src/plugins/visualization_ui_components/public/index.ts index b8be5d3afbd78..c56b6cb2c3d12 100644 --- a/src/plugins/visualization_ui_components/public/index.ts +++ b/src/plugins/visualization_ui_components/public/index.ts @@ -32,6 +32,7 @@ export { EmptyDimensionButton, LineStyleSettings, TextDecorationSetting, + emptyTitleText, } from './components'; export { isFieldLensCompatible } from './util'; diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index f39d5d89b0464..d2f053d378c18 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -181,6 +181,13 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.apm.managedServiceUrl (any)', 'xpack.apm.serverlessOnboarding (any)', 'xpack.apm.latestAgentVersionsUrl (string)', + 'xpack.apm.featureFlags.agentConfigurationAvailable (any)', + 'xpack.apm.featureFlags.configurableIndicesAvailable (any)', + 'xpack.apm.featureFlags.infrastructureTabAvailable (any)', + 'xpack.apm.featureFlags.infraUiAvailable (any)', + 'xpack.apm.featureFlags.migrationToFleetAvailable (any)', + 'xpack.apm.featureFlags.sourcemapApiAvailable (any)', + 'xpack.apm.featureFlags.storageExplorerAvailable (any)', 'xpack.cases.files.allowedMimeTypes (array)', 'xpack.cases.files.maxSize (number)', 'xpack.cases.markdownPlugins.lens (boolean)', diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_overlay/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_overlay/index.tsx index ed8ae782946b4..91200fd57ceb7 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_overlay/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/assistant_overlay/index.tsx @@ -24,7 +24,7 @@ const StyledEuiModal = styled(EuiModal)` `; /** - * Modal container for Security Assistant conversations, receiving the page contents as context, plus whatever + * Modal container for Elastic AI Assistant conversations, receiving the page contents as context, plus whatever * component currently has focus and any specific context it may provide through the SAssInterface. */ export const AssistantOverlay: React.FC = React.memo(() => { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.test.tsx index 75e3d4e015d45..88f90c2c0fa6b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.test.tsx @@ -6,11 +6,11 @@ */ import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { TestProviders } from '../../mock/test_providers/test_providers'; -import type { PromptContext } from '../prompt_context/types'; +import type { PromptContext, SelectedPromptContext } from '../prompt_context/types'; import { ContextPills } from '.'; const mockPromptContexts: Record = { @@ -30,6 +30,12 @@ const mockPromptContexts: Record = { }, }; +const defaultProps = { + defaultAllow: [], + defaultAllowReplacement: [], + promptContexts: mockPromptContexts, +}; + describe('ContextPills', () => { beforeEach(() => jest.clearAllMocks()); @@ -37,9 +43,9 @@ describe('ContextPills', () => { render( ); @@ -49,35 +55,45 @@ describe('ContextPills', () => { }); }); - it('invokes setSelectedPromptContextIds() when the prompt is NOT already selected', () => { + it('invokes setSelectedPromptContexts() when the prompt is NOT already selected', async () => { const context = mockPromptContexts.context1; - const setSelectedPromptContextIds = jest.fn(); + const setSelectedPromptContexts = jest.fn(); render( ); userEvent.click(screen.getByTestId(`pillButton-${context.id}`)); - expect(setSelectedPromptContextIds).toBeCalled(); + await waitFor(() => { + expect(setSelectedPromptContexts).toBeCalled(); + }); }); - it('it does NOT invoke setSelectedPromptContextIds() when the prompt is already selected', () => { + it('it does NOT invoke setSelectedPromptContexts() when the prompt is already selected', async () => { const context = mockPromptContexts.context1; - const setSelectedPromptContextIds = jest.fn(); + const mockSelectedPromptContext: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: context.id, + rawData: 'test-raw-data', + }; + const setSelectedPromptContexts = jest.fn(); render( ); @@ -85,18 +101,28 @@ describe('ContextPills', () => { // NOTE: this test uses `fireEvent` instead of `userEvent` to bypass the disabled button: fireEvent.click(screen.getByTestId(`pillButton-${context.id}`)); - expect(setSelectedPromptContextIds).not.toBeCalled(); + await waitFor(() => { + expect(setSelectedPromptContexts).not.toBeCalled(); + }); }); it('disables selected context pills', () => { const context = mockPromptContexts.context1; + const mockSelectedPromptContext: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: context.id, + rawData: 'test-raw-data', + }; render( ); @@ -110,9 +136,9 @@ describe('ContextPills', () => { render( ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.tsx index a8522a75b5adb..be5374e37bd67 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/context_pills/index.tsx @@ -11,22 +11,29 @@ import React, { useCallback, useMemo } from 'react'; // eslint-disable-next-line @kbn/eslint/module_migration import styled from 'styled-components'; -import type { PromptContext } from '../prompt_context/types'; +import { getNewSelectedPromptContext } from '../../data_anonymization/get_new_selected_prompt_context'; +import type { PromptContext, SelectedPromptContext } from '../prompt_context/types'; const PillButton = styled(EuiButton)` margin-right: ${({ theme }) => theme.eui.euiSizeXS}; `; interface Props { + defaultAllow: string[]; + defaultAllowReplacement: string[]; promptContexts: Record; - selectedPromptContextIds: string[]; - setSelectedPromptContextIds: React.Dispatch>; + selectedPromptContexts: Record; + setSelectedPromptContexts: React.Dispatch< + React.SetStateAction> + >; } const ContextPillsComponent: React.FC = ({ + defaultAllow, + defaultAllowReplacement, promptContexts, - selectedPromptContextIds, - setSelectedPromptContextIds, + selectedPromptContexts, + setSelectedPromptContexts, }) => { const sortedPromptContexts = useMemo( () => sortBy('description', Object.values(promptContexts)), @@ -34,12 +41,27 @@ const ContextPillsComponent: React.FC = ({ ); const selectPromptContext = useCallback( - (id: string) => { - if (!selectedPromptContextIds.includes(id)) { - setSelectedPromptContextIds((prev) => [...prev, id]); + async (id: string) => { + if (selectedPromptContexts[id] == null && promptContexts[id] != null) { + const newSelectedPromptContext = await getNewSelectedPromptContext({ + defaultAllow, + defaultAllowReplacement, + promptContext: promptContexts[id], + }); + + setSelectedPromptContexts((prev) => ({ + ...prev, + [id]: newSelectedPromptContext, + })); } }, - [selectedPromptContextIds, setSelectedPromptContextIds] + [ + defaultAllow, + defaultAllowReplacement, + promptContexts, + selectedPromptContexts, + setSelectedPromptContexts, + ] ); return ( @@ -49,7 +71,7 @@ const ContextPillsComponent: React.FC = ({ selectPromptContext(id)} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/get_anonymized_value/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/get_anonymized_value/index.test.ts new file mode 100644 index 0000000000000..a3235c2c4012b --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/get_anonymized_value/index.test.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 { invert } from 'lodash/fp'; + +import { getAnonymizedValue } from '.'; + +jest.mock('uuid', () => ({ + v4: () => 'test-uuid', +})); + +describe('getAnonymizedValue', () => { + beforeEach(() => jest.clearAllMocks()); + + it('returns a new UUID when currentReplacements is not provided', () => { + const currentReplacements = undefined; + const rawValue = 'test'; + + const result = getAnonymizedValue({ currentReplacements, rawValue }); + + expect(result).toBe('test-uuid'); + }); + + it('returns an existing anonymized value when currentReplacements contains an entry for it', () => { + const rawValue = 'test'; + const currentReplacements = { anonymized: 'test' }; + const rawValueToReplacement = invert(currentReplacements); + + const result = getAnonymizedValue({ currentReplacements, rawValue }); + expect(result).toBe(rawValueToReplacement[rawValue]); + }); + + it('returns a new UUID with currentReplacements if no existing match', () => { + const rawValue = 'test'; + const currentReplacements = { anonymized: 'other' }; + + const result = getAnonymizedValue({ currentReplacements, rawValue }); + + expect(result).toBe('test-uuid'); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/get_anonymized_value/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/get_anonymized_value/index.ts new file mode 100644 index 0000000000000..455e9700882fb --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/get_anonymized_value/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { invert } from 'lodash/fp'; +import { v4 } from 'uuid'; + +export const getAnonymizedValue = ({ + currentReplacements, + rawValue, +}: { + currentReplacements: Record | undefined; + rawValue: string; +}): string => { + if (currentReplacements != null) { + const rawValueToReplacement: Record = invert(currentReplacements); + const existingReplacement: string | undefined = rawValueToReplacement[rawValue]; + + return existingReplacement != null ? existingReplacement : v4(); + } + + return v4(); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx index 4c6d237e6cdfa..6ff45eadcaaa3 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/index.tsx @@ -15,6 +15,8 @@ import { EuiCommentList, EuiToolTip, EuiSplitPanel, + EuiSwitchEvent, + EuiSwitch, EuiCallOut, EuiIcon, EuiTitle, @@ -32,8 +34,10 @@ import { getMessageFromRawResponse } from './helpers'; import { ConversationSettingsPopover } from './conversation_settings_popover/conversation_settings_popover'; import { useAssistantContext } from '../assistant_context'; import { ContextPills } from './context_pills'; +import { getNewSelectedPromptContext } from '../data_anonymization/get_new_selected_prompt_context'; +import { SettingsPopover } from '../data_anonymization/settings/settings_popover'; import { PromptTextArea } from './prompt_textarea'; -import type { PromptContext } from './prompt_context/types'; +import type { PromptContext, SelectedPromptContext } from './prompt_context/types'; import { useConversation } from './use_conversation'; import { CodeBlockDetails } from './use_conversation/helpers'; import { useSendMessages } from './use_send_messages'; @@ -85,14 +89,23 @@ const AssistantComponent: React.FC = ({ actionTypeRegistry, augmentMessageCodeBlocks, conversations, + defaultAllow, + defaultAllowReplacement, getComments, http, promptContexts, title, } = useAssistantContext(); - const [selectedPromptContextIds, setSelectedPromptContextIds] = useState([]); + const [selectedPromptContexts, setSelectedPromptContexts] = useState< + Record + >({}); + const selectedPromptContextsCount = useMemo( + () => Object.keys(selectedPromptContexts).length, + [selectedPromptContexts] + ); - const { appendMessage, clearConversation, createConversation } = useConversation(); + const { appendMessage, appendReplacements, clearConversation, createConversation } = + useConversation(); const { isLoading, sendMessages } = useSendMessages(); const [selectedConversationId, setSelectedConversationId] = useState(conversationId); @@ -132,6 +145,8 @@ const AssistantComponent: React.FC = ({ const [showMissingConnectorCallout, setShowMissingConnectorCallout] = useState(false); + const [showAnonymizedValues, setShowAnonymizedValues] = useState(false); + const [messageCodeBlocks, setMessageCodeBlocks] = useState( augmentMessageCodeBlocks(currentConversation) ); @@ -179,17 +194,24 @@ const AssistantComponent: React.FC = ({ bottomRef.current?.scrollIntoView({ behavior: 'auto' }); promptTextAreaRef?.current?.focus(); }, 0); - }, [currentConversation.messages.length, selectedPromptContextIds.length]); + }, [currentConversation.messages.length, selectedPromptContextsCount]); //// // Handles sending latest user prompt to API const handleSendMessage = useCallback( async (promptText) => { + const onNewReplacements = (newReplacements: Record) => + appendReplacements({ + conversationId: selectedConversationId, + replacements: newReplacements, + }); + const message = await getCombinedMessage({ isNewChat: currentConversation.messages.length === 0, - promptContexts, + currentReplacements: currentConversation.replacements, + onNewReplacements, promptText, - selectedPromptContextIds, + selectedPromptContexts, selectedSystemPrompt: currentConversation.apiConfig.defaultSystemPrompt, }); @@ -199,7 +221,7 @@ const AssistantComponent: React.FC = ({ }); // Reset prompt context selection and preview before sending: - setSelectedPromptContextIds([]); + setSelectedPromptContexts({}); setPromptTextPreview(''); const rawResponse = await sendMessages({ @@ -212,12 +234,13 @@ const AssistantComponent: React.FC = ({ }, [ appendMessage, + appendReplacements, currentConversation.apiConfig, currentConversation.messages.length, + currentConversation.replacements, http, - promptContexts, selectedConversationId, - selectedPromptContextIds, + selectedPromptContexts, sendMessages, ] ); @@ -237,7 +260,24 @@ const AssistantComponent: React.FC = ({ codeBlockContainers.forEach((e) => (e.style.minHeight = '75px')); //// - const comments = getComments({ currentConversation, lastCommentRef }); + const onToggleShowAnonymizedValues = useCallback( + (e: EuiSwitchEvent) => { + if (setShowAnonymizedValues != null) { + setShowAnonymizedValues(e.target.checked); + } + }, + [setShowAnonymizedValues] + ); + + const comments = useMemo( + () => + getComments({ + currentConversation, + lastCommentRef, + showAnonymizedValues, + }), + [currentConversation, getComments, showAnonymizedValues] + ); useEffect(() => { // Adding `conversationId !== selectedConversationId` to prevent auto-run still executing after changing selected conversation @@ -253,12 +293,24 @@ const AssistantComponent: React.FC = ({ if (promptContext != null) { setAutoPopulatedOnce(true); - // select this prompt context - if (!selectedPromptContextIds.includes(promptContext.id)) { - setSelectedPromptContextIds((prev) => [...prev, promptContext.id]); + if (!Object.keys(selectedPromptContexts).includes(promptContext.id)) { + const addNewSelectedPromptContext = async () => { + const newSelectedPromptContext = await getNewSelectedPromptContext({ + defaultAllow, + defaultAllowReplacement, + promptContext, + }); + + setSelectedPromptContexts((prev) => ({ + ...prev, + [promptContext.id]: newSelectedPromptContext, + })); + }; + + addNewSelectedPromptContext(); } - if (promptContext?.suggestedUserPrompt != null) { + if (promptContext.suggestedUserPrompt != null) { setSuggestedUserPrompt(promptContext.suggestedUserPrompt); } } @@ -269,8 +321,10 @@ const AssistantComponent: React.FC = ({ handleSendMessage, conversationId, selectedConversationId, - selectedPromptContextIds, + selectedPromptContexts, autoPopulatedOnce, + defaultAllow, + defaultAllowReplacement, ]); // Show missing connector callout if no connectors are configured @@ -319,6 +373,35 @@ const AssistantComponent: React.FC = ({ shouldDisableKeyboardShortcut={shouldDisableConversationSelectorHotkeys} isDisabled={isWelcomeSetup} /> + + <> + + + + + 0 && + showAnonymizedValues + } + compressed={true} + disabled={currentConversation.replacements == null} + label={i18n.SHOW_ANONYMIZED} + onChange={onToggleShowAnonymizedValues} + /> + + + + + + + + @@ -354,9 +437,11 @@ const AssistantComponent: React.FC = ({ {!isWelcomeSetup && ( <> {Object.keys(promptContexts).length > 0 && } @@ -375,21 +460,22 @@ const AssistantComponent: React.FC = ({ <> -

    {(currentConversation.messages.length === 0 || - selectedPromptContextIds.length > 0) && ( + Object.keys(selectedPromptContexts).length > 0) && ( )} + +
    )} @@ -426,7 +512,7 @@ const AssistantComponent: React.FC = ({ onClick={() => { setPromptTextPreview(''); clearConversation(selectedConversationId); - setSelectedPromptContextIds([]); + setSelectedPromptContexts({}); setSuggestedUserPrompt(''); }} /> diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.test.ts index ca878bd5e5875..5604b21ad2e0d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.test.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.test.ts @@ -7,10 +7,21 @@ import type { Message } from '../../assistant_context/types'; import { getCombinedMessage, getSystemMessages } from './helpers'; +import { mockGetAnonymizedValue } from '../../mock/get_anonymized_value'; import { mockSystemPrompt } from '../../mock/system_prompt'; -import { mockAlertPromptContext, mockEventPromptContext } from '../../mock/prompt_context'; +import { mockAlertPromptContext } from '../../mock/prompt_context'; +import type { SelectedPromptContext } from '../prompt_context/types'; + +const mockSelectedAlertPromptContext: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: mockAlertPromptContext.id, + rawData: 'alert data', +}; describe('helpers', () => { + beforeEach(() => jest.clearAllMocks()); + describe('getSystemMessages', () => { it('should return an empty array if isNewChat is false', () => { const result = getSystemMessages({ @@ -51,17 +62,15 @@ describe('helpers', () => { }); describe('getCombinedMessage', () => { - const mockPromptContexts = { - [mockAlertPromptContext.id]: mockAlertPromptContext, - [mockEventPromptContext.id]: mockEventPromptContext, - }; - it('returns correct content for a new chat with a system prompt', async () => { const message: Message = await getCombinedMessage({ + currentReplacements: {}, isNewChat: true, - promptContexts: mockPromptContexts, + onNewReplacements: jest.fn(), promptText: 'User prompt text', - selectedPromptContextIds: [mockAlertPromptContext.id], + selectedPromptContexts: { + [mockSelectedAlertPromptContext.promptContextId]: mockSelectedAlertPromptContext, + }, selectedSystemPrompt: mockSystemPrompt, }); @@ -78,10 +87,13 @@ User prompt text`); it('returns correct content for a new chat WITHOUT a system prompt', async () => { const message: Message = await getCombinedMessage({ + currentReplacements: {}, isNewChat: true, - promptContexts: mockPromptContexts, + onNewReplacements: jest.fn(), promptText: 'User prompt text', - selectedPromptContextIds: [mockAlertPromptContext.id], + selectedPromptContexts: { + [mockSelectedAlertPromptContext.promptContextId]: mockSelectedAlertPromptContext, + }, selectedSystemPrompt: undefined, // <-- no system prompt }); @@ -97,10 +109,13 @@ User prompt text`); it('returns the correct content for an existing chat', async () => { const message: Message = await getCombinedMessage({ + currentReplacements: {}, isNewChat: false, - promptContexts: mockPromptContexts, + onNewReplacements: jest.fn(), promptText: 'User prompt text', - selectedPromptContextIds: [mockAlertPromptContext.id], + selectedPromptContexts: { + [mockSelectedAlertPromptContext.promptContextId]: mockSelectedAlertPromptContext, + }, selectedSystemPrompt: mockSystemPrompt, }); @@ -109,36 +124,89 @@ User prompt text`); alert data """ -CONTEXT: -""" -alert data -""" - User prompt text`); }); - test('getCombinedMessage returns the expected role', async () => { + it('returns the expected role', async () => { const message: Message = await getCombinedMessage({ + currentReplacements: {}, isNewChat: true, - promptContexts: mockPromptContexts, + onNewReplacements: jest.fn(), promptText: 'User prompt text', - selectedPromptContextIds: [mockAlertPromptContext.id], + selectedPromptContexts: { + [mockSelectedAlertPromptContext.promptContextId]: mockSelectedAlertPromptContext, + }, selectedSystemPrompt: mockSystemPrompt, }); expect(message.role).toBe('user'); }); - test('getCombinedMessage returns a valid timestamp', async () => { + it('returns a valid timestamp', async () => { const message: Message = await getCombinedMessage({ + currentReplacements: {}, isNewChat: true, - promptContexts: mockPromptContexts, + onNewReplacements: jest.fn(), promptText: 'User prompt text', - selectedPromptContextIds: [mockAlertPromptContext.id], + selectedPromptContexts: {}, selectedSystemPrompt: mockSystemPrompt, }); expect(Date.parse(message.timestamp)).not.toBeNaN(); }); + + describe('when there is data to anonymize', () => { + const onNewReplacements = jest.fn(); + + const mockPromptContextWithDataToAnonymize: SelectedPromptContext = { + allow: ['field1', 'field2'], + allowReplacement: ['field1', 'field2'], + promptContextId: 'test-prompt-context-id', + rawData: { + field1: ['foo', 'bar', 'baz'], + field2: ['foozle'], + }, + }; + + it('invokes `onNewReplacements` with the expected replacements', async () => { + await getCombinedMessage({ + currentReplacements: {}, + getAnonymizedValue: mockGetAnonymizedValue, + isNewChat: true, + onNewReplacements, + promptText: 'User prompt text', + selectedPromptContexts: { + [mockPromptContextWithDataToAnonymize.promptContextId]: + mockPromptContextWithDataToAnonymize, + }, + selectedSystemPrompt: mockSystemPrompt, + }); + + expect(onNewReplacements).toBeCalledWith({ + elzoof: 'foozle', + oof: 'foo', + rab: 'bar', + zab: 'baz', + }); + }); + + it('returns the expected content when `isNewChat` is false', async () => { + const isNewChat = false; // <-- not a new chat + + const message: Message = await getCombinedMessage({ + currentReplacements: {}, + getAnonymizedValue: mockGetAnonymizedValue, + isNewChat, + onNewReplacements: jest.fn(), + promptText: 'User prompt text', + selectedPromptContexts: {}, + selectedSystemPrompt: mockSystemPrompt, + }); + + expect(message.content).toEqual(` + +User prompt text`); + }); + }); }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts index 10dd5f62a2a89..cbf2259489505 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt/helpers.ts @@ -7,7 +7,10 @@ import type { Message } from '../../assistant_context/types'; import { SYSTEM_PROMPT_CONTEXT_NON_I18N } from '../../content/prompts/system/translations'; -import type { PromptContext } from '../prompt_context/types'; + +import { transformRawData } from '../../data_anonymization/transform_raw_data'; +import { getAnonymizedValue as defaultGetAnonymizedValue } from '../get_anonymized_value'; +import type { SelectedPromptContext } from '../prompt_context/types'; import type { Prompt } from '../types'; export const getSystemMessages = ({ @@ -31,35 +34,45 @@ export const getSystemMessages = ({ }; export async function getCombinedMessage({ + currentReplacements, + getAnonymizedValue = defaultGetAnonymizedValue, isNewChat, - promptContexts, + onNewReplacements, promptText, - selectedPromptContextIds, + selectedPromptContexts, selectedSystemPrompt, }: { + currentReplacements: Record | undefined; + getAnonymizedValue?: ({ + currentReplacements, + rawValue, + }: { + currentReplacements: Record | undefined; + rawValue: string; + }) => string; isNewChat: boolean; - promptContexts: Record; + onNewReplacements: (newReplacements: Record) => void; promptText: string; - selectedPromptContextIds: string[]; + selectedPromptContexts: Record; selectedSystemPrompt: Prompt | undefined; }): Promise { - const selectedPromptContexts = selectedPromptContextIds.reduce((acc, id) => { - const promptContext = promptContexts[id]; - return promptContext != null ? [...acc, promptContext] : acc; - }, []); - - const promptContextsContent = await Promise.all( - selectedPromptContexts.map(async ({ getPromptContext }) => { - const promptContext = await getPromptContext(); + const promptContextsContent = Object.keys(selectedPromptContexts) + .sort() + .map((id) => { + const promptContext = transformRawData({ + currentReplacements, + getAnonymizedValue, + onNewReplacements, + selectedPromptContext: selectedPromptContexts[id], + }); return `${SYSTEM_PROMPT_CONTEXT_NON_I18N(promptContext)}`; - }) - ); + }); return { - content: `${isNewChat ? `${selectedSystemPrompt?.content ?? ''}` : `${promptContextsContent}`} - -${promptContextsContent} + content: `${ + isNewChat ? `${selectedSystemPrompt?.content ?? ''}\n\n` : '' + }${promptContextsContent} ${promptText}`, role: 'user', // we are combining the system and user messages into one message diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_context/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_context/types.ts index 9c9b807281665..4e821c5c44bfa 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_context/types.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_context/types.ts @@ -8,7 +8,7 @@ import type { ReactNode } from 'react'; /** - * helps the Elastic Assistant display the most relevant user prompts + * helps the Elastic AI Assistant display the most relevant user prompts */ export type PromptContextCategory = | 'alert' @@ -19,7 +19,7 @@ export type PromptContextCategory = | string; /** - * This interface is used to pass context to the Elastic Assistant, + * This interface is used to pass context to the Elastic AI Assistant, * for the purpose of building prompts. Examples of context include: * - a single alert * - multiple alerts @@ -33,39 +33,53 @@ export interface PromptContext { /** * The category of data, e.g. `alert | alerts | event | events | string` * - * `category` helps the Elastic Assistant display the most relevant user prompts + * `category` helps the Elastic AI Assistant display the most relevant user prompts */ category: PromptContextCategory; /** - * The Elastic Assistant will display this **short**, static description + * The Elastic AI Assistant will display this **short**, static description * in the context pill */ description: string; /** - * The Elastic Assistant will invoke this function to retrieve the context data, + * The Elastic AI Assistant will invoke this function to retrieve the context data, * which will be included in a prompt (e.g. the contents of an alert or an event) */ - getPromptContext: () => Promise; + getPromptContext: () => Promise | Promise>; /** * A unique identifier for this prompt context */ id: string; /** - * An optional user prompt that's filled in, but not sent, when the Elastic Assistant opens + * An optional user prompt that's filled in, but not sent, when the Elastic AI Assistant opens */ suggestedUserPrompt?: string; /** - * The Elastic Assistant will display this tooltip when the user hovers over the context pill + * The Elastic AI Assistant will display this tooltip when the user hovers over the context pill */ tooltip: ReactNode; } /** - * This interface is used to pass a default or base set of contexts to the Elastic Assistant when + * A prompt context that was added from the pills to the current conversation, but not yet sent + */ +export interface SelectedPromptContext { + /** fields allowed to be included in a conversation */ + allow: string[]; + /** fields that will be anonymized */ + allowReplacement: string[]; + /** unique id of the selected `PromptContext` */ + promptContextId: string; + /** this data is not anonymized */ + rawData: string | Record; +} + +/** + * This interface is used to pass a default or base set of contexts to the Elastic AI Assistant when * initializing it. This is used to provide 'category' options when users create Quick Prompts. * Also, useful for collating all of a solutions' prompts in one place. * diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.test.tsx index 8aa50c7f86224..b14e69160f9c3 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.test.tsx @@ -10,8 +10,23 @@ import { render, screen, waitFor } from '@testing-library/react'; import { mockAlertPromptContext, mockEventPromptContext } from '../../mock/prompt_context'; import { TestProviders } from '../../mock/test_providers/test_providers'; +import { SelectedPromptContext } from '../prompt_context/types'; import { PromptEditor, Props } from '.'; +const mockSelectedAlertPromptContext: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: mockAlertPromptContext.id, + rawData: 'alert data', +}; + +const mockSelectedEventPromptContext: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: mockEventPromptContext.id, + rawData: 'event data', +}; + const defaultProps: Props = { conversation: undefined, isNewConversation: true, @@ -20,8 +35,8 @@ const defaultProps: Props = { [mockEventPromptContext.id]: mockEventPromptContext, }, promptTextPreview: 'Preview text', - selectedPromptContextIds: [], - setSelectedPromptContextIds: jest.fn(), + selectedPromptContexts: {}, + setSelectedPromptContexts: jest.fn(), }; describe('PromptEditorComponent', () => { @@ -52,16 +67,19 @@ describe('PromptEditorComponent', () => { }); it('renders the selected prompt contexts', async () => { - const selectedPromptContextIds = [mockAlertPromptContext.id, mockEventPromptContext.id]; + const selectedPromptContexts = { + [mockAlertPromptContext.id]: mockSelectedAlertPromptContext, + [mockEventPromptContext.id]: mockSelectedEventPromptContext, + }; render( - + ); await waitFor(() => { - selectedPromptContextIds.forEach((id) => + Object.keys(selectedPromptContexts).forEach((id) => expect(screen.queryByTestId(`selectedPromptContext-${id}`)).toBeInTheDocument() ); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.tsx index 3de97f30593ca..a35259c0655a6 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/index.tsx @@ -11,7 +11,7 @@ import React, { useMemo } from 'react'; import styled from 'styled-components'; import { Conversation } from '../../..'; -import type { PromptContext } from '../prompt_context/types'; +import type { PromptContext, SelectedPromptContext } from '../prompt_context/types'; import { SystemPrompt } from './system_prompt'; import * as i18n from './translations'; @@ -22,8 +22,10 @@ export interface Props { isNewConversation: boolean; promptContexts: Record; promptTextPreview: string; - selectedPromptContextIds: string[]; - setSelectedPromptContextIds: React.Dispatch>; + selectedPromptContexts: Record; + setSelectedPromptContexts: React.Dispatch< + React.SetStateAction> + >; } const PreviewText = styled(EuiText)` @@ -35,8 +37,8 @@ const PromptEditorComponent: React.FC = ({ isNewConversation, promptContexts, promptTextPreview, - selectedPromptContextIds, - setSelectedPromptContextIds, + selectedPromptContexts, + setSelectedPromptContexts, }) => { const commentBody = useMemo( () => ( @@ -46,8 +48,8 @@ const PromptEditorComponent: React.FC = ({ @@ -60,8 +62,8 @@ const PromptEditorComponent: React.FC = ({ isNewConversation, promptContexts, promptTextPreview, - selectedPromptContextIds, - setSelectedPromptContextIds, + selectedPromptContexts, + setSelectedPromptContexts, ] ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.test.tsx index 4ab4b708a68c8..8b71d45d3bc21 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.test.tsx @@ -11,6 +11,7 @@ import userEvent from '@testing-library/user-event'; import { mockAlertPromptContext, mockEventPromptContext } from '../../../mock/prompt_context'; import { TestProviders } from '../../../mock/test_providers/test_providers'; +import type { SelectedPromptContext } from '../../prompt_context/types'; import { Props, SelectedPromptContexts } from '.'; const defaultProps: Props = { @@ -19,8 +20,22 @@ const defaultProps: Props = { [mockAlertPromptContext.id]: mockAlertPromptContext, [mockEventPromptContext.id]: mockEventPromptContext, }, - selectedPromptContextIds: [], - setSelectedPromptContextIds: jest.fn(), + selectedPromptContexts: {}, + setSelectedPromptContexts: jest.fn(), +}; + +const mockSelectedAlertPromptContext: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: mockAlertPromptContext.id, + rawData: 'test-raw-data', +}; + +const mockSelectedEventPromptContext: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: mockEventPromptContext.id, + rawData: 'test-raw-data', }; describe('SelectedPromptContexts', () => { @@ -44,7 +59,9 @@ describe('SelectedPromptContexts', () => { ); @@ -60,7 +77,9 @@ describe('SelectedPromptContexts', () => { ); @@ -76,7 +95,10 @@ describe('SelectedPromptContexts', () => { ); @@ -87,57 +109,67 @@ describe('SelectedPromptContexts', () => { }); it('renders the selected prompt contexts', async () => { - const selectedPromptContextIds = [mockAlertPromptContext.id, mockEventPromptContext.id]; + const selectedPromptContexts = { + [mockAlertPromptContext.id]: mockSelectedAlertPromptContext, + [mockEventPromptContext.id]: mockSelectedEventPromptContext, + }; render( - + ); await waitFor(() => { - selectedPromptContextIds.forEach((id) => + Object.keys(selectedPromptContexts).forEach((id) => expect(screen.getByTestId(`selectedPromptContext-${id}`)).toBeInTheDocument() ); }); }); it('removes a prompt context when the remove button is clicked', async () => { - const setSelectedPromptContextIds = jest.fn(); + const setSelectedPromptContexts = jest.fn(); const promptContextId = mockAlertPromptContext.id; + const selectedPromptContexts = { + [mockAlertPromptContext.id]: mockSelectedAlertPromptContext, + [mockEventPromptContext.id]: mockSelectedEventPromptContext, + }; render( - + + + ); userEvent.click(screen.getByTestId(`removePromptContext-${promptContextId}`)); await waitFor(() => { - expect(setSelectedPromptContextIds).toHaveBeenCalled(); + expect(setSelectedPromptContexts).toHaveBeenCalled(); }); }); it('displays the correct accordion content', async () => { render( - + + + ); userEvent.click(screen.getByText(mockAlertPromptContext.description)); - const codeBlock = screen.getByTestId('promptCodeBlock'); + const codeBlock = screen.getByTestId('readOnlyContextViewer'); await waitFor(() => { - expect(codeBlock).toHaveTextContent('alert data'); + expect(codeBlock).toHaveTextContent('CONTEXT: """ test-raw-data """'); }); }); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.tsx index eca303284d1a8..b8aed6edf0212 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/selected_prompt_contexts/index.tsx @@ -8,114 +8,98 @@ import { EuiAccordion, EuiButtonIcon, - EuiCodeBlock, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiToolTip, } from '@elastic/eui'; -import { isEmpty } from 'lodash/fp'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { isEmpty, omit } from 'lodash/fp'; +import React, { useCallback } from 'react'; // eslint-disable-next-line @kbn/eslint/module_migration import styled from 'styled-components'; -import { SYSTEM_PROMPT_CONTEXT_NON_I18N } from '../../../content/prompts/system/translations'; -import type { PromptContext } from '../../prompt_context/types'; +import { DataAnonymizationEditor } from '../../../data_anonymization_editor'; +import type { PromptContext, SelectedPromptContext } from '../../prompt_context/types'; import * as i18n from './translations'; -const PromptContextContainer = styled.div` - max-width: 60vw; - overflow-x: auto; -`; - export interface Props { isNewConversation: boolean; promptContexts: Record; - selectedPromptContextIds: string[]; - setSelectedPromptContextIds: React.Dispatch>; + selectedPromptContexts: Record; + setSelectedPromptContexts: React.Dispatch< + React.SetStateAction> + >; } +export const EditorContainer = styled.div<{ + $accordionState: 'closed' | 'open'; +}>` + ${({ $accordionState }) => ($accordionState === 'closed' ? 'height: 0px;' : '')} + ${({ $accordionState }) => ($accordionState === 'closed' ? 'overflow: hidden;' : '')} + ${({ $accordionState }) => ($accordionState === 'closed' ? 'position: absolute;' : '')} +`; + const SelectedPromptContextsComponent: React.FC = ({ isNewConversation, promptContexts, - selectedPromptContextIds, - setSelectedPromptContextIds, + selectedPromptContexts, + setSelectedPromptContexts, }) => { - const selectedPromptContexts = useMemo( - () => selectedPromptContextIds.map((id) => promptContexts[id]), - [promptContexts, selectedPromptContextIds] - ); + const [accordionState, setAccordionState] = React.useState<'closed' | 'open'>('closed'); - const [accordionContent, setAccordionContent] = useState>({}); + const onToggle = useCallback( + () => setAccordionState((prev) => (prev === 'open' ? 'closed' : 'open')), + [] + ); const unselectPromptContext = useCallback( (unselectedId: string) => { - setSelectedPromptContextIds((prev) => prev.filter((id) => id !== unselectedId)); + setSelectedPromptContexts((prev) => omit(unselectedId, prev)); }, - [setSelectedPromptContextIds] + [setSelectedPromptContexts] ); - useEffect(() => { - const abortController = new AbortController(); - - const fetchAccordionContent = async () => { - const newAccordionContent = await Promise.all( - selectedPromptContexts.map(async ({ getPromptContext, id }) => ({ - [id]: await getPromptContext(), - })) - ); - - if (!abortController.signal.aborted) { - setAccordionContent(newAccordionContent.reduce((acc, curr) => ({ ...acc, ...curr }), {})); - } - }; - - fetchAccordionContent(); - - return () => { - abortController.abort(); - }; - }, [selectedPromptContexts]); - if (isEmpty(promptContexts)) { return null; } return ( - {selectedPromptContexts.map(({ description, id }) => ( - - {isNewConversation || selectedPromptContexts.length > 1 ? ( - - ) : null} - - unselectPromptContext(id)} + {Object.keys(selectedPromptContexts) + .sort() + .map((id) => ( + + {isNewConversation || Object.keys(selectedPromptContexts).length > 1 ? ( + + ) : null} + + unselectPromptContext(id)} + /> + + } + id={id} + onToggle={onToggle} + paddingSize="s" + > + + - - } - id={id} - paddingSize="s" - > - - - {id != null && accordionContent[id] != null - ? SYSTEM_PROMPT_CONTEXT_NON_I18N(accordionContent[id]) - : ''} - - - - - ))} + + + + ))} ); }; -SelectedPromptContextsComponent.displayName = 'SelectedPromptContextsComponent'; export const SelectedPromptContexts = React.memo(SelectedPromptContextsComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts index faf9a4d21c3c8..0b401eeb400a9 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/translations.ts @@ -14,7 +14,7 @@ export const CLEAR_CHAT = i18n.translate('xpack.elasticAssistant.assistant.clear export const DEFAULT_ASSISTANT_TITLE = i18n.translate( 'xpack.elasticAssistant.assistant.defaultAssistantTitle', { - defaultMessage: 'Elastic Assistant', + defaultMessage: 'Elastic AI Assistant', } ); @@ -58,6 +58,20 @@ export const SETTINGS_PROMPT_HELP_TEXT_TITLE = i18n.translate( } ); +export const SHOW_ANONYMIZED = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.showAnonymizedToggleLabel', + { + defaultMessage: 'Show anonymized', + } +); + +export const SHOW_ANONYMIZED_TOOLTIP = i18n.translate( + 'xpack.elasticAssistant.assistant.settings.showAnonymizedTooltip', + { + defaultMessage: 'Show the anonymized values sent to and from the assistant', + } +); + export const SUBMIT_MESSAGE = i18n.translate('xpack.elasticAssistant.assistant.submitMessage', { defaultMessage: 'Submit message', }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_assistant_overlay/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_assistant_overlay/index.tsx index f804ec5178ca2..ba1992b5e50de 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_assistant_overlay/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_assistant_overlay/index.tsx @@ -58,7 +58,7 @@ export const useAssistantOverlay = ( id: PromptContext['id'] | null, /** - * An optional user prompt that's filled in, but not sent, when the Elastic Assistant opens + * An optional user prompt that's filled in, but not sent, when the Elastic AI Assistant opens */ suggestedUserPrompt: PromptContext['suggestedUserPrompt'] | null, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/index.tsx index 7fa03f713ee8d..08124d750d949 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/index.tsx @@ -10,17 +10,17 @@ import { useCallback } from 'react'; import { useAssistantContext } from '../../assistant_context'; import { Conversation, Message } from '../../assistant_context/types'; import * as i18n from './translations'; -import { ELASTIC_SECURITY_ASSISTANT, ELASTIC_SECURITY_ASSISTANT_TITLE } from './translations'; +import { ELASTIC_AI_ASSISTANT, ELASTIC_AI_ASSISTANT_TITLE } from './translations'; export const DEFAULT_CONVERSATION_STATE: Conversation = { id: i18n.DEFAULT_CONVERSATION_TITLE, messages: [], apiConfig: {}, theme: { - title: ELASTIC_SECURITY_ASSISTANT_TITLE, + title: ELASTIC_AI_ASSISTANT_TITLE, titleIcon: 'logoSecurity', assistant: { - name: ELASTIC_SECURITY_ASSISTANT, + name: ELASTIC_AI_ASSISTANT, icon: 'logoSecurity', }, system: { @@ -35,6 +35,11 @@ interface AppendMessageProps { message: Message; } +interface AppendReplacementsProps { + conversationId: string; + replacements: Record; +} + interface CreateConversationProps { conversationId: string; messages?: Message[]; @@ -51,6 +56,10 @@ interface SetConversationProps { interface UseConversation { appendMessage: ({ conversationId: string, message: Message }: AppendMessageProps) => Message[]; + appendReplacements: ({ + conversationId, + replacements, + }: AppendReplacementsProps) => Record; clearConversation: (conversationId: string) => void; createConversation: ({ conversationId, @@ -93,9 +102,38 @@ export const useConversation = (): UseConversation => { [setConversations] ); - /** - * Clear the messages[] for a given conversationId - */ + const appendReplacements = useCallback( + ({ conversationId, replacements }: AppendReplacementsProps): Record => { + let allReplacements = replacements; + + setConversations((prev: Record) => { + const prevConversation: Conversation | undefined = prev[conversationId]; + + if (prevConversation != null) { + allReplacements = { + ...prevConversation.replacements, + ...replacements, + }; + + const newConversation = { + ...prevConversation, + replacements: allReplacements, + }; + + return { + ...prev, + [conversationId]: newConversation, + }; + } else { + return prev; + } + }); + + return allReplacements; + }, + [setConversations] + ); + const clearConversation = useCallback( (conversationId: string) => { setConversations((prev: Record) => { @@ -105,6 +143,7 @@ export const useConversation = (): UseConversation => { const newConversation = { ...prevConversation, messages: [], + replacements: undefined, }; return { @@ -210,6 +249,7 @@ export const useConversation = (): UseConversation => { return { appendMessage, + appendReplacements, clearConversation, createConversation, deleteConversation, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/sample_conversations.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/sample_conversations.tsx index 3fc41160d5bbf..a49cd0e22a0f4 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/sample_conversations.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/sample_conversations.tsx @@ -9,8 +9,8 @@ import { Conversation } from '../../assistant_context/types'; import * as i18n from '../../content/prompts/welcome/translations'; import { DEFAULT_CONVERSATION_TITLE, - ELASTIC_SECURITY_ASSISTANT, - ELASTIC_SECURITY_ASSISTANT_TITLE, + ELASTIC_AI_ASSISTANT, + ELASTIC_AI_ASSISTANT_TITLE, WELCOME_CONVERSATION_TITLE, } from './translations'; @@ -87,10 +87,10 @@ export const BASE_CONVERSATIONS: Record = { [WELCOME_CONVERSATION_TITLE]: { id: WELCOME_CONVERSATION_TITLE, theme: { - title: ELASTIC_SECURITY_ASSISTANT_TITLE, + title: ELASTIC_AI_ASSISTANT_TITLE, titleIcon: 'logoSecurity', assistant: { - name: ELASTIC_SECURITY_ASSISTANT, + name: ELASTIC_AI_ASSISTANT, icon: 'logoSecurity', }, system: { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/translations.ts index 48271c8b50629..e26e910b9953d 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/use_conversation/translations.ts @@ -20,15 +20,15 @@ export const DEFAULT_CONVERSATION_TITLE = i18n.translate( } ); -export const ELASTIC_SECURITY_ASSISTANT_TITLE = i18n.translate( - 'xpack.elasticAssistant.assistant.useConversation.elasticSecurityAssistantTitle', +export const ELASTIC_AI_ASSISTANT_TITLE = i18n.translate( + 'xpack.elasticAssistant.assistant.useConversation.elasticAiAssistantTitle', { - defaultMessage: 'Elastic Security Assistant', + defaultMessage: 'Elastic AI Assistant', } ); -export const ELASTIC_SECURITY_ASSISTANT = i18n.translate( - 'xpack.elasticAssistant.assistant.useConversation.elasticSecurityAssistantName', +export const ELASTIC_AI_ASSISTANT = i18n.translate( + 'xpack.elasticAssistant.assistant.useConversation.elasticAiAssistantName', { defaultMessage: 'Assistant', } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.test.tsx index 564d57ddd39fa..c410ef029fd6c 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.test.tsx @@ -21,10 +21,16 @@ const ContextWrapper: React.FC = ({ children }) => ( {children} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx index a460a60748386..a67aeb54f65a5 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/index.tsx @@ -7,7 +7,7 @@ import { EuiCommentProps } from '@elastic/eui'; import type { HttpSetup } from '@kbn/core-http-browser'; -import { omit } from 'lodash/fp'; +import { omit, uniq } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; @@ -45,6 +45,10 @@ type ShowAssistantOverlay = ({ interface AssistantProviderProps { actionTypeRegistry: ActionTypeRegistryContract; augmentMessageCodeBlocks: (currentConversation: Conversation) => CodeBlockDetails[][]; + baseAllow: string[]; + baseAllowReplacement: string[]; + defaultAllow: string[]; + defaultAllowReplacement: string[]; basePromptContexts?: PromptContextTemplate[]; baseQuickPrompts?: QuickPrompt[]; baseSystemPrompts?: Prompt[]; @@ -52,14 +56,18 @@ interface AssistantProviderProps { getComments: ({ currentConversation, lastCommentRef, + showAnonymizedValues, }: { currentConversation: Conversation; lastCommentRef: React.MutableRefObject; + showAnonymizedValues: boolean; }) => EuiCommentProps[]; http: HttpSetup; getInitialConversations: () => Record; nameSpace?: string; setConversations: React.Dispatch>>; + setDefaultAllow: React.Dispatch>; + setDefaultAllowReplacement: React.Dispatch>; title?: string; } @@ -68,6 +76,10 @@ interface UseAssistantContext { augmentMessageCodeBlocks: (currentConversation: Conversation) => CodeBlockDetails[][]; allQuickPrompts: QuickPrompt[]; allSystemPrompts: Prompt[]; + baseAllow: string[]; + baseAllowReplacement: string[]; + defaultAllow: string[]; + defaultAllowReplacement: string[]; basePromptContexts: PromptContextTemplate[]; baseQuickPrompts: QuickPrompt[]; baseSystemPrompts: Prompt[]; @@ -76,9 +88,12 @@ interface UseAssistantContext { getComments: ({ currentConversation, lastCommentRef, + showAnonymizedValues, }: { currentConversation: Conversation; lastCommentRef: React.MutableRefObject; + + showAnonymizedValues: boolean; }) => EuiCommentProps[]; http: HttpSetup; promptContexts: Record; @@ -87,6 +102,8 @@ interface UseAssistantContext { setAllQuickPrompts: React.Dispatch>; setAllSystemPrompts: React.Dispatch>; setConversations: React.Dispatch>>; + setDefaultAllow: React.Dispatch>; + setDefaultAllowReplacement: React.Dispatch>; setShowAssistantOverlay: (showAssistantOverlay: ShowAssistantOverlay) => void; showAssistantOverlay: ShowAssistantOverlay; title: string; @@ -98,6 +115,10 @@ const AssistantContext = React.createContext(un export const AssistantProvider: React.FC = ({ actionTypeRegistry, augmentMessageCodeBlocks, + baseAllow, + baseAllowReplacement, + defaultAllow, + defaultAllowReplacement, basePromptContexts = [], baseQuickPrompts = [], baseSystemPrompts = BASE_SYSTEM_PROMPTS, @@ -107,6 +128,8 @@ export const AssistantProvider: React.FC = ({ getInitialConversations, nameSpace = DEFAULT_ASSISTANT_NAMESPACE, setConversations, + setDefaultAllow, + setDefaultAllowReplacement, title = DEFAULT_ASSISTANT_TITLE, }) => { /** @@ -202,11 +225,15 @@ export const AssistantProvider: React.FC = ({ augmentMessageCodeBlocks, allQuickPrompts: localStorageQuickPrompts ?? [], allSystemPrompts: localStorageSystemPrompts ?? [], + baseAllow: uniq(baseAllow), + baseAllowReplacement: uniq(baseAllowReplacement), basePromptContexts, baseQuickPrompts, baseSystemPrompts, conversationIds, conversations, + defaultAllow: uniq(defaultAllow), + defaultAllowReplacement: uniq(defaultAllowReplacement), getComments, http, promptContexts, @@ -215,6 +242,8 @@ export const AssistantProvider: React.FC = ({ setAllQuickPrompts: setLocalStorageQuickPrompts, setAllSystemPrompts: setLocalStorageSystemPrompts, setConversations: onConversationsUpdated, + setDefaultAllow, + setDefaultAllowReplacement, setShowAssistantOverlay, showAssistantOverlay, title, @@ -223,19 +252,25 @@ export const AssistantProvider: React.FC = ({ [ actionTypeRegistry, augmentMessageCodeBlocks, + baseAllow, + baseAllowReplacement, basePromptContexts, baseQuickPrompts, baseSystemPrompts, conversationIds, conversations, + defaultAllow, + defaultAllowReplacement, getComments, http, localStorageQuickPrompts, localStorageSystemPrompts, - promptContexts, nameSpace, - registerPromptContext, onConversationsUpdated, + promptContexts, + registerPromptContext, + setDefaultAllow, + setDefaultAllowReplacement, setLocalStorageQuickPrompts, setLocalStorageSystemPrompts, showAssistantOverlay, diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx index e237b8855f731..ce49b55e5ef84 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/types.tsx @@ -51,6 +51,7 @@ export interface Conversation { }; id: string; messages: Message[]; + replacements?: Record; theme?: ConversationTheme; isDefault?: boolean; } diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts index c9eb7797e362c..923cb916df4e6 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/translations.ts @@ -11,7 +11,7 @@ export const LOAD_ACTIONS_ERROR_MESSAGE = i18n.translate( 'xpack.elasticAssistant.connectors.useLoadActionTypes.errorMessage', { defaultMessage: - 'Welcome to your Elastic Assistant! I am your 100% open-source portal into your Elastic Life. ', + 'Welcome to your Elastic AI Assistant! I am your 100% open-source portal into your Elastic Life. ', } ); @@ -19,7 +19,7 @@ export const LOAD_CONNECTORS_ERROR_MESSAGE = i18n.translate( 'xpack.elasticAssistant.connectors.useLoadConnectors.errorMessage', { defaultMessage: - 'Welcome to your Elastic Assistant! I am your 100% open-source portal into your Elastic Life. ', + 'Welcome to your Elastic AI Assistant! I am your 100% open-source portal into your Elastic Life. ', } ); @@ -27,7 +27,7 @@ export const WELCOME_SECURITY = i18n.translate( 'xpack.elasticAssistant.content.prompts.welcome.welcomeSecurityPrompt', { defaultMessage: - 'Welcome to your Elastic Assistant! I am your 100% open-source portal into Elastic Security. ', + 'Welcome to your Elastic AI Assistant! I am your 100% open-source portal into Elastic Security. ', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx index 3a11330446667..e2034cc62c33a 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/index.tsx @@ -14,7 +14,7 @@ import { } from './translations'; /** - * Base System Prompts for Elastic Assistant (if not overridden on initialization). + * Base System Prompts for Elastic AI Assistant (if not overridden on initialization). */ export const BASE_SYSTEM_PROMPTS: Prompt[] = [ { diff --git a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts index 9a1c02eaccfc2..1a8b09f0c2aa1 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/system/translations.ts @@ -11,7 +11,7 @@ export const YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT = i18n.translate( 'xpack.elasticAssistant.assistant.content.prompts.system.youAreAHelpfulExpertAssistant', { defaultMessage: - 'You are a helpful, expert assistant who only answers questions about Elastic Security.', + 'You are a helpful, expert assistant who answers questions about Elastic Security.', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/welcome/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/welcome/translations.ts index 6a6b1253ca2b1..8c28f1a8fa3f3 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/welcome/translations.ts +++ b/x-pack/packages/kbn-elastic-assistant/impl/content/prompts/welcome/translations.ts @@ -11,7 +11,7 @@ export const WELCOME_GENERAL = i18n.translate( 'xpack.elasticAssistant.securityAssistant.content.prompts.welcome.welcomeGeneralPrompt', { defaultMessage: - 'Welcome to your Elastic Assistant! I am your 100% open-code portal into your Elastic life. In time, I will be able to answer questions and provide assistance across all your information in Elastic, and oh-so much more. Till then, I hope this early preview will open your mind to the possibilities of what we can create when we work together, in the open. Cheers!', + 'Welcome to your Elastic AI Assistant! I am your 100% open-code portal into your Elastic life. In time, I will be able to answer questions and provide assistance across all your information in Elastic, and oh-so much more. Till then, I hope this early preview will open your mind to the possibilities of what we can create when we work together, in the open. Cheers!', } ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.test.ts new file mode 100644 index 0000000000000..abfb627376fc3 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getAnonymizedValues } from '../get_anonymized_values'; +import { mockGetAnonymizedValue } from '../../mock/get_anonymized_value'; +import { getAnonymizedData } from '.'; + +describe('getAnonymizedData', () => { + const rawData: Record = { + doNotReplace: ['this-will-not-be-replaced', 'neither-will-this'], + empty: [], + 'host.ip': ['127.0.0.1', '10.0.0.1'], + 'host.name': ['test-host'], + doNotInclude: ['this-will-not-be-included', 'neither-will-this'], + }; + + const commonArgs = { + allow: ['doNotReplace', 'empty', 'host.ip', 'host.name'], + allowReplacement: ['empty', 'host.ip', 'host.name'], + currentReplacements: {}, + rawData, + getAnonymizedValue: mockGetAnonymizedValue, + getAnonymizedValues, + }; + + it('returns the expected anonymized data', () => { + const result = getAnonymizedData({ + ...commonArgs, + }); + + expect(result.anonymizedData).toEqual({ + doNotReplace: ['this-will-not-be-replaced', 'neither-will-this'], + empty: [], + 'host.ip': ['1.0.0.721', '1.0.0.01'], + 'host.name': ['tsoh-tset'], + }); + }); + + it('returns the expected map of replaced value to original value', () => { + const result = getAnonymizedData({ + ...commonArgs, + }); + + expect(result.replacements).toEqual({ + '1.0.0.721': '127.0.0.1', + '1.0.0.01': '10.0.0.1', + 'tsoh-tset': 'test-host', + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.ts new file mode 100644 index 0000000000000..a0ecd88234313 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_data/index.ts @@ -0,0 +1,66 @@ +/* + * Copyright 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 { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { isAllowed } from '../../data_anonymization_editor/helpers'; +import type { AnonymizedData, GetAnonymizedValues } from '../types'; + +export const getAnonymizedData = ({ + allow, + allowReplacement, + currentReplacements, + getAnonymizedValue, + getAnonymizedValues, + rawData, +}: { + allow: SelectedPromptContext['allow']; + allowReplacement: SelectedPromptContext['allowReplacement']; + currentReplacements: Record | undefined; + getAnonymizedValue: ({ + currentReplacements, + rawValue, + }: { + currentReplacements: Record | undefined; + rawValue: string; + }) => string; + getAnonymizedValues: GetAnonymizedValues; + rawData: Record; +}): AnonymizedData => + Object.keys(rawData).reduce( + (acc, field) => { + const allowReplacementSet = new Set(allowReplacement); + const allowSet = new Set(allow); + + if (isAllowed({ allowSet, field })) { + const { anonymizedValues, replacements } = getAnonymizedValues({ + allowReplacementSet, + allowSet, + currentReplacements, + field, + getAnonymizedValue, + rawData, + }); + + return { + anonymizedData: { + ...acc.anonymizedData, + [field]: anonymizedValues, + }, + replacements: { + ...acc.replacements, + ...replacements, + }, + }; + } else { + return acc; + } + }, + { + anonymizedData: {}, + replacements: {}, + } + ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.test.tsx new file mode 100644 index 0000000000000..24e95ca0f0bb0 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.test.tsx @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getAnonymizedValues } from '.'; +import { mockGetAnonymizedValue } from '../../mock/get_anonymized_value'; + +describe('getAnonymizedValues', () => { + it('returns empty anonymizedValues and replacements when provided with empty raw data', () => { + const result = getAnonymizedValues({ + allowReplacementSet: new Set(), + allowSet: new Set(), + currentReplacements: {}, + field: 'test.field', + getAnonymizedValue: jest.fn(), + rawData: {}, + }); + + expect(result).toEqual({ + anonymizedValues: [], + replacements: {}, + }); + }); + + it('returns the expected anonymized values', () => { + const rawData = { + 'test.field': ['test1', 'test2'], + }; + + const result = getAnonymizedValues({ + allowReplacementSet: new Set(['test.field']), + allowSet: new Set(['test.field']), + currentReplacements: {}, + field: 'test.field', + getAnonymizedValue: mockGetAnonymizedValue, + rawData, + }); + + expect(result.anonymizedValues).toEqual(['1tset', '2tset']); + }); + + it('returns the expected replacements', () => { + const rawData = { + 'test.field': ['test1', 'test2'], + }; + + const result = getAnonymizedValues({ + allowReplacementSet: new Set(['test.field']), + allowSet: new Set(['test.field']), + currentReplacements: {}, + field: 'test.field', + getAnonymizedValue: mockGetAnonymizedValue, + rawData, + }); + + expect(result.replacements).toEqual({ + '1tset': 'test1', + '2tset': 'test2', + }); + }); + + it('returns non-anonymized values when the field is not a member of the `allowReplacementSet`', () => { + const rawData = { + 'test.field': ['test1', 'test2'], + }; + + const result = getAnonymizedValues({ + allowReplacementSet: new Set(), // does NOT include `test.field` + allowSet: new Set(['test.field']), + currentReplacements: {}, + field: 'test.field', + getAnonymizedValue: mockGetAnonymizedValue, + rawData, + }); + + expect(result.anonymizedValues).toEqual(['test1', 'test2']); // no anonymization + }); + + it('does NOT allow a field to be included in `anonymizedValues` when the field is not a member of the `allowSet`', () => { + const rawData = { + 'test.field': ['test1', 'test2'], + }; + + const result = getAnonymizedValues({ + allowReplacementSet: new Set(['test.field']), + allowSet: new Set(), // does NOT include `test.field` + currentReplacements: {}, + field: 'test.field', + getAnonymizedValue: mockGetAnonymizedValue, + rawData, + }); + + expect(result.anonymizedValues).toEqual([]); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.ts new file mode 100644 index 0000000000000..db846f93bf112 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_anonymized_values/index.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 { isAllowed, isAnonymized } from '../../data_anonymization_editor/helpers'; +import { AnonymizedValues, GetAnonymizedValues } from '../types'; + +export const getAnonymizedValues: GetAnonymizedValues = ({ + allowSet, + allowReplacementSet, + currentReplacements, + field, + getAnonymizedValue, + rawData, +}): AnonymizedValues => { + const rawValues = rawData[field] ?? []; + + return rawValues.reduce( + (acc, rawValue) => { + if (isAllowed({ allowSet, field }) && isAnonymized({ allowReplacementSet, field })) { + const anonymizedValue = getAnonymizedValue({ currentReplacements, rawValue }); + + return { + anonymizedValues: [...acc.anonymizedValues, anonymizedValue], + replacements: { + ...acc.replacements, + [anonymizedValue]: rawValue, + }, + }; + } else if (isAllowed({ allowSet, field })) { + return { + anonymizedValues: [...acc.anonymizedValues, rawValue], // no anonymization for this value + replacements: { + ...acc.replacements, // no additional replacements + }, + }; + } else { + return acc; + } + }, + { + anonymizedValues: [], + replacements: {}, + } + ); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.test.ts new file mode 100644 index 0000000000000..b1c08d29b1b95 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.test.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getCsvFromData } from '.'; + +describe('getCsvFromData', () => { + it('returns the expected csv', () => { + const data: Record = { + a: ['1', '2', '3'], + b: ['4', '5', '6'], + c: ['7', '8', '9'], + }; + + const result = getCsvFromData(data); + + expect(result).toBe('a,1,2,3\nb,4,5,6\nc,7,8,9'); + }); + + it('returns an empty string for empty data', () => { + const data: Record = {}; + + const result = getCsvFromData(data); + + expect(result).toBe(''); + }); + + it('sorts the keys alphabetically', () => { + const data: Record = { + b: ['1', '2', '3'], + a: ['4', '5', '6'], + c: ['7', '8', '9'], + }; + + const result = getCsvFromData(data); + + expect(result).toBe('a,4,5,6\nb,1,2,3\nc,7,8,9'); + }); + + it('correctly handles single-element arrays', () => { + const data: Record = { + a: ['1'], + b: ['2'], + c: ['3'], + }; + + const result = getCsvFromData(data); + + expect(result).toBe('a,1\nb,2\nc,3'); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.ts new file mode 100644 index 0000000000000..4bef8a0218f6d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_csv_from_data/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getCsvFromData = (data: Record): string => + Object.keys(data) + .sort() + .map((key) => `${key},${data[key].join(',')}`) + .join('\n'); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_new_selected_prompt_context/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_new_selected_prompt_context/index.test.ts new file mode 100644 index 0000000000000..fb2577c91d097 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_new_selected_prompt_context/index.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PromptContext, SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { mockAlertPromptContext } from '../../mock/prompt_context'; +import { getNewSelectedPromptContext } from '.'; + +describe('getNewSelectedPromptContext', () => { + const defaultAllow = ['field1', 'field2']; + const defaultAllowReplacement = ['field3', 'field4']; + + it("returns empty `allow` and `allowReplacement` for string `rawData`, because it's not anonymized", async () => { + const promptContext: PromptContext = { + ...mockAlertPromptContext, + getPromptContext: () => Promise.resolve('string data'), // not anonymized + }; + + const result = await getNewSelectedPromptContext({ + defaultAllow, + defaultAllowReplacement, + promptContext, + }); + + const excepted: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: promptContext.id, + rawData: 'string data', + }; + + expect(result).toEqual(excepted); + }); + + it('returns `allow` and `allowReplacement` with the contents of `defaultAllow` and `defaultAllowReplacement` for object rawData, which is anonymized', async () => { + const promptContext: PromptContext = { + ...mockAlertPromptContext, + getPromptContext: () => Promise.resolve({ field1: ['value1'], field2: ['value2'] }), + }; + + const excepted: SelectedPromptContext = { + allow: [...defaultAllow], + allowReplacement: [...defaultAllowReplacement], + promptContextId: promptContext.id, + rawData: { field1: ['value1'], field2: ['value2'] }, + }; + + const result = await getNewSelectedPromptContext({ + defaultAllow, + defaultAllowReplacement, + promptContext, + }); + + expect(result).toEqual(excepted); + }); + + it('calls getPromptContext from the given promptContext', async () => { + const promptContext: PromptContext = { + ...mockAlertPromptContext, + getPromptContext: jest.fn(() => Promise.resolve('string data')), + }; + + await getNewSelectedPromptContext({ + defaultAllow, + defaultAllowReplacement, + promptContext, + }); + + expect(promptContext.getPromptContext).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_new_selected_prompt_context/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_new_selected_prompt_context/index.ts new file mode 100644 index 0000000000000..daf64ee590ae0 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/get_new_selected_prompt_context/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { PromptContext, SelectedPromptContext } from '../../assistant/prompt_context/types'; + +export async function getNewSelectedPromptContext({ + defaultAllow, + defaultAllowReplacement, + promptContext, +}: { + defaultAllow: string[]; + defaultAllowReplacement: string[]; + promptContext: PromptContext; +}): Promise { + const rawData = await promptContext.getPromptContext(); + + if (typeof rawData === 'string') { + return { + allow: [], + allowReplacement: [], + promptContextId: promptContext.id, + rawData, + }; + } else { + return { + allow: [...defaultAllow], + allowReplacement: [...defaultAllowReplacement], + promptContextId: promptContext.id, + rawData, + }; + } +} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.test.tsx new file mode 100644 index 0000000000000..583c0d8076a68 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.test.tsx @@ -0,0 +1,159 @@ +/* + * Copyright 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, fireEvent } from '@testing-library/react'; + +import { TestProviders } from '../../../mock/test_providers/test_providers'; +import { AnonymizationSettings } from '.'; + +const mockUseAssistantContext = { + allSystemPrompts: [ + { + id: 'default-system-prompt', + content: 'default', + name: 'default', + promptType: 'system', + isDefault: true, + isNewConversationDefault: true, + }, + { + id: 'CB9FA555-B59F-4F71-AFF9-8A891AC5BC28', + content: 'superhero', + name: 'superhero', + promptType: 'system', + isDefault: true, + }, + ], + baseAllow: ['@timestamp', 'event.category', 'user.name'], + baseAllowReplacement: ['user.name', 'host.ip'], + defaultAllow: ['foo', 'bar', 'baz', '@baz'], + defaultAllowReplacement: ['bar'], + setAllSystemPrompts: jest.fn(), + setDefaultAllow: jest.fn(), + setDefaultAllowReplacement: jest.fn(), +}; +jest.mock('../../../assistant_context', () => { + const original = jest.requireActual('../../../assistant_context'); + + return { + ...original, + useAssistantContext: () => mockUseAssistantContext, + }; +}); + +describe('AnonymizationSettings', () => { + const closeModal = jest.fn(); + + beforeEach(() => jest.clearAllMocks()); + + it('renders the editor', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('contextEditor')).toBeInTheDocument(); + }); + + it('does NOT call `setDefaultAllow` when `Reset` is clicked, because only local state is reset until the user clicks save', () => { + const { getByTestId } = render( + + + + ); + + fireEvent.click(getByTestId('reset')); + + expect(mockUseAssistantContext.setDefaultAllow).not.toHaveBeenCalled(); + }); + + it('does NOT call `setDefaultAllowReplacement` when `Reset` is clicked, because only local state is reset until the user clicks save', () => { + const { getByTestId } = render( + + + + ); + + fireEvent.click(getByTestId('reset')); + + expect(mockUseAssistantContext.setDefaultAllowReplacement).not.toHaveBeenCalled(); + }); + + it('renders the expected allowed stat content', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('allowedStat')).toHaveTextContent( + `${mockUseAssistantContext.defaultAllow.length}Allowed` + ); + }); + + it('renders the expected anonymized stat content', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('anonymizedFieldsStat')).toHaveTextContent( + `${mockUseAssistantContext.defaultAllowReplacement.length}Anonymized` + ); + }); + + it('calls closeModal is called when the cancel button is clicked', () => { + const { getByTestId } = render( + + + + ); + fireEvent.click(getByTestId('cancel')); + expect(closeModal).toHaveBeenCalledTimes(1); + }); + + it('calls closeModal is called when the save button is clicked', () => { + const { getByTestId } = render( + + + + ); + fireEvent.click(getByTestId('cancel')); + expect(closeModal).toHaveBeenCalledTimes(1); + }); + + it('calls setDefaultAllow with the expected values when the save button is clicked', () => { + const { getByTestId } = render( + + + + ); + + fireEvent.click(getByTestId('save')); + + expect(mockUseAssistantContext.setDefaultAllow).toHaveBeenCalledWith( + mockUseAssistantContext.defaultAllow + ); + }); + + it('calls setDefaultAllowReplacement with the expected values when the save button is clicked', () => { + const { getByTestId } = render( + + + + ); + + fireEvent.click(getByTestId('save')); + + expect(mockUseAssistantContext.setDefaultAllowReplacement).toHaveBeenCalledWith( + mockUseAssistantContext.defaultAllowReplacement + ); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.tsx new file mode 100644 index 0000000000000..e833276d4850d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/index.tsx @@ -0,0 +1,147 @@ +/* + * Copyright 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 { + EuiButton, + EuiButtonEmpty, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, +} from '@elastic/eui'; +import React, { useCallback, useMemo, useState } from 'react'; +// eslint-disable-next-line @kbn/eslint/module_migration +import styled from 'styled-components'; + +import { useAssistantContext } from '../../../assistant_context'; +import { ContextEditor } from '../../../data_anonymization_editor/context_editor'; +import type { BatchUpdateListItem } from '../../../data_anonymization_editor/context_editor/types'; +import { updateDefaults } from '../../../data_anonymization_editor/helpers'; +import { AllowedStat } from '../../../data_anonymization_editor/stats/allowed_stat'; +import { AnonymizedStat } from '../../../data_anonymization_editor/stats/anonymized_stat'; +import { CANCEL, SAVE } from '../anonymization_settings_modal/translations'; +import * as i18n from './translations'; + +const StatFlexItem = styled(EuiFlexItem)` + margin-right: ${({ theme }) => theme.eui.euiSizeL}; +`; + +interface Props { + closeModal?: () => void; +} + +const AnonymizationSettingsComponent: React.FC = ({ closeModal }) => { + const { + baseAllow, + baseAllowReplacement, + defaultAllow, + defaultAllowReplacement, + setDefaultAllow, + setDefaultAllowReplacement, + } = useAssistantContext(); + + // Local state for default allow and default allow replacement to allow for intermediate changes + const [localDefaultAllow, setLocalDefaultAllow] = useState(defaultAllow); + const [localDefaultAllowReplacement, setLocalDefaultAllowReplacement] = + useState(defaultAllowReplacement); + + const onListUpdated = useCallback( + (updates: BatchUpdateListItem[]) => { + updateDefaults({ + defaultAllow: localDefaultAllow, + defaultAllowReplacement: localDefaultAllowReplacement, + setDefaultAllow: setLocalDefaultAllow, + setDefaultAllowReplacement: setLocalDefaultAllowReplacement, + updates, + }); + }, + [localDefaultAllow, localDefaultAllowReplacement] + ); + + const onReset = useCallback(() => { + setLocalDefaultAllow(baseAllow); + setLocalDefaultAllowReplacement(baseAllowReplacement); + }, [baseAllow, baseAllowReplacement]); + + const onSave = useCallback(() => { + setDefaultAllow(localDefaultAllow); + setDefaultAllowReplacement(localDefaultAllowReplacement); + closeModal?.(); + }, [ + closeModal, + localDefaultAllow, + localDefaultAllowReplacement, + setDefaultAllow, + setDefaultAllowReplacement, + ]); + + const anonymized: number = useMemo(() => { + const allowSet = new Set(localDefaultAllow); + + return localDefaultAllowReplacement.reduce( + (acc, field) => (allowSet.has(field) ? acc + 1 : acc), + 0 + ); + }, [localDefaultAllow, localDefaultAllowReplacement]); + + return ( + <> + +

    {i18n.CALLOUT_PARAGRAPH1}

    + + {i18n.RESET} + +
    + + + + + + + + + + + + + + + + + + + {closeModal != null && ( + + + {CANCEL} + + + )} + + + + {SAVE} + + + + + ); +}; + +AnonymizationSettingsComponent.displayName = 'AnonymizationSettingsComponent'; + +export const AnonymizationSettings = React.memo(AnonymizationSettingsComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/translations.ts new file mode 100644 index 0000000000000..e7f82289dff78 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings/translations.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const CALLOUT_PARAGRAPH1 = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettings.calloutParagraph1', + { + defaultMessage: 'The fields below are allowed by default', + } +); + +export const CALLOUT_PARAGRAPH2 = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettings.calloutParagraph2', + { + defaultMessage: 'Optionally enable anonymization for these fields', + } +); + +export const CALLOUT_TITLE = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettings.calloutTitle', + { + defaultMessage: 'Anonymization defaults', + } +); + +export const RESET = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettings.resetButton', + { + defaultMessage: 'Reset', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/index.test.tsx new file mode 100644 index 0000000000000..35ee1a1bde473 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/index.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, fireEvent, screen } from '@testing-library/react'; + +import { AnonymizationSettingsModal } from '.'; +import { TestProviders } from '../../../mock/test_providers/test_providers'; + +describe('AnonymizationSettingsModal', () => { + const closeModal = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + + render( + + + + ); + }); + + it('renders the anonymizationSettings', () => { + expect(screen.getByTestId('anonymizationSettingsCallout')).toBeInTheDocument(); + }); + + it('calls closeModal when Cancel is clicked', () => { + fireEvent.click(screen.getByTestId('cancel')); + + expect(closeModal).toHaveBeenCalledTimes(1); + }); + + it('calls closeModal when Save is clicked', () => { + fireEvent.click(screen.getByTestId('save')); + + expect(closeModal).toHaveBeenCalledTimes(1); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/index.tsx new file mode 100644 index 0000000000000..ae4b395ca0d0e --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/index.tsx @@ -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 { EuiModal, EuiModalBody, EuiModalHeader } from '@elastic/eui'; +import React from 'react'; + +import { AnonymizationSettings } from '../anonymization_settings'; + +interface Props { + closeModal: () => void; +} + +const AnonymizationSettingsModalComponent: React.FC = ({ closeModal }) => ( + + + + + + +); + +export const AnonymizationSettingsModal = React.memo(AnonymizationSettingsModalComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/translations.ts new file mode 100644 index 0000000000000..d3da99dcf5052 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/anonymization_settings_modal/translations.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const ANONYMIZATION = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettingsModal.anonymizationModalTitle', + { + defaultMessage: 'Anonymization', + } +); + +export const CANCEL = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettingsModal.cancelButton', + { + defaultMessage: 'Cancel', + } +); + +export const SAVE = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.anonymizationSettingsModal.saveButton', + { + defaultMessage: 'Save', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/index.test.tsx new file mode 100644 index 0000000000000..3168c6a6b28dc --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/index.test.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 React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { TestProviders } from '../../../mock/test_providers/test_providers'; +import * as i18n from './translations'; +import { SettingsPopover } from '.'; + +describe('SettingsPopover', () => { + beforeEach(() => { + render( + + + + ); + }); + + it('renders the settings button', () => { + const settingsButton = screen.getByTestId('settings'); + + expect(settingsButton).toBeInTheDocument(); + }); + + it('opens the popover when the settings button is clicked', () => { + const settingsButton = screen.getByTestId('settings'); + + userEvent.click(settingsButton); + + const popover = screen.queryByText(i18n.ANONYMIZATION); + expect(popover).toBeInTheDocument(); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/index.tsx new file mode 100644 index 0000000000000..e623798e8c4dd --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/index.tsx @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiButtonIcon, + EuiContextMenu, + EuiContextMenuPanelDescriptor, + EuiPopover, + useGeneratedHtmlId, +} from '@elastic/eui'; +import React, { useCallback, useMemo, useState } from 'react'; +import { AnonymizationSettingsModal } from '../anonymization_settings_modal'; + +import * as i18n from './translations'; + +const SettingsPopoverComponent: React.FC = () => { + const [showAnonymizationSettingsModal, setShowAnonymizationSettingsModal] = useState(false); + const closeAnonymizationSettingsModal = useCallback( + () => setShowAnonymizationSettingsModal(false), + [] + ); + + const contextMenuPopoverId = useGeneratedHtmlId(); + + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + + const onButtonClick = useCallback(() => setIsPopoverOpen((prev) => !prev), []); + const button = useMemo( + () => ( + + ), + [onButtonClick] + ); + + const panels: EuiContextMenuPanelDescriptor[] = useMemo( + () => [ + { + id: 0, + items: [ + { + icon: 'eyeClosed', + name: i18n.ANONYMIZATION, + onClick: () => { + closePopover(); + + setShowAnonymizationSettingsModal(true); + }, + }, + ], + size: 's', + width: 150, + }, + ], + [closePopover] + ); + + return ( + <> + + + + + {showAnonymizationSettingsModal && ( + + )} + + ); +}; + +SettingsPopoverComponent.displayName = 'SettingsPopoverComponent'; + +export const SettingsPopover = React.memo(SettingsPopoverComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/translations.ts new file mode 100644 index 0000000000000..4fcbcfcfa596b --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/settings/settings_popover/translations.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 { i18n } from '@kbn/i18n'; + +export const ANONYMIZATION = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.settingsPopover.anonymizationMenuItem', + { + defaultMessage: 'Anonymization', + } +); + +export const SETTINGS = i18n.translate( + 'xpack.elasticAssistant.dataAnonymization.settings.settingsPopover.settingsAriaLabel', + { + defaultMessage: 'Settings', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.test.tsx new file mode 100644 index 0000000000000..48caf7ca226dc --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.test.tsx @@ -0,0 +1,90 @@ +/* + * Copyright 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 { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { mockGetAnonymizedValue } from '../../mock/get_anonymized_value'; +import { transformRawData } from '.'; + +describe('transformRawData', () => { + it('returns non-anonymized data when rawData is a string', () => { + const inputRawData: SelectedPromptContext = { + allow: ['field1'], + allowReplacement: ['field1', 'field2'], + promptContextId: 'abcd', + rawData: 'this will not be anonymized', + }; + + const result = transformRawData({ + currentReplacements: {}, + getAnonymizedValue: mockGetAnonymizedValue, + onNewReplacements: () => {}, + selectedPromptContext: inputRawData, + }); + + expect(result).toEqual('this will not be anonymized'); + }); + + it('calls onNewReplacements with the expected replacements', () => { + const inputRawData: SelectedPromptContext = { + allow: ['field1'], + allowReplacement: ['field1'], + promptContextId: 'abcd', + rawData: { field1: ['value1'] }, + }; + + const onNewReplacements = jest.fn(); + + transformRawData({ + currentReplacements: {}, + getAnonymizedValue: mockGetAnonymizedValue, + onNewReplacements, + selectedPromptContext: inputRawData, + }); + + expect(onNewReplacements).toHaveBeenCalledWith({ '1eulav': 'value1' }); + }); + + it('returns the expected mix of anonymized and non-anonymized data as a CSV string', () => { + const inputRawData: SelectedPromptContext = { + allow: ['field1', 'field2'], + allowReplacement: ['field1'], // only field 1 will be anonymized + promptContextId: 'abcd', + rawData: { field1: ['value1', 'value2'], field2: ['value3', 'value4'] }, + }; + + const result = transformRawData({ + currentReplacements: {}, + getAnonymizedValue: mockGetAnonymizedValue, + onNewReplacements: () => {}, + selectedPromptContext: inputRawData, + }); + + expect(result).toEqual('field1,1eulav,2eulav\nfield2,value3,value4'); // only field 1 is anonymized + }); + + it('omits fields that are not included in the `allow` list, even if they are members of `allowReplacement`', () => { + const inputRawData: SelectedPromptContext = { + allow: ['field1', 'field2'], // field3 is NOT allowed + allowReplacement: ['field1', 'field3'], // field3 is requested to be anonymized + promptContextId: 'abcd', + rawData: { + field1: ['value1', 'value2'], + field2: ['value3', 'value4'], + field3: ['value5', 'value6'], // this data should NOT be included in the output + }, + }; + + const result = transformRawData({ + currentReplacements: {}, + getAnonymizedValue: mockGetAnonymizedValue, + onNewReplacements: () => {}, + selectedPromptContext: inputRawData, + }); + + expect(result).toEqual('field1,1eulav,2eulav\nfield2,value3,value4'); // field 3 is not included + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.tsx new file mode 100644 index 0000000000000..c478b0ab39f68 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/transform_raw_data/index.tsx @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { getAnonymizedData } from '../get_anonymized_data'; +import { getAnonymizedValues } from '../get_anonymized_values'; +import { getCsvFromData } from '../get_csv_from_data'; + +export const transformRawData = ({ + currentReplacements, + getAnonymizedValue, + onNewReplacements, + selectedPromptContext, +}: { + currentReplacements: Record | undefined; + getAnonymizedValue: ({ + currentReplacements, + rawValue, + }: { + currentReplacements: Record | undefined; + rawValue: string; + }) => string; + onNewReplacements?: (replacements: Record) => void; + selectedPromptContext: SelectedPromptContext; +}): string => { + if (typeof selectedPromptContext.rawData === 'string') { + return selectedPromptContext.rawData; + } + + const anonymizedData = getAnonymizedData({ + allow: selectedPromptContext.allow, + allowReplacement: selectedPromptContext.allowReplacement, + currentReplacements, + rawData: selectedPromptContext.rawData, + getAnonymizedValue, + getAnonymizedValues, + }); + + if (onNewReplacements != null) { + onNewReplacements(anonymizedData.replacements); + } + + return getCsvFromData(anonymizedData.anonymizedData); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/types.ts new file mode 100644 index 0000000000000..59ca12414b640 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization/types.ts @@ -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. + */ + +export interface AnonymizedValues { + /** The original values were transformed to these anonymized values */ + anonymizedValues: string[]; + + /** A map from replacement value to original value */ + replacements: Record; +} + +export interface AnonymizedData { + /** The original data was transformed to this anonymized data */ + anonymizedData: Record; + + /** A map from replacement value to original value */ + replacements: Record; +} + +export type GetAnonymizedValues = ({ + allowReplacementSet, + allowSet, + currentReplacements, + field, + getAnonymizedValue, + rawData, +}: { + allowReplacementSet: Set; + allowSet: Set; + currentReplacements: Record | undefined; + field: string; + getAnonymizedValue: ({ + currentReplacements, + rawValue, + }: { + currentReplacements: Record | undefined; + rawValue: string; + }) => string; + rawData: Record; +}) => AnonymizedValues; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/bulk_actions/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/bulk_actions/index.test.tsx new file mode 100644 index 0000000000000..ec2f276f6f4bd --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/bulk_actions/index.test.tsx @@ -0,0 +1,139 @@ +/* + * Copyright 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, fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { BulkActions } from '.'; + +const selected = [ + { + allowed: true, + anonymized: false, + denied: false, + field: 'process.args', + rawValues: ['abc', 'def'], + }, + { + allowed: false, + anonymized: true, + denied: true, + field: 'user.name', + rawValues: ['fooUser'], + }, +]; + +const defaultProps = { + appliesTo: 'multipleRows' as const, + disabled: false, + onListUpdated: jest.fn(), + onlyDefaults: false, + selected, +}; + +describe('BulkActions', () => { + beforeEach(() => jest.clearAllMocks()); + + it('calls onListUpdated with the expected updates when Allow is clicked', () => { + const { getByTestId, getByText } = render(); + + userEvent.click(getByTestId('bulkActionsButton')); + fireEvent.click(getByText(/^Allow$/)); + + expect(defaultProps.onListUpdated).toBeCalledWith([ + { field: 'process.args', operation: 'add', update: 'allow' }, + { field: 'user.name', operation: 'add', update: 'allow' }, + ]); + }); + + it('calls onListUpdated with the expected updates when Deny is clicked', () => { + const { getByTestId, getByText } = render(); + + userEvent.click(getByTestId('bulkActionsButton')); + fireEvent.click(getByText(/^Deny$/)); + + expect(defaultProps.onListUpdated).toBeCalledWith([ + { field: 'process.args', operation: 'remove', update: 'allow' }, + { field: 'user.name', operation: 'remove', update: 'allow' }, + ]); + }); + + it('calls onListUpdated with the expected updates when Anonymize is clicked', () => { + const { getByTestId, getByText } = render(); + + userEvent.click(getByTestId('bulkActionsButton')); + fireEvent.click(getByText(/^Anonymize$/)); + + expect(defaultProps.onListUpdated).toBeCalledWith([ + { field: 'process.args', operation: 'add', update: 'allowReplacement' }, + { field: 'user.name', operation: 'add', update: 'allowReplacement' }, + ]); + }); + + it('calls onListUpdated with the expected updates when Unanonymize is clicked', () => { + const { getByTestId, getByText } = render(); + + userEvent.click(getByTestId('bulkActionsButton')); + fireEvent.click(getByText(/^Unanonymize$/)); + + expect(defaultProps.onListUpdated).toBeCalledWith([ + { field: 'process.args', operation: 'remove', update: 'allowReplacement' }, + { field: 'user.name', operation: 'remove', update: 'allowReplacement' }, + ]); + }); + + it('calls onListUpdated with the expected updates when Deny by default is clicked', () => { + const { getByTestId, getByText } = render( + + ); + + userEvent.click(getByTestId('bulkActionsButton')); + fireEvent.click(getByText(/^Deny by default$/)); + + expect(defaultProps.onListUpdated).toBeCalledWith([ + { field: 'process.args', operation: 'remove', update: 'allow' }, + { field: 'user.name', operation: 'remove', update: 'allow' }, + { field: 'process.args', operation: 'remove', update: 'defaultAllow' }, + { field: 'user.name', operation: 'remove', update: 'defaultAllow' }, + ]); + }); + + it('calls onListUpdated with the expected updates when Anonymize by default is clicked', () => { + const { getByTestId, getByText } = render( + + ); + + userEvent.click(getByTestId('bulkActionsButton')); + fireEvent.click(getByText(/^Defaults$/)); + fireEvent.click(getByText(/^Anonymize by default$/)); + + expect(defaultProps.onListUpdated).toBeCalledWith([ + { field: 'process.args', operation: 'add', update: 'allowReplacement' }, + { field: 'user.name', operation: 'add', update: 'allowReplacement' }, + { field: 'process.args', operation: 'add', update: 'defaultAllowReplacement' }, + { field: 'user.name', operation: 'add', update: 'defaultAllowReplacement' }, + ]); + }); + + it('calls onListUpdated with the expected updates when Unanonymize by default is clicked', () => { + const { getByTestId, getByText } = render( + + ); + + userEvent.click(getByTestId('bulkActionsButton')); + fireEvent.click(getByText(/^Defaults$/)); + fireEvent.click(getByText(/^Unanonymize by default$/)); + + expect(defaultProps.onListUpdated).toBeCalledWith([ + { field: 'process.args', operation: 'remove', update: 'allowReplacement' }, + { field: 'user.name', operation: 'remove', update: 'allowReplacement' }, + { field: 'process.args', operation: 'remove', update: 'defaultAllowReplacement' }, + { field: 'user.name', operation: 'remove', update: 'defaultAllowReplacement' }, + ]); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/bulk_actions/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/bulk_actions/index.tsx new file mode 100644 index 0000000000000..3511ee2118a89 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/bulk_actions/index.tsx @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiButtonEmpty, + EuiContextMenu, + EuiContextMenuPanelDescriptor, + EuiPopover, + EuiToolTip, + useGeneratedHtmlId, +} from '@elastic/eui'; + +import React, { useCallback, useMemo, useState } from 'react'; +import { getContextMenuPanels, PRIMARY_PANEL_ID } from '../get_context_menu_panels'; +import * as i18n from '../translations'; +import { BatchUpdateListItem, ContextEditorRow } from '../types'; + +export interface Props { + appliesTo: 'multipleRows' | 'singleRow'; + disabled: boolean; + disableAllow?: boolean; + disableAnonymize?: boolean; + disableDeny?: boolean; + disableUnanonymize?: boolean; + onListUpdated: (updates: BatchUpdateListItem[]) => void; + onlyDefaults: boolean; + selected: ContextEditorRow[]; +} + +const BulkActionsComponent: React.FC = ({ + appliesTo, + disabled, + disableAllow = false, + disableAnonymize = false, + disableDeny = false, + disableUnanonymize = false, + onListUpdated, + onlyDefaults, + selected, +}) => { + const [isPopoverOpen, setPopover] = useState(false); + + const contextMenuPopoverId = useGeneratedHtmlId({ + prefix: 'contextEditorBulkActions', + }); + + const closePopover = useCallback(() => setPopover(false), []); + + const onButtonClick = useCallback(() => setPopover((isOpen) => !isOpen), []); + + const button = useMemo( + () => ( + + + {appliesTo === 'multipleRows' ? i18n.BULK_ACTIONS : null} + + + ), + [appliesTo, disabled, onButtonClick] + ); + + const panels: EuiContextMenuPanelDescriptor[] = useMemo( + () => + getContextMenuPanels({ + disableAllow, + disableAnonymize, + disableDeny, + disableUnanonymize, + closePopover, + onListUpdated, + onlyDefaults, + selected, + }), + [ + closePopover, + disableAllow, + disableAnonymize, + disableDeny, + disableUnanonymize, + onListUpdated, + onlyDefaults, + selected, + ] + ); + + return ( + + + + ); +}; + +export const BulkActions = React.memo(BulkActionsComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.test.tsx new file mode 100644 index 0000000000000..1f6590d576c30 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.test.tsx @@ -0,0 +1,318 @@ +/* + * Copyright 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 { EuiBasicTableColumn } from '@elastic/eui'; +import { fireEvent, render, screen } from '@testing-library/react'; +import React from 'react'; + +import { TestProviders } from '../../../mock/test_providers/test_providers'; +import { ContextEditorRow } from '../types'; +import { getColumns } from '.'; + +interface ColumnWithRender { + render: (_: unknown, row: ContextEditorRow) => React.ReactNode; +} + +const fieldIsNotAllowed: ContextEditorRow = { + allowed: false, // the field is not allowed + anonymized: false, + denied: false, + field: 'event.category', + rawValues: ['authentication'], +}; + +const fieldIsAllowedButNotAnonymized: ContextEditorRow = { + allowed: true, // the field is allowed + anonymized: false, + denied: false, + field: 'event.category', + rawValues: ['authentication'], +}; + +const rowWhereFieldIsAnonymized: ContextEditorRow = { + allowed: true, + anonymized: true, // the field is anonymized + denied: false, + field: 'user.name', + rawValues: ['rawUsername'], +}; + +describe('getColumns', () => { + const onListUpdated = jest.fn(); + const rawData: Record = { + 'field.name': ['value1', 'value2'], + }; + + const row: ContextEditorRow = { + allowed: true, + anonymized: false, + denied: false, + field: 'event.category', + rawValues: ['authentication'], + }; + + it('includes the values column when rawData is NOT null', () => { + const columns: Array & { field?: string }> = getColumns({ + onListUpdated, + rawData, + }); + + expect(columns.some(({ field }) => field === 'rawValues')).toBe(true); + }); + + it('does NOT include the values column when rawData is null', () => { + const columns: Array & { field?: string }> = getColumns({ + onListUpdated, + rawData: null, + }); + + expect(columns.some(({ field }) => field === 'rawValues')).toBe(false); + }); + + describe('allowed column render()', () => { + it('calls onListUpdated with a `remove` operation when the toggle is clicked on field that is allowed', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[0] as ColumnWithRender; + const allowedRow = { + ...row, + allowed: true, // the field is allowed + }; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, allowedRow)} + + ); + + fireEvent.click(getByTestId('allowed')); + + expect(onListUpdated).toBeCalledWith([ + { field: 'event.category', operation: 'remove', update: 'allow' }, + ]); + }); + + it('calls onListUpdated with an `add` operation when the toggle is clicked on a field that is NOT allowed', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[0] as ColumnWithRender; + const notAllowedRow = { + ...row, + allowed: false, // the field is NOT allowed + }; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, notAllowedRow)} + + ); + + fireEvent.click(getByTestId('allowed')); + + expect(onListUpdated).toBeCalledWith([ + { field: 'event.category', operation: 'add', update: 'allow' }, + ]); + }); + + it('calls onListUpdated with a `remove` operation to update the `defaultAllowReplacement` list when the toggle is clicked on a default field that is allowed', () => { + const columns = getColumns({ onListUpdated, rawData: null }); // null raw data means the field is a default field + const anonymizedColumn: ColumnWithRender = columns[0] as ColumnWithRender; + const allowedRow = { + ...row, + allowed: true, // the field is allowed + }; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, allowedRow)} + + ); + + fireEvent.click(getByTestId('allowed')); + + expect(onListUpdated).toBeCalledWith([ + { field: 'event.category', operation: 'remove', update: 'defaultAllowReplacement' }, + ]); + }); + }); + + describe('anonymized column render()', () => { + it('disables the button when the field is not allowed', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, fieldIsNotAllowed)} + + ); + + expect(getByTestId('anonymized')).toBeDisabled(); + }); + + it('enables the button when the field is allowed', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, fieldIsAllowedButNotAnonymized)} + + ); + + expect(getByTestId('anonymized')).not.toBeDisabled(); + }); + + it('calls onListUpdated with an `add` operation when an unanonymized field is toggled', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, row)} + + ); + + fireEvent.click(getByTestId('anonymized')); + + expect(onListUpdated).toBeCalledWith([ + { field: 'event.category', operation: 'add', update: 'allowReplacement' }, + ]); + }); + + it('calls onListUpdated with a `remove` operation when an anonymized field is toggled', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const anonymizedRow = { + ...row, + anonymized: true, + }; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, anonymizedRow)} + + ); + + fireEvent.click(getByTestId('anonymized')); + + expect(onListUpdated).toBeCalledWith([ + { field: 'event.category', operation: 'remove', update: 'allowReplacement' }, + ]); + }); + + it('calls onListUpdated with an update to the `defaultAllowReplacement` list when rawData is null, because the field is a default', () => { + const columns = getColumns({ onListUpdated, rawData: null }); // null raw data means the field is a default field + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, row)} + + ); + + fireEvent.click(getByTestId('anonymized')); + + expect(onListUpdated).toBeCalledWith([ + { field: 'event.category', operation: 'add', update: 'allowReplacement' }, + ]); + }); + + it('displays a closed eye icon when the field is anonymized', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { container } = render( + + <>{anonymizedColumn.render(undefined, rowWhereFieldIsAnonymized)} + + ); + + expect(container.getElementsByClassName('euiButtonContent__icon')[0]).toHaveAttribute( + 'data-euiicon-type', + 'eyeClosed' + ); + }); + + it('displays a open eye icon when the field is NOT anonymized', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { container } = render( + + <>{anonymizedColumn.render(undefined, fieldIsAllowedButNotAnonymized)} + + ); + + expect(container.getElementsByClassName('euiButtonContent__icon')[0]).toHaveAttribute( + 'data-euiicon-type', + 'eye' + ); + }); + + it('displays Yes when the field is anonymized', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, rowWhereFieldIsAnonymized)} + + ); + + expect(getByTestId('anonymized')).toHaveTextContent('Yes'); + }); + + it('displays No when the field is NOT anonymized', () => { + const columns = getColumns({ onListUpdated, rawData }); + const anonymizedColumn: ColumnWithRender = columns[1] as ColumnWithRender; + + const { getByTestId } = render( + + <>{anonymizedColumn.render(undefined, fieldIsAllowedButNotAnonymized)} + + ); + + expect(getByTestId('anonymized')).toHaveTextContent('No'); + }); + }); + + describe('values column render()', () => { + it('joins values with a comma', () => { + const columns = getColumns({ onListUpdated, rawData }); + const valuesColumn: ColumnWithRender = columns[3] as ColumnWithRender; + + const rowWithMultipleValues = { + ...row, + field: 'user.name', + rawValues: ['abe', 'bart'], + }; + + render( + + <>{valuesColumn.render(rowWithMultipleValues.rawValues, rowWithMultipleValues)} + + ); + + expect(screen.getByTestId('rawValues')).toHaveTextContent('abe,bart'); + }); + }); + + describe('actions column render()', () => { + it('renders the bulk actions', () => { + const columns = getColumns({ onListUpdated, rawData }); + const actionsColumn: ColumnWithRender = columns[4] as ColumnWithRender; + + render( + + <>{actionsColumn.render(null, row)} + + ); + + expect(screen.getByTestId('bulkActions')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.tsx new file mode 100644 index 0000000000000..75fd3e6d633eb --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_columns/index.tsx @@ -0,0 +1,132 @@ +/* + * Copyright 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 { EuiBasicTableColumn, EuiButtonEmpty, EuiCode, EuiSwitch, EuiText } from '@elastic/eui'; +import React from 'react'; +// eslint-disable-next-line @kbn/eslint/module_migration +import styled from 'styled-components'; + +import { BulkActions } from '../bulk_actions'; +import * as i18n from '../translations'; +import { BatchUpdateListItem, ContextEditorRow, FIELDS } from '../types'; + +const AnonymizedButton = styled(EuiButtonEmpty)` + max-height: 24px; +`; + +export const getColumns = ({ + onListUpdated, + rawData, +}: { + onListUpdated: (updates: BatchUpdateListItem[]) => void; + rawData: Record | null; +}): Array> => { + const actionsColumn: EuiBasicTableColumn = { + field: FIELDS.ACTIONS, + name: '', + render: (_, row) => { + return ( + + ); + }, + sortable: false, + width: '36px', + }; + + const valuesColumn: EuiBasicTableColumn = { + field: FIELDS.RAW_VALUES, + name: i18n.VALUES, + render: (rawValues: ContextEditorRow['rawValues']) => ( + {rawValues.join(',')} + ), + sortable: false, + }; + + const baseColumns: Array> = [ + { + field: FIELDS.ALLOWED, + name: i18n.ALLOWED, + render: (_, { allowed, field }) => ( + { + onListUpdated([ + { + field, + operation: allowed ? 'remove' : 'add', + update: rawData == null ? 'defaultAllow' : 'allow', + }, + ]); + + if (rawData == null && allowed) { + // when editing defaults, remove the default replacement if the field is no longer allowed + onListUpdated([ + { + field, + operation: 'remove', + update: 'defaultAllowReplacement', + }, + ]); + } + }} + /> + ), + sortable: true, + width: '75px', + }, + { + field: FIELDS.ANONYMIZED, + name: i18n.ANONYMIZED, + render: (_, { allowed, anonymized, field }) => ( + + onListUpdated([ + { + field, + operation: anonymized ? 'remove' : 'add', + update: rawData == null ? 'defaultAllowReplacement' : 'allowReplacement', + }, + ]) + } + > + {anonymized ? i18n.YES : i18n.NO} + + ), + sortable: true, + width: '102px', + }, + { + field: FIELDS.FIELD, + name: i18n.FIELD, + sortable: true, + width: '260px', + }, + ]; + + return rawData == null + ? [...baseColumns, actionsColumn] + : [...baseColumns, valuesColumn, actionsColumn]; +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_context_menu_panels/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_context_menu_panels/index.test.ts new file mode 100644 index 0000000000000..e5cc77e1cd759 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_context_menu_panels/index.test.ts @@ -0,0 +1,677 @@ +/* + * Copyright 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 { getContextMenuPanels, PRIMARY_PANEL_ID, SECONDARY_PANEL_ID } from '.'; +import * as i18n from '../translations'; +import { ContextEditorRow } from '../types'; + +describe('getContextMenuPanels', () => { + const closePopover = jest.fn(); + const onListUpdated = jest.fn(); + const selected: ContextEditorRow[] = [ + { + allowed: true, + anonymized: true, + denied: false, + field: 'user.name', + rawValues: ['jodi'], + }, + ]; + + beforeEach(() => jest.clearAllMocks()); + + it('the first panel has a `primary-panel-id` when onlyDefaults is true', () => { + const onlyDefaults = true; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults, + }); + + expect(panels[0].id).toEqual(PRIMARY_PANEL_ID); + }); + + it('the first panel also has a `primary-panel-id` when onlyDefaults is false', () => { + const onlyDefaults = false; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults, + }); + + expect(panels[0].id).toEqual(PRIMARY_PANEL_ID); // first panel is always the primary panel + }); + + it('the second panel has a `secondary-panel-id` when onlyDefaults is false', () => { + const onlyDefaults = false; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults, + }); + + expect(panels[1].id).toEqual(SECONDARY_PANEL_ID); + }); + + it('the second panel is not rendered when onlyDefaults is true', () => { + const onlyDefaults = true; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults, + }); + + expect(panels.length).toEqual(1); + }); + + describe('allow by default', () => { + it('calls closePopover when allow by default is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const allowByDefaultItem = panels[1].items?.find( + (item) => item.name === i18n.ALLOW_BY_DEFAULT + ); + + allowByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to add the field to both the `allow` and `defaultAllow` lists', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const allowByDefaultItem = panels[1].items?.find( + (item) => item.name === i18n.ALLOW_BY_DEFAULT + ); + + allowByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'add', update: 'allow' }, + { field: 'user.name', operation: 'add', update: 'defaultAllow' }, + ]); + }); + }); + + describe('deny by default', () => { + it('calls closePopover when deny by default is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const denyByDefaultItem = panels[1].items?.find((item) => item.name === i18n.DENY_BY_DEFAULT); + + denyByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to remove the field from both the `allow` and `defaultAllow` lists', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const denyByDefaultItem = panels[1].items?.find((item) => item.name === i18n.DENY_BY_DEFAULT); + + denyByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'remove', update: 'allow' }, + { field: 'user.name', operation: 'remove', update: 'defaultAllow' }, + ]); + }); + }); + + describe('anonymize by default', () => { + it('calls closePopover when anonymize by default is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const anonymizeByDefaultItem = panels[1].items?.find( + (item) => item.name === i18n.ANONYMIZE_BY_DEFAULT + ); + + anonymizeByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to add the field to both the `allowReplacement` and `defaultAllowReplacement` lists', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const anonymizeByDefaultItem = panels[1].items?.find( + (item) => item.name === i18n.ANONYMIZE_BY_DEFAULT + ); + + anonymizeByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'add', update: 'allowReplacement' }, + { field: 'user.name', operation: 'add', update: 'defaultAllowReplacement' }, + ]); + }); + }); + + describe('unanonymize by default', () => { + it('calls closePopover when unanonymize by default is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const unAnonymizeByDefaultItem = panels[1].items?.find( + (item) => item.name === i18n.UNANONYMIZE_BY_DEFAULT + ); + + unAnonymizeByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to remove the field from both the `allowReplacement` and `defaultAllowReplacement` lists', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const unAnonymizeByDefaultItem = panels[1].items?.find( + (item) => item.name === i18n.UNANONYMIZE_BY_DEFAULT + ); + + unAnonymizeByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'remove', update: 'allowReplacement' }, + { field: 'user.name', operation: 'remove', update: 'defaultAllowReplacement' }, + ]); + }); + }); + + describe('allow', () => { + it('is disabled when `disableAlow` is true', () => { + const disableAllow = true; + + const panels = getContextMenuPanels({ + disableAllow, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const allowItem = panels[0].items?.find((item) => item.name === i18n.ALLOW); + + expect(allowItem?.disabled).toBe(true); + }); + + it('is NOT disabled when `disableAlow` is false', () => { + const disableAllow = false; + + const panels = getContextMenuPanels({ + disableAllow, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const allowItem = panels[0].items?.find((item) => item.name === i18n.ALLOW); + + expect(allowItem?.disabled).toBe(false); + }); + + it('calls closePopover when allow is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const allowItem = panels[0].items?.find((item) => item.name === i18n.ALLOW); + + allowItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to add the field to the `allow` list', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const allowItem = panels[0].items?.find((item) => item.name === i18n.ALLOW); + + allowItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'add', update: 'allow' }, + ]); + }); + }); + + describe('deny', () => { + it('is disabled when `disableDeny` is true', () => { + const disableDeny = true; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const denyItem = panels[0].items?.find((item) => item.name === i18n.DENY); + + expect(denyItem?.disabled).toBe(true); + }); + + it('is NOT disabled when `disableDeny` is false', () => { + const disableDeny = false; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const denyItem = panels[0].items?.find((item) => item.name === i18n.DENY); + + expect(denyItem?.disabled).toBe(false); + }); + + it('calls closePopover when deny is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const denyByDefaultItem = panels[0].items?.find((item) => item.name === i18n.DENY); + + denyByDefaultItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to remove the field from the `allow` list', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const denyItem = panels[0].items?.find((item) => item.name === i18n.DENY); + + denyItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'remove', update: 'allow' }, + ]); + }); + }); + + describe('anonymize', () => { + it('is disabled when `disableAnonymize` is true', () => { + const disableAnonymize = true; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const anonymizeItem = panels[0].items?.find((item) => item.name === i18n.ANONYMIZE); + + expect(anonymizeItem?.disabled).toBe(true); + }); + + it('is NOT disabled when `disableAnonymize` is false', () => { + const disableAnonymize = false; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const anonymizeItem = panels[0].items?.find((item) => item.name === i18n.ANONYMIZE); + + expect(anonymizeItem?.disabled).toBe(false); + }); + + it('calls closePopover when anonymize is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const anonymizeItem = panels[0].items?.find((item) => item.name === i18n.ANONYMIZE); + + anonymizeItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to add the field to both the `allowReplacement` and `defaultAllowReplacement` lists', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const anonymizeItem = panels[0].items?.find((item) => item.name === i18n.ANONYMIZE); + + anonymizeItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'add', update: 'allowReplacement' }, + ]); + }); + }); + + describe('unanonymize', () => { + it('is disabled when `disableUnanonymize` is true', () => { + const disableUnanonymize = true; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const unanonymizeItem = panels[0].items?.find((item) => item.name === i18n.UNANONYMIZE); + + expect(unanonymizeItem?.disabled).toBe(true); + }); + + it('is NOT disabled when `disableUnanonymize` is false', () => { + const disableUnanonymize = false; + + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const unanonymizeItem = panels[0].items?.find((item) => item.name === i18n.UNANONYMIZE); + + expect(unanonymizeItem?.disabled).toBe(false); + }); + + it('calls closePopover when unanonymize is clicked', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const unAnonymizeItem = panels[0].items?.find((item) => item.name === i18n.UNANONYMIZE); + + unAnonymizeItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(closePopover).toHaveBeenCalled(); + }); + + it('calls onListUpdated to remove the field from the `allowReplacement` list', () => { + const panels = getContextMenuPanels({ + disableAllow: false, + disableAnonymize: false, + disableDeny: false, + disableUnanonymize: false, + closePopover, + onListUpdated, + selected, + onlyDefaults: false, + }); + + const unAnonymizeItem = panels[0].items?.find((item) => item.name === i18n.UNANONYMIZE); + + unAnonymizeItem?.onClick!( + new MouseEvent('click', { bubbles: true }) as unknown as React.MouseEvent< + HTMLHRElement, + MouseEvent + > + ); + + expect(onListUpdated).toHaveBeenCalledWith([ + { field: 'user.name', operation: 'remove', update: 'allowReplacement' }, + ]); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_context_menu_panels/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_context_menu_panels/index.ts new file mode 100644 index 0000000000000..a6afe0984d6e3 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_context_menu_panels/index.ts @@ -0,0 +1,223 @@ +/* + * Copyright 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 { EuiContextMenuPanelDescriptor } from '@elastic/eui'; + +import * as i18n from '../translations'; +import { BatchUpdateListItem, ContextEditorRow } from '../types'; + +export const PRIMARY_PANEL_ID = 'primary-panel-id'; +export const SECONDARY_PANEL_ID = 'secondary-panel-id'; + +export const getContextMenuPanels = ({ + disableAllow, + disableAnonymize, + disableDeny, + disableUnanonymize, + closePopover, + onListUpdated, + onlyDefaults, + selected, +}: { + disableAllow: boolean; + disableAnonymize: boolean; + disableDeny: boolean; + disableUnanonymize: boolean; + closePopover: () => void; + onListUpdated: (updates: BatchUpdateListItem[]) => void; + selected: ContextEditorRow[]; + onlyDefaults: boolean; +}): EuiContextMenuPanelDescriptor[] => { + const defaultsPanelId = onlyDefaults ? PRIMARY_PANEL_ID : SECONDARY_PANEL_ID; + const nonDefaultsPanelId = onlyDefaults ? SECONDARY_PANEL_ID : PRIMARY_PANEL_ID; + + const allowByDefault = [ + !onlyDefaults + ? { + icon: 'check', + name: i18n.ALLOW_BY_DEFAULT, + onClick: () => { + closePopover(); + + const updateAllow = selected.map(({ field }) => ({ + field, + operation: 'add', + update: 'allow', + })); + + const updateDefaultAllow = selected.map(({ field }) => ({ + field, + operation: 'add', + update: 'defaultAllow', + })); + + onListUpdated([...updateAllow, ...updateDefaultAllow]); + }, + } + : [], + ].flat(); + + const defaultsPanelItems: EuiContextMenuPanelDescriptor[] = [ + { + id: defaultsPanelId, + title: i18n.DEFAULTS, + items: [ + ...allowByDefault, + { + icon: 'cross', + name: i18n.DENY_BY_DEFAULT, + onClick: () => { + closePopover(); + + const updateAllow = selected.map(({ field }) => ({ + field, + operation: 'remove', + update: 'allow', + })); + + const updateDefaultAllow = selected.map(({ field }) => ({ + field, + operation: 'remove', + update: 'defaultAllow', + })); + + onListUpdated([...updateAllow, ...updateDefaultAllow]); + }, + }, + { + icon: 'eyeClosed', + name: i18n.ANONYMIZE_BY_DEFAULT, + onClick: () => { + closePopover(); + + const updateAllowReplacement = selected.map(({ field }) => ({ + field, + operation: 'add', + update: 'allowReplacement', + })); + + const updateDefaultAllowReplacement = selected.map( + ({ field }) => ({ + field, + operation: 'add', + update: 'defaultAllowReplacement', + }) + ); + + onListUpdated([...updateAllowReplacement, ...updateDefaultAllowReplacement]); + }, + }, + { + icon: 'eye', + name: i18n.UNANONYMIZE_BY_DEFAULT, + onClick: () => { + closePopover(); + + const updateAllowReplacement = selected.map(({ field }) => ({ + field, + operation: 'remove', + update: 'allowReplacement', + })); + + const updateDefaultAllowReplacement = selected.map( + ({ field }) => ({ + field, + operation: 'remove', + update: 'defaultAllowReplacement', + }) + ); + + onListUpdated([...updateAllowReplacement, ...updateDefaultAllowReplacement]); + }, + }, + ], + }, + ]; + + const nonDefaultsPanelItems: EuiContextMenuPanelDescriptor[] = [ + { + id: nonDefaultsPanelId, + items: [ + { + disabled: disableAllow, + icon: 'check', + name: i18n.ALLOW, + onClick: () => { + closePopover(); + + const updates = selected.map(({ field }) => ({ + field, + operation: 'add', + update: 'allow', + })); + + onListUpdated(updates); + }, + }, + { + disabled: disableDeny, + icon: 'cross', + name: i18n.DENY, + onClick: () => { + closePopover(); + + const updates = selected.map(({ field }) => ({ + field, + operation: 'remove', + update: 'allow', + })); + + onListUpdated(updates); + }, + }, + { + disabled: disableAnonymize, + icon: 'eyeClosed', + name: i18n.ANONYMIZE, + onClick: () => { + closePopover(); + + const updates = selected.map(({ field }) => ({ + field, + operation: 'add', + update: 'allowReplacement', + })); + + onListUpdated(updates); + }, + }, + { + disabled: disableUnanonymize, + icon: 'eye', + name: i18n.UNANONYMIZE, + onClick: () => { + closePopover(); + + const updates = selected.map(({ field }) => ({ + field, + operation: 'remove', + update: 'allowReplacement', + })); + + onListUpdated(updates); + }, + }, + { + isSeparator: true, + key: 'sep', + }, + { + name: i18n.DEFAULTS, + panel: defaultsPanelId, + }, + ], + }, + ...defaultsPanelItems, + ]; + + return onlyDefaults ? defaultsPanelItems : nonDefaultsPanelItems; +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.test.ts new file mode 100644 index 0000000000000..c8c35767f1e54 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.test.ts @@ -0,0 +1,95 @@ +/* + * Copyright 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 { SelectedPromptContext } from '../../../assistant/prompt_context/types'; +import { ContextEditorRow } from '../types'; +import { getRows } from '.'; + +describe('getRows', () => { + const defaultArgs: { + allow: SelectedPromptContext['allow']; + allowReplacement: SelectedPromptContext['allowReplacement']; + rawData: Record | null; + } = { + allow: ['event.action', 'user.name', 'other.field'], // other.field is not in the rawData + allowReplacement: ['user.name', 'host.ip'], // host.ip is not in the rawData + rawData: { + 'event.category': ['process'], // event.category is not in the allow list, nor is it in the allowReplacement list + 'event.action': ['process_stopped', 'stop'], // event.action is in the allow list, but not the allowReplacement list + 'user.name': ['max'], // user.name is in the allow list and the allowReplacement list + }, + }; + + it('returns only the allowed fields if no rawData is provided', () => { + const expected: ContextEditorRow[] = [ + { + allowed: true, + anonymized: false, + denied: false, + field: 'event.action', + rawValues: [], + }, + { + allowed: true, + anonymized: false, + denied: false, + field: 'other.field', + rawValues: [], + }, + { + allowed: true, + anonymized: true, + denied: false, + field: 'user.name', + rawValues: [], + }, + ]; + + const nullRawData: { + allow: SelectedPromptContext['allow']; + allowReplacement: SelectedPromptContext['allowReplacement']; + rawData: Record | null; + } = { + ...defaultArgs, + rawData: null, + }; + + const rows = getRows(nullRawData); + + expect(rows).toEqual(expected); + }); + + it('returns the expected metadata and raw values', () => { + const expected: ContextEditorRow[] = [ + { + allowed: true, + anonymized: false, + denied: false, + field: 'event.action', + rawValues: ['process_stopped', 'stop'], + }, + { + allowed: false, + anonymized: false, + denied: true, + field: 'event.category', + rawValues: ['process'], + }, + { + allowed: true, + anonymized: true, + denied: false, + field: 'user.name', + rawValues: ['max'], + }, + ]; + + const rows = getRows(defaultArgs); + + expect(rows).toEqual(expected); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.ts new file mode 100644 index 0000000000000..279f75272372f --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/get_rows/index.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 { SelectedPromptContext } from '../../../assistant/prompt_context/types'; +import { isAllowed, isAnonymized, isDenied } from '../../helpers'; +import { ContextEditorRow } from '../types'; + +export const getRows = ({ + allow, + allowReplacement, + rawData, +}: { + allow: SelectedPromptContext['allow']; + allowReplacement: SelectedPromptContext['allowReplacement']; + rawData: Record | null; +}): ContextEditorRow[] => { + const allowReplacementSet = new Set(allowReplacement); + const allowSet = new Set(allow); + + if (rawData !== null && typeof rawData === 'object') { + const rawFields = Object.keys(rawData).sort(); + + return rawFields.reduce( + (acc, field) => [ + ...acc, + { + field, + allowed: isAllowed({ allowSet, field }), + anonymized: isAnonymized({ allowReplacementSet, field }), + denied: isDenied({ allowSet, field }), + rawValues: rawData[field], + }, + ], + [] + ); + } else { + return allow.sort().reduce( + (acc, field) => [ + ...acc, + { + field, + allowed: true, + anonymized: allowReplacementSet.has(field), + denied: false, + rawValues: [], + }, + ], + [] + ); + } +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.test.tsx new file mode 100644 index 0000000000000..77ffe90ec8c97 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.test.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; + +import { ContextEditor } from '.'; + +describe('ContextEditor', () => { + const allow = ['field1', 'field2']; + const allowReplacement = ['field1']; + const rawData = { field1: ['value1'], field2: ['value2'] }; + + const onListUpdated = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + + render( + + ); + }); + + it('renders the expected selected field count', () => { + expect(screen.getByTestId('selectedFields')).toHaveTextContent('Selected 0 fields'); + }); + + it('renders the select all fields button with the expected count', () => { + expect(screen.getByTestId('selectAllFields')).toHaveTextContent('Select all 2 fields'); + }); + + it('updates the table selection when "Select all n fields" is clicked', () => { + userEvent.click(screen.getByTestId('selectAllFields')); + + expect(screen.getByTestId('selectedFields')).toHaveTextContent('Selected 2 fields'); + }); + + it('calls onListUpdated with the expected values when the update button is clicked', () => { + userEvent.click(screen.getAllByTestId('allowed')[0]); + + expect(onListUpdated).toHaveBeenCalledWith([ + { + field: 'field1', + operation: 'remove', + update: 'allow', + }, + ]); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx new file mode 100644 index 0000000000000..1aab52a0d6432 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/index.tsx @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiInMemoryTable } from '@elastic/eui'; +import type { EuiSearchBarProps, EuiTableSelectionType } from '@elastic/eui'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; + +import { getColumns } from './get_columns'; +import { getRows } from './get_rows'; +import { Toolbar } from './toolbar'; +import * as i18n from './translations'; +import { BatchUpdateListItem, ContextEditorRow, FIELDS, SortConfig } from './types'; + +export const DEFAULT_PAGE_SIZE = 10; + +const pagination = { + initialPageSize: DEFAULT_PAGE_SIZE, + pageSizeOptions: [5, DEFAULT_PAGE_SIZE, 25, 50], +}; + +const defaultSort: SortConfig = { + sort: { + direction: 'desc', + field: FIELDS.ALLOWED, + }, +}; + +export interface Props { + allow: string[]; + allowReplacement: string[]; + onListUpdated: (updates: BatchUpdateListItem[]) => void; + rawData: Record | null; +} + +const search: EuiSearchBarProps = { + box: { + incremental: true, + }, + filters: [ + { + field: FIELDS.ALLOWED, + type: 'is', + name: i18n.ALLOWED, + }, + { + field: FIELDS.ANONYMIZED, + type: 'is', + name: i18n.ANONYMIZED, + }, + ], +}; + +const ContextEditorComponent: React.FC = ({ + allow, + allowReplacement, + onListUpdated, + rawData, +}) => { + const [selected, setSelection] = useState([]); + const selectionValue: EuiTableSelectionType = useMemo( + () => ({ + selectable: () => true, + onSelectionChange: (newSelection) => setSelection(newSelection), + initialSelected: [], + }), + [] + ); + const tableRef = useRef | null>(null); + + const columns = useMemo(() => getColumns({ onListUpdated, rawData }), [onListUpdated, rawData]); + + const rows = useMemo( + () => + getRows({ + allow, + allowReplacement, + rawData, + }), + [allow, allowReplacement, rawData] + ); + + const onSelectAll = useCallback(() => { + tableRef.current?.setSelection(rows); // updates selection in the EuiInMemoryTable + + setTimeout(() => setSelection(rows), 0); // updates selection in the component state + }, [rows]); + + const toolbar = useMemo( + () => ( + + ), + [onListUpdated, onSelectAll, rawData, rows.length, selected] + ); + + return ( + + ); +}; + +ContextEditorComponent.displayName = 'ContextEditorComponent'; +export const ContextEditor = React.memo(ContextEditorComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/toolbar/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/toolbar/index.test.tsx new file mode 100644 index 0000000000000..11b2488c096ad --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/toolbar/index.test.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; + +import { Toolbar } from '.'; +import * as i18n from '../translations'; +import { ContextEditorRow } from '../types'; + +const selected: ContextEditorRow[] = [ + { + allowed: true, + anonymized: false, + denied: false, + field: 'event.action', + rawValues: ['process_stopped', 'stop'], + }, + { + allowed: false, + anonymized: false, + denied: true, + field: 'event.category', + rawValues: ['process'], + }, + { + allowed: true, + anonymized: true, + denied: false, + field: 'user.name', + rawValues: ['max'], + }, +]; + +describe('Toolbar', () => { + const defaultProps = { + onListUpdated: jest.fn(), + onlyDefaults: false, + onSelectAll: jest.fn(), + selected: [], // no rows selected + totalFields: 5, + }; + + it('displays the number of selected fields', () => { + const { getByText } = render(); + + const selectedCount = selected.length; + const selectedFieldsText = getByText(i18n.SELECTED_FIELDS(selectedCount)); + + expect(selectedFieldsText).toBeInTheDocument(); + }); + + it('disables bulk actions when no rows are selected', () => { + const { getByTestId } = render(); + + const bulkActionsButton = getByTestId('bulkActionsButton'); + + expect(bulkActionsButton).toBeDisabled(); + }); + + it('enables bulk actions when some fields are selected', () => { + const { getByTestId } = render(); + + const bulkActionsButton = getByTestId('bulkActionsButton'); + + expect(bulkActionsButton).not.toBeDisabled(); + }); + + it('calls onSelectAll when the Select All Fields button is clicked', () => { + const { getByText } = render(); + const selectAllButton = getByText(i18n.SELECT_ALL_FIELDS(defaultProps.totalFields)); + + fireEvent.click(selectAllButton); + + expect(defaultProps.onSelectAll).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/toolbar/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/toolbar/index.tsx new file mode 100644 index 0000000000000..476005c8da5ba --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/toolbar/index.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 { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import React from 'react'; + +import { BulkActions } from '../bulk_actions'; +import * as i18n from '../translations'; +import { BatchUpdateListItem, ContextEditorRow } from '../types'; + +export interface Props { + onListUpdated: (updates: BatchUpdateListItem[]) => void; + onlyDefaults: boolean; + onSelectAll: () => void; + selected: ContextEditorRow[]; + totalFields: number; +} + +const ToolbarComponent: React.FC = ({ + onListUpdated, + onlyDefaults, + onSelectAll, + selected, + totalFields, +}) => ( + + + + {i18n.SELECTED_FIELDS(selected.length)} + + + + + + {i18n.SELECT_ALL_FIELDS(totalFields)} + + + + + + + +); + +ToolbarComponent.displayName = 'ToolbarComponent'; + +export const Toolbar = React.memo(ToolbarComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/translations.ts new file mode 100644 index 0000000000000..a48a52ee8092a --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/translations.ts @@ -0,0 +1,146 @@ +/* + * Copyright 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 ALL_ACTIONS = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.allActionsTooltip', + { + defaultMessage: 'All actions', + } +); + +export const ALLOW = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.allowAction', + { + defaultMessage: 'Allow', + } +); + +export const ALLOW_BY_DEFAULT = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.allowByDefaultAction', + { + defaultMessage: 'Allow by default', + } +); + +export const ALLOWED = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.allowedColumnTitle', + { + defaultMessage: 'Allowed', + } +); + +export const ALWAYS = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.alwaysSubmenu', + { + defaultMessage: 'Always', + } +); + +export const ANONYMIZE = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.anonymizeAction', + { + defaultMessage: 'Anonymize', + } +); + +export const ANONYMIZE_BY_DEFAULT = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.anonymizeByDefaultAction', + { + defaultMessage: 'Anonymize by default', + } +); + +export const ANONYMIZED = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.anonymizedColumnTitle', + { + defaultMessage: 'Anonymized', + } +); + +export const BULK_ACTIONS = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.bulkActions', + { + defaultMessage: 'Bulk actions', + } +); + +export const DEFAULTS = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.defaultsSubmenu', + { + defaultMessage: 'Defaults', + } +); + +export const DENY = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.denyAction', + { + defaultMessage: 'Deny', + } +); + +export const DENY_BY_DEFAULT = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.denyByDefaultAction', + { + defaultMessage: 'Deny by default', + } +); + +export const FIELD = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.fieldColumnTitle', + { + defaultMessage: 'Field', + } +); + +export const NO = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.noButtonLabel', + { + defaultMessage: 'No', + } +); + +export const SELECT_ALL_FIELDS = (totalFields: number) => + i18n.translate('xpack.elasticAssistant.dataAnonymizationEditor.contextEditor.selectAllFields', { + values: { totalFields }, + defaultMessage: 'Select all {totalFields} fields', + }); + +export const SELECTED_FIELDS = (selected: number) => + i18n.translate('xpack.elasticAssistant.dataAnonymizationEditor.contextEditor.selectedFields', { + values: { selected }, + defaultMessage: 'Selected {selected} fields', + }); + +export const UNANONYMIZE = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.unanonymizeAction', + { + defaultMessage: 'Unanonymize', + } +); + +export const UNANONYMIZE_BY_DEFAULT = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.unanonymizeByDefaultAction', + { + defaultMessage: 'Unanonymize by default', + } +); + +export const VALUES = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.valuesColumnTitle', + { + defaultMessage: 'Values', + } +); + +export const YES = i18n.translate( + 'xpack.elasticAssistant.assistant.dataAnonymizationEditor.contextEditor.yesButtonLabel', + { + defaultMessage: 'Yes', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/types.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/types.ts new file mode 100644 index 0000000000000..251c41db0396d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/context_editor/types.ts @@ -0,0 +1,50 @@ +/* + * Copyright 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 { Direction } from '@elastic/eui'; + +export interface ContextEditorRow { + /** Is the field is allowed to be included in the context sent to the assistant */ + allowed: boolean; + /** Are the field's values anonymized */ + anonymized: boolean; + /** Is the field is denied to be included in the context sent to the assistant */ + denied: boolean; + /** The name of the field, e.g. `user.name` */ + field: string; + /** The raw, NOT anonymized values */ + rawValues: string[]; +} + +export const FIELDS = { + ACTIONS: 'actions', + ALLOWED: 'allowed', + ANONYMIZED: 'anonymized', + DENIED: 'denied', + FIELD: 'field', + RAW_VALUES: 'rawValues', +}; + +export interface SortConfig { + sort: { + direction: Direction; + field: string; + }; +} + +/** The `field` in the specified `list` will be added or removed, as specified by the `operation` */ +export interface BatchUpdateListItem { + field: string; + operation: 'add' | 'remove'; + update: + | 'allow' + | 'allowReplacement' + | 'defaultAllow' + | 'defaultAllowReplacement' + | 'deny' + | 'denyReplacement'; +} diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.test.ts new file mode 100644 index 0000000000000..94d96cbbec685 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import type { Stats } from '../helpers'; +import { getStats } from '.'; + +describe('getStats', () => { + it('returns ZERO_STATS for string rawData', () => { + const context: SelectedPromptContext = { + allow: [], + allowReplacement: [], + promptContextId: 'abcd', + rawData: 'this will not be anonymized', + }; + + const expectedResult: Stats = { + allowed: 0, + anonymized: 0, + denied: 0, + total: 0, + }; + + expect(getStats(context)).toEqual(expectedResult); + }); + + it('returns the expected stats for object rawData', () => { + const context: SelectedPromptContext = { + allow: ['event.category', 'event.action', 'user.name'], + allowReplacement: ['user.name', 'host.ip'], // only user.name is allowed to be sent + promptContextId: 'abcd', + rawData: { + 'event.category': ['process'], + 'event.action': ['process_stopped'], + 'user.name': ['sean'], + other: ['this', 'is', 'not', 'allowed'], + }, + }; + + const expectedResult: Stats = { + allowed: 3, + anonymized: 1, + denied: 1, + total: 4, + }; + + expect(getStats(context)).toEqual(expectedResult); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.ts new file mode 100644 index 0000000000000..fbed27e5ac740 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/get_stats/index.ts @@ -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 { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { Stats, isAllowed, isAnonymized, isDenied } from '../helpers'; + +export const getStats = ({ allow, allowReplacement, rawData }: SelectedPromptContext): Stats => { + const ZERO_STATS = { + allowed: 0, + anonymized: 0, + denied: 0, + total: 0, + }; + + if (typeof rawData === 'string') { + return ZERO_STATS; + } else { + const rawFields = Object.keys(rawData); + + const allowReplacementSet = new Set(allowReplacement); + const allowSet = new Set(allow); + + return rawFields.reduce( + (acc, field) => ({ + allowed: acc.allowed + (isAllowed({ allowSet, field }) ? 1 : 0), + anonymized: + acc.anonymized + + (isAllowed({ allowSet, field }) && isAnonymized({ allowReplacementSet, field }) ? 1 : 0), + denied: acc.denied + (isDenied({ allowSet, field }) ? 1 : 0), + total: acc.total + 1, + }), + ZERO_STATS + ); + } +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/helpers/index.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/helpers/index.test.ts new file mode 100644 index 0000000000000..77031bccdf8ae --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/helpers/index.test.ts @@ -0,0 +1,304 @@ +/* + * Copyright 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 { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { + isAllowed, + isAnonymized, + isDenied, + getIsDataAnonymizable, + updateDefaultList, + updateDefaults, + updateList, + updateSelectedPromptContext, +} from '.'; +import { BatchUpdateListItem } from '../context_editor/types'; + +describe('helpers', () => { + beforeEach(() => jest.clearAllMocks()); + + describe('getIsDataAnonymizable', () => { + it('returns false for string data', () => { + const rawData = 'this will not be anonymized'; + + const result = getIsDataAnonymizable(rawData); + + expect(result).toBe(false); + }); + + it('returns true for key / values data', () => { + const rawData = { key: ['value1', 'value2'] }; + + const result = getIsDataAnonymizable(rawData); + + expect(result).toBe(true); + }); + }); + + describe('isAllowed', () => { + it('returns true when the field is present in the allowSet', () => { + const allowSet = new Set(['fieldName1', 'fieldName2', 'fieldName3']); + + expect(isAllowed({ allowSet, field: 'fieldName1' })).toBe(true); + }); + + it('returns false when the field is NOT present in the allowSet', () => { + const allowSet = new Set(['fieldName1', 'fieldName2', 'fieldName3']); + + expect(isAllowed({ allowSet, field: 'nonexistentField' })).toBe(false); + }); + }); + + describe('isDenied', () => { + it('returns true when the field is NOT in the allowSet', () => { + const allowSet = new Set(['field1', 'field2']); + const field = 'field3'; + + expect(isDenied({ allowSet, field })).toBe(true); + }); + + it('returns false when the field is in the allowSet', () => { + const allowSet = new Set(['field1', 'field2']); + const field = 'field1'; + + expect(isDenied({ allowSet, field })).toBe(false); + }); + + it('returns true for an empty allowSet', () => { + const allowSet = new Set(); + const field = 'field1'; + + expect(isDenied({ allowSet, field })).toBe(true); + }); + + it('returns false when the field is an empty string and allowSet contains the empty string', () => { + const allowSet = new Set(['', 'field1']); + const field = ''; + + expect(isDenied({ allowSet, field })).toBe(false); + }); + }); + + describe('isAnonymized', () => { + const allowReplacementSet = new Set(['user.name', 'host.name']); + + it('returns true when the field is in the allowReplacementSet', () => { + const field = 'user.name'; + + expect(isAnonymized({ allowReplacementSet, field })).toBe(true); + }); + + it('returns false when the field is NOT in the allowReplacementSet', () => { + const field = 'foozle'; + + expect(isAnonymized({ allowReplacementSet, field })).toBe(false); + }); + + it('returns false when allowReplacementSet is empty', () => { + const emptySet = new Set(); + const field = 'user.name'; + + expect(isAnonymized({ allowReplacementSet: emptySet, field })).toBe(false); + }); + }); + + describe('updateList', () => { + it('adds a new field to the list when the operation is `add`', () => { + const result = updateList({ + field: 'newField', + list: ['field1', 'field2'], + operation: 'add', + }); + + expect(result).toEqual(['field1', 'field2', 'newField']); + }); + + it('does NOT add a duplicate field to the list when the operation is `add`', () => { + const result = updateList({ + field: 'field1', + list: ['field1', 'field2'], + operation: 'add', + }); + + expect(result).toEqual(['field1', 'field2']); + }); + + it('removes an existing field from the list when the operation is `remove`', () => { + const result = updateList({ + field: 'field1', + list: ['field1', 'field2'], + operation: 'remove', + }); + + expect(result).toEqual(['field2']); + }); + + it('should NOT modify the list when removing a non-existent field', () => { + const result = updateList({ + field: 'host.name', + list: ['field1', 'field2'], + operation: 'remove', + }); + + expect(result).toEqual(['field1', 'field2']); + }); + }); + + describe('updateSelectedPromptContext', () => { + const selectedPromptContext: SelectedPromptContext = { + allow: ['user.name', 'event.category'], + allowReplacement: ['user.name'], + promptContextId: 'testId', + rawData: {}, + }; + + it('updates the allow list when update is `allow` and the operation is `add`', () => { + const result = updateSelectedPromptContext({ + field: 'event.action', + operation: 'add', + selectedPromptContext, + update: 'allow', + }); + + expect(result.allow).toEqual(['user.name', 'event.category', 'event.action']); + }); + + it('updates the allow list when update is `allow` and the operation is `remove`', () => { + const result = updateSelectedPromptContext({ + field: 'user.name', + operation: 'remove', + selectedPromptContext, + update: 'allow', + }); + + expect(result.allow).toEqual(['event.category']); + }); + + it('updates the allowReplacement list when update is `allowReplacement` and the operation is `add`', () => { + const result = updateSelectedPromptContext({ + field: 'event.type', + operation: 'add', + selectedPromptContext, + update: 'allowReplacement', + }); + expect(result.allowReplacement).toEqual(['user.name', 'event.type']); + }); + + it('updates the allowReplacement list when update is `allowReplacement` and the operation is `remove`', () => { + const result = updateSelectedPromptContext({ + field: 'user.name', + operation: 'remove', + selectedPromptContext, + update: 'allowReplacement', + }); + expect(result.allowReplacement).toEqual([]); + }); + + it('does not update selectedPromptContext when update is not "allow" or "allowReplacement"', () => { + const result = updateSelectedPromptContext({ + field: 'user.name', + operation: 'add', + selectedPromptContext, + update: 'deny', + }); + + expect(result).toEqual(selectedPromptContext); + }); + }); + + describe('updateDefaultList', () => { + it('updates the `defaultAllow` list to add a field when the operation is add', () => { + const currentList = ['test1', 'test2']; + const setDefaultList = jest.fn(); + const update = 'defaultAllow'; + const updates: BatchUpdateListItem[] = [{ field: 'test3', operation: 'add', update }]; + + updateDefaultList({ currentList, setDefaultList, update, updates }); + + expect(setDefaultList).toBeCalledWith([...currentList, 'test3']); + }); + + it('updates the `defaultAllow` list to remove a field when the operation is remove', () => { + const currentList = ['test1', 'test2']; + const setDefaultList = jest.fn(); + const update = 'defaultAllow'; + const updates: BatchUpdateListItem[] = [{ field: 'test1', operation: 'remove', update }]; + + updateDefaultList({ currentList, setDefaultList, update, updates }); + + expect(setDefaultList).toBeCalledWith(['test2']); + }); + + it('does NOT invoke `setDefaultList` when `update` does NOT match any of the batched `updates` types', () => { + const currentList = ['test1', 'test2']; + const setDefaultList = jest.fn(); + const update = 'allow'; + const updates: BatchUpdateListItem[] = [ + { field: 'test1', operation: 'remove', update: 'defaultAllow' }, // update does not match + ]; + + updateDefaultList({ currentList, setDefaultList, update, updates }); + + expect(setDefaultList).not.toBeCalled(); + }); + + it('does NOT invoke `setDefaultList` when `updates` is empty', () => { + const currentList = ['test1', 'test2']; + const setDefaultList = jest.fn(); + const update = 'defaultAllow'; + const updates: BatchUpdateListItem[] = []; // no updates + + updateDefaultList({ currentList, setDefaultList, update, updates }); + + expect(setDefaultList).not.toBeCalled(); + }); + }); + + describe('updateDefaults', () => { + const setDefaultAllow = jest.fn(); + const setDefaultAllowReplacement = jest.fn(); + + const defaultAllow = ['field1', 'field2']; + const defaultAllowReplacement = ['field2']; + const batchUpdateListItems: BatchUpdateListItem[] = [ + { + field: 'field1', + operation: 'remove', + update: 'defaultAllow', + }, + { + field: 'host.name', + operation: 'add', + update: 'defaultAllowReplacement', + }, + ]; + + it('updates defaultAllow with filtered updates', () => { + updateDefaults({ + defaultAllow, + defaultAllowReplacement, + setDefaultAllow, + setDefaultAllowReplacement, + updates: batchUpdateListItems, + }); + + expect(setDefaultAllow).toHaveBeenCalledWith(['field2']); + }); + + it('updates defaultAllowReplacement with filtered updates', () => { + updateDefaults({ + defaultAllow, + defaultAllowReplacement, + setDefaultAllow, + setDefaultAllowReplacement, + updates: batchUpdateListItems, + }); + + expect(setDefaultAllowReplacement).toHaveBeenCalledWith(['field2', 'host.name']); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/helpers/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/helpers/index.ts new file mode 100644 index 0000000000000..389ba9ce421b7 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/helpers/index.ts @@ -0,0 +1,135 @@ +/* + * Copyright 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 { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import type { BatchUpdateListItem } from '../context_editor/types'; + +export const getIsDataAnonymizable = (rawData: string | Record): boolean => + typeof rawData !== 'string'; + +export interface Stats { + allowed: number; + anonymized: number; + denied: number; + total: number; +} + +export const isAllowed = ({ allowSet, field }: { allowSet: Set; field: string }): boolean => + allowSet.has(field); + +export const isDenied = ({ allowSet, field }: { allowSet: Set; field: string }): boolean => + !allowSet.has(field); + +export const isAnonymized = ({ + allowReplacementSet, + field, +}: { + allowReplacementSet: Set; + field: string; +}): boolean => allowReplacementSet.has(field); + +export const updateList = ({ + field, + list, + operation, +}: { + field: string; + list: string[]; + operation: 'add' | 'remove'; +}): string[] => { + if (operation === 'add') { + return list.includes(field) ? list : [...list, field]; + } else { + return list.filter((x) => x !== field); + } +}; + +export const updateSelectedPromptContext = ({ + field, + operation, + selectedPromptContext, + update, +}: { + field: string; + operation: 'add' | 'remove'; + selectedPromptContext: SelectedPromptContext; + update: + | 'allow' + | 'allowReplacement' + | 'defaultAllow' + | 'defaultAllowReplacement' + | 'deny' + | 'denyReplacement'; +}): SelectedPromptContext => { + const { allow, allowReplacement } = selectedPromptContext; + + switch (update) { + case 'allow': + return { + ...selectedPromptContext, + allow: updateList({ field, list: allow, operation }), + }; + case 'allowReplacement': + return { + ...selectedPromptContext, + allowReplacement: updateList({ field, list: allowReplacement, operation }), + }; + default: + return selectedPromptContext; + } +}; + +export const updateDefaultList = ({ + currentList, + setDefaultList, + update, + updates, +}: { + currentList: string[]; + setDefaultList: React.Dispatch>; + update: 'allow' | 'allowReplacement' | 'defaultAllow' | 'defaultAllowReplacement' | 'deny'; + updates: BatchUpdateListItem[]; +}): void => { + const filteredUpdates = updates.filter((x) => x.update === update); + + if (filteredUpdates.length > 0) { + const updatedList = filteredUpdates.reduce( + (acc, { field, operation }) => updateList({ field, list: acc, operation }), + currentList + ); + + setDefaultList(updatedList); + } +}; + +export const updateDefaults = ({ + defaultAllow, + defaultAllowReplacement, + setDefaultAllow, + setDefaultAllowReplacement, + updates, +}: { + defaultAllow: string[]; + defaultAllowReplacement: string[]; + setDefaultAllow: React.Dispatch>; + setDefaultAllowReplacement: React.Dispatch>; + updates: BatchUpdateListItem[]; +}): void => { + updateDefaultList({ + currentList: defaultAllow, + setDefaultList: setDefaultAllow, + update: 'defaultAllow', + updates, + }); + + updateDefaultList({ + currentList: defaultAllowReplacement, + setDefaultList: setDefaultAllowReplacement, + update: 'defaultAllowReplacement', + updates, + }); +}; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/index.test.tsx new file mode 100644 index 0000000000000..84a36b3fb8454 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/index.test.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { SelectedPromptContext } from '../assistant/prompt_context/types'; +import { TestProviders } from '../mock/test_providers/test_providers'; +import { DataAnonymizationEditor } from '.'; + +describe('DataAnonymizationEditor', () => { + const mockSelectedPromptContext: SelectedPromptContext = { + allow: ['field1', 'field2'], + allowReplacement: ['field1'], + promptContextId: 'test-id', + rawData: 'test-raw-data', + }; + + it('renders stats', () => { + render( + + + + ); + + expect(screen.getByTestId('stats')).toBeInTheDocument(); + }); + + describe('when rawData is a string (non-anonymized data)', () => { + it('renders the ReadOnlyContextViewer when rawData is (non-anonymized data)', () => { + render( + + + + ); + + expect(screen.getByTestId('readOnlyContextViewer')).toBeInTheDocument(); + }); + + it('does NOT render the ContextEditor when rawData is non-anonymized data', () => { + render( + + + + ); + + expect(screen.queryByTestId('contextEditor')).not.toBeInTheDocument(); + }); + }); + + describe('when rawData is a `Record` (anonymized data)', () => { + const setSelectedPromptContexts = jest.fn(); + const mockRawData: Record = { + field1: ['value1', 'value2'], + field2: ['value3', 'value4', 'value5'], + field3: ['value6'], + }; + + const selectedPromptContextWithAnonymized: SelectedPromptContext = { + ...mockSelectedPromptContext, + rawData: mockRawData, + }; + + beforeEach(() => { + render( + + + + ); + }); + + it('renders the ContextEditor when rawData is anonymized data', () => { + expect(screen.getByTestId('contextEditor')).toBeInTheDocument(); + }); + + it('does NOT render the ReadOnlyContextViewer when rawData is anonymized data', () => { + expect(screen.queryByTestId('readOnlyContextViewer')).not.toBeInTheDocument(); + }); + + it('calls setSelectedPromptContexts when a field is toggled', () => { + userEvent.click(screen.getAllByTestId('allowed')[0]); // toggle the first field + + expect(setSelectedPromptContexts).toBeCalled(); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/index.tsx new file mode 100644 index 0000000000000..089e316f4795f --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/index.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 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 { EuiSpacer } from '@elastic/eui'; +import React, { useCallback, useMemo } from 'react'; +// eslint-disable-next-line @kbn/eslint/module_migration +import styled from 'styled-components'; + +import { useAssistantContext } from '../assistant_context'; +import type { SelectedPromptContext } from '../assistant/prompt_context/types'; +import { ContextEditor } from './context_editor'; +import { BatchUpdateListItem } from './context_editor/types'; +import { getIsDataAnonymizable, updateDefaults, updateSelectedPromptContext } from './helpers'; +import { ReadOnlyContextViewer } from './read_only_context_viewer'; +import { Stats } from './stats'; + +const EditorContainer = styled.div` + overflow-x: auto; +`; + +export interface Props { + selectedPromptContext: SelectedPromptContext; + setSelectedPromptContexts: React.Dispatch< + React.SetStateAction> + >; +} + +const DataAnonymizationEditorComponent: React.FC = ({ + selectedPromptContext, + setSelectedPromptContexts, +}) => { + const { defaultAllow, defaultAllowReplacement, setDefaultAllow, setDefaultAllowReplacement } = + useAssistantContext(); + const isDataAnonymizable = useMemo( + () => getIsDataAnonymizable(selectedPromptContext.rawData), + [selectedPromptContext] + ); + + const onListUpdated = useCallback( + (updates: BatchUpdateListItem[]) => { + const updatedPromptContext = updates.reduce( + (acc, { field, operation, update }) => + updateSelectedPromptContext({ + field, + operation, + selectedPromptContext: acc, + update, + }), + selectedPromptContext + ); + + setSelectedPromptContexts((prev) => ({ + ...prev, + [selectedPromptContext.promptContextId]: updatedPromptContext, + })); + + updateDefaults({ + defaultAllow, + defaultAllowReplacement, + setDefaultAllow, + setDefaultAllowReplacement, + updates, + }); + }, + [ + defaultAllow, + defaultAllowReplacement, + selectedPromptContext, + setDefaultAllow, + setDefaultAllowReplacement, + setSelectedPromptContexts, + ] + ); + + return ( + + + + + + {typeof selectedPromptContext.rawData === 'string' ? ( + + ) : ( + + )} + + ); +}; + +export const DataAnonymizationEditor = React.memo(DataAnonymizationEditorComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/read_only_context_viewer/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/read_only_context_viewer/index.test.tsx new file mode 100644 index 0000000000000..101b5058b5481 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/read_only_context_viewer/index.test.tsx @@ -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 React from 'react'; +import { render, screen } from '@testing-library/react'; + +import { SYSTEM_PROMPT_CONTEXT_NON_I18N } from '../../content/prompts/system/translations'; +import { ReadOnlyContextViewer, Props } from '.'; + +const defaultProps: Props = { + rawData: 'this content is NOT anonymized', +}; + +describe('ReadOnlyContextViewer', () => { + it('renders the context with the correct formatting', () => { + render(); + + const contextBlock = screen.getByTestId('readOnlyContextViewer'); + + expect(contextBlock.textContent).toBe(SYSTEM_PROMPT_CONTEXT_NON_I18N(defaultProps.rawData)); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/read_only_context_viewer/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/read_only_context_viewer/index.tsx new file mode 100644 index 0000000000000..0fd2da1942bc5 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/read_only_context_viewer/index.tsx @@ -0,0 +1,27 @@ +/* + * Copyright 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 { EuiCodeBlock } from '@elastic/eui'; +import React from 'react'; + +import { SYSTEM_PROMPT_CONTEXT_NON_I18N } from '../../content/prompts/system/translations'; + +export interface Props { + rawData: string; +} + +const ReadOnlyContextViewerComponent: React.FC = ({ rawData }) => { + return ( + + {SYSTEM_PROMPT_CONTEXT_NON_I18N(rawData)} + + ); +}; + +ReadOnlyContextViewerComponent.displayName = 'ReadOnlyContextViewerComponent'; + +export const ReadOnlyContextViewer = React.memo(ReadOnlyContextViewerComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.test.tsx new file mode 100644 index 0000000000000..8f5b3506c5054 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.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 { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; + +import { AllowedStat } from '.'; +import * as i18n from './translations'; + +describe('AllowedStat', () => { + const defaultProps = { + allowed: 3, + total: 5, + }; + + it('renders the expected stat content', () => { + render(); + + expect(screen.getByTestId('allowedStat')).toHaveTextContent('3Allowed'); + }); + + it('displays the correct tooltip content', async () => { + render(); + + userEvent.hover(screen.getByTestId('allowedStat')); + + await waitFor(() => { + expect(screen.getByText(i18n.ALLOWED_TOOLTIP(defaultProps))).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.tsx new file mode 100644 index 0000000000000..096617d17422a --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/index.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 { EuiStat, EuiToolTip } from '@elastic/eui'; +import React, { useMemo } from 'react'; + +import { TITLE_SIZE } from '../constants'; +import * as i18n from './translations'; + +interface Props { + allowed: number; + total: number; +} + +const AllowedStatComponent: React.FC = ({ allowed, total }) => { + const tooltipContent = useMemo(() => i18n.ALLOWED_TOOLTIP({ allowed, total }), [allowed, total]); + + return ( + + + + ); +}; + +AllowedStatComponent.displayName = 'AllowedStatComponent'; + +export const AllowedStat = React.memo(AllowedStatComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/translations.ts new file mode 100644 index 0000000000000..f9e9a26952528 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/allowed_stat/translations.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 { i18n } from '@kbn/i18n'; + +export const ALLOWED_TOOLTIP = ({ allowed, total }: { allowed: number; total: number }) => + i18n.translate( + 'xpack.elasticAssistant.dataAnonymizationEditor.stats.allowedStat.allowedTooltip', + { + values: { allowed, total }, + defaultMessage: + '{allowed} of {total} fields in this context are allowed to be included in the conversation', + } + ); + +export const ALLOWED = i18n.translate( + 'xpack.elasticAssistant.dataAnonymizationEditor.stats.allowedStat.allowedDescription', + { + defaultMessage: 'Allowed', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/helpers.test.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/helpers.test.ts new file mode 100644 index 0000000000000..cbddce86cfd37 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/helpers.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getColor, getTooltipContent } from './helpers'; + +describe('helpers', () => { + describe('getColor', () => { + it('returns `default` when isDataAnonymizable is true', () => { + const result = getColor(true); + + expect(result).toBe('default'); + }); + + it('returns `subdued` when isDataAnonymizable is false', () => { + const result = getColor(false); + + expect(result).toBe('subdued'); + }); + }); + + describe('getTooltipContent', () => { + it('informs the user that the context cannot be anonymized when isDataAnonymizable is false', () => { + const result = getTooltipContent({ anonymized: 0, isDataAnonymizable: false }); + + expect(result).toEqual('This context cannot be anonymized'); + }); + + it('returns the expected message when the data is anonymizable, but no data has been anonymized', () => { + const result = getTooltipContent({ anonymized: 0, isDataAnonymizable: true }); + expect(result).toEqual( + 'Select fields to be replaced with random values. Responses are automatically translated back to the original values.' + ); + }); + + it('returns the correct plural form of "field" when one field has been anonymized', () => { + const result = getTooltipContent({ anonymized: 1, isDataAnonymizable: true }); + expect(result).toEqual( + '1 field in this context will be replaced with random values. Responses are automatically translated back to the original values.' + ); + }); + + it('returns the correct plural form of "field" when more than one field has been anonymized', () => { + const result = getTooltipContent({ anonymized: 2, isDataAnonymizable: true }); + expect(result).toEqual( + '2 fields in this context will be replaced with random values. Responses are automatically translated back to the original values.' + ); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/helpers.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/helpers.ts new file mode 100644 index 0000000000000..bfffd9a1c5c13 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/helpers.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 * as i18n from './translations'; + +export const getColor = (isDataAnonymizable: boolean): 'default' | 'subdued' => + isDataAnonymizable ? 'default' : 'subdued'; + +export const getTooltipContent = ({ + anonymized, + isDataAnonymizable, +}: { + anonymized: number; + isDataAnonymizable: boolean; +}): string => + !isDataAnonymizable || anonymized === 0 + ? i18n.NONE_OF_THE_DATA_WILL_BE_ANONYMIZED(isDataAnonymizable) + : i18n.FIELDS_WILL_BE_ANONYMIZED(anonymized); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.test.tsx new file mode 100644 index 0000000000000..a4b2b957d04c7 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.test.tsx @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiToolTip } from '@elastic/eui'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; + +import { getTooltipContent } from './helpers'; +import * as i18n from './translations'; +import { AnonymizedStat } from '.'; +import { TestProviders } from '../../../mock/test_providers/test_providers'; + +const defaultProps = { + anonymized: 0, + isDataAnonymizable: false, + showIcon: false, +}; + +describe('AnonymizedStat', () => { + it('renders the expected content when the data is NOT anonymizable', () => { + render( + + + + ); + + expect(screen.getByTestId('anonymizedFieldsStat')).toHaveTextContent('0Anonymized'); + }); + + it('shows the anonymization icon when showIcon is true', () => { + render( + + + + ); + + expect(screen.getByTestId('anonymizationIcon')).toBeInTheDocument(); + }); + + it('does NOT show the anonymization icon when showIcon is false', () => { + render( + + + + ); + + expect(screen.queryByTestId('anonymizationIcon')).not.toBeInTheDocument(); + }); + + it('shows the correct tooltip content when anonymized is 0 and isDataAnonymizable is false', async () => { + render( + + + + ); + + userEvent.hover(screen.getByTestId('anonymizedFieldsStat')); + + await waitFor(() => { + expect(screen.getByText(i18n.NONE_OF_THE_DATA_WILL_BE_ANONYMIZED(false))).toBeInTheDocument(); + }); + }); + + it('shows correct tooltip content when anonymized is positive and isDataAnonymizable is true', async () => { + const anonymized = 3; + const isDataAnonymizable = true; + + render( + + + + ); + + userEvent.hover(screen.getByTestId('anonymizedFieldsStat')); + + await waitFor(() => { + expect(screen.getByText(i18n.FIELDS_WILL_BE_ANONYMIZED(anonymized))).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.tsx new file mode 100644 index 0000000000000..574bc9aafc190 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/index.tsx @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiStat, EuiText, EuiToolTip } from '@elastic/eui'; +import React, { useMemo } from 'react'; +// eslint-disable-next-line @kbn/eslint/module_migration +import styled from 'styled-components'; + +import { getColor, getTooltipContent } from './helpers'; +import { TITLE_SIZE } from '../constants'; +import * as i18n from './translations'; + +const ANONYMIZATION_ICON = 'eyeClosed'; + +const AnonymizationIconFlexItem = styled(EuiFlexItem)` + margin-right: ${({ theme }) => theme.eui.euiSizeS}; +`; + +interface Props { + anonymized: number; + isDataAnonymizable: boolean; + showIcon?: boolean; +} + +const AnonymizedStatComponent: React.FC = ({ + anonymized, + isDataAnonymizable, + showIcon = false, +}) => { + const color = useMemo(() => getColor(isDataAnonymizable), [isDataAnonymizable]); + + const tooltipContent = useMemo( + () => getTooltipContent({ anonymized, isDataAnonymizable }), + [anonymized, isDataAnonymizable] + ); + + const description = useMemo( + () => ( + + {showIcon && ( + + + + )} + + + + {i18n.ANONYMIZED_FIELDS} + + + + ), + [color, showIcon] + ); + + return ( + + + + ); +}; + +AnonymizedStatComponent.displayName = 'AnonymizedStatComponent'; + +export const AnonymizedStat = React.memo(AnonymizedStatComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/translations.ts new file mode 100644 index 0000000000000..2decce2c7b794 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/anonymized_stat/translations.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const ANONYMIZED_FIELDS = i18n.translate( + 'xpack.elasticAssistant.dataAnonymizationEditor.stats.anonymizedStat.anonymizeFieldsdDescription', + { + defaultMessage: 'Anonymized', + } +); + +export const FIELDS_WILL_BE_ANONYMIZED = (anonymized: number) => + i18n.translate( + 'xpack.elasticAssistant.dataAnonymizationEditor.stats.anonymizedStat.fieldsWillBeAnonymizedTooltip', + { + values: { anonymized }, + defaultMessage: + '{anonymized} {anonymized, plural, =1 {field} other {fields}} in this context will be replaced with random values. Responses are automatically translated back to the original values.', + } + ); + +export const NONE_OF_THE_DATA_WILL_BE_ANONYMIZED = (isDataAnonymizable: boolean) => + i18n.translate( + 'xpack.elasticAssistant.dataAnonymizationEditor.stats.anonymizedStat.noneOfTheDataWillBeAnonymizedTooltip', + { + values: { isDataAnonymizable }, + defaultMessage: + '{isDataAnonymizable, select, true {Select fields to be replaced with random values. Responses are automatically translated back to the original values.} other {This context cannot be anonymized}}', + } + ); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.test.tsx new file mode 100644 index 0000000000000..a969696622e4d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.test.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; + +import { AvailableStat } from '.'; +import * as i18n from './translations'; + +describe('AvailableStat component', () => { + const total = 5; + + it('renders the expected stat content', () => { + render(); + + expect(screen.getByTestId('availableStat')).toHaveTextContent(`${total}Available`); + }); + + it('displays the tooltip with the correct content', async () => { + render(); + + userEvent.hover(screen.getByTestId('availableStat')); + + await waitFor(() => { + const tooltipContent = i18n.AVAILABLE_TOOLTIP(total); + + expect(screen.getByText(tooltipContent)).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.tsx new file mode 100644 index 0000000000000..d675758951ca8 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/index.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 { EuiStat, EuiToolTip } from '@elastic/eui'; +import React, { useMemo } from 'react'; + +import { TITLE_SIZE } from '../constants'; +import * as i18n from './translations'; + +interface Props { + total: number; +} + +const AvailableStatComponent: React.FC = ({ total }) => { + const tooltipContent = useMemo(() => i18n.AVAILABLE_TOOLTIP(total), [total]); + + return ( + + + + ); +}; + +AvailableStatComponent.displayName = 'AvailableStatComponent'; + +export const AvailableStat = React.memo(AvailableStatComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/translations.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/translations.ts new file mode 100644 index 0000000000000..06e2343c98794 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/available_stat/translations.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 { i18n } from '@kbn/i18n'; + +export const AVAILABLE_TOOLTIP = (total: number) => + i18n.translate( + 'xpack.elasticAssistant.dataAnonymizationEditor.stats.availableStat.availableTooltip', + { + values: { total }, + defaultMessage: + '{total} fields in this context are available to be included in the conversation', + } + ); + +export const AVAILABLE = i18n.translate( + 'xpack.elasticAssistant.dataAnonymizationEditor.stats.availableStat.availableDescription', + { + defaultMessage: 'Available', + } +); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/constants.ts b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/constants.ts new file mode 100644 index 0000000000000..ba1e02e569bc2 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/constants.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const TITLE_SIZE = 'xs'; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.test.tsx new file mode 100644 index 0000000000000..c1980a55e410d --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.test.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +import { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { TestProviders } from '../../mock/test_providers/test_providers'; +import { Stats } from '.'; + +describe('Stats', () => { + const selectedPromptContext: SelectedPromptContext = { + allow: ['field1', 'field2'], + allowReplacement: ['field1'], + promptContextId: 'abcd', + rawData: { + field1: ['value1', 'value2'], + field2: ['value3, value4', 'value5'], + field3: ['value6'], + }, + }; + + it('renders the expected allowed stat content', () => { + render( + + + + ); + + expect(screen.getByTestId('allowedStat')).toHaveTextContent('2Allowed'); + }); + + it('renders the expected anonymized stat content', () => { + render( + + + + ); + + expect(screen.getByTestId('anonymizedFieldsStat')).toHaveTextContent('1Anonymized'); + }); + + it('renders the expected available stat content', () => { + render( + + + + ); + + expect(screen.getByTestId('availableStat')).toHaveTextContent('3Available'); + }); + + it('should not display the allowed stat when isDataAnonymizable is false', () => { + render( + + + + ); + + expect(screen.queryByTestId('allowedStat')).not.toBeInTheDocument(); + }); + + it('should not display the available stat when isDataAnonymizable is false', () => { + render( + + + + ); + + expect(screen.queryByTestId('availableStat')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.tsx b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.tsx new file mode 100644 index 0000000000000..b0a27e271cdf7 --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/data_anonymization_editor/stats/index.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 { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { useMemo } from 'react'; +// eslint-disable-next-line @kbn/eslint/module_migration +import styled from 'styled-components'; + +import { AllowedStat } from './allowed_stat'; +import { AnonymizedStat } from './anonymized_stat'; +import type { SelectedPromptContext } from '../../assistant/prompt_context/types'; +import { getStats } from '../get_stats'; +import { AvailableStat } from './available_stat'; + +const StatFlexItem = styled(EuiFlexItem)` + margin-right: ${({ theme }) => theme.eui.euiSizeL}; +`; + +interface Props { + isDataAnonymizable: boolean; + selectedPromptContext: SelectedPromptContext; +} + +const StatsComponent: React.FC = ({ isDataAnonymizable, selectedPromptContext }) => { + const { allowed, anonymized, total } = useMemo( + () => getStats(selectedPromptContext), + [selectedPromptContext] + ); + + return ( + + {isDataAnonymizable && ( + + + + )} + + + + + + {isDataAnonymizable && ( + + + + )} + + ); +}; + +StatsComponent.displayName = 'StatsComponent'; + +export const Stats = React.memo(StatsComponent); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/mock/get_anonymized_value/index.ts b/x-pack/packages/kbn-elastic-assistant/impl/mock/get_anonymized_value/index.ts new file mode 100644 index 0000000000000..1ec76a90d292b --- /dev/null +++ b/x-pack/packages/kbn-elastic-assistant/impl/mock/get_anonymized_value/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** This mock returns the reverse of `value` */ +export const mockGetAnonymizedValue = ({ + currentReplacements, + rawValue, +}: { + currentReplacements: Record | undefined; + rawValue: string; +}): string => rawValue.split('').reverse().join(''); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx b/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx index 9ceda348795ae..d3923b2ca8fd1 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/mock/test_providers/test_providers.tsx @@ -34,9 +34,15 @@ export const TestProvidersComponent: React.FC = ({ children }) => { {children} diff --git a/x-pack/packages/ml/error_utils/src/types.ts b/x-pack/packages/ml/error_utils/src/types.ts index b66c960b8c8c0..1b9bf0301ac87 100644 --- a/x-pack/packages/ml/error_utils/src/types.ts +++ b/x-pack/packages/ml/error_utils/src/types.ts @@ -10,7 +10,6 @@ import type Boom from '@hapi/boom'; import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { IHttpFetchError } from '@kbn/core-http-browser'; -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; /** * Short hand type of estypes.ErrorCause. @@ -144,53 +143,49 @@ export type ErrorType = MLHttpFetchError | EsErrorBody | Boom.Boom | string | un /** * Type guard to check if error is of type EsErrorBody * @export - * @param {unknown} error + * @param {any} error * @returns {error is EsErrorBody} */ -export function isEsErrorBody(error: unknown): error is EsErrorBody { - return isPopulatedObject(error, ['error']) && isPopulatedObject(error.error, ['reason']); +export function isEsErrorBody(error: any): error is EsErrorBody { + return error && error.error?.reason !== undefined; } /** * Type guard to check if error is a string. * @export - * @param {unknown} error + * @param {any} error * @returns {error is string} */ -export function isErrorString(error: unknown): error is string { +export function isErrorString(error: any): error is string { return typeof error === 'string'; } /** * Type guard to check if error is of type ErrorMessage. * @export - * @param {unknown} error + * @param {any} error * @returns {error is ErrorMessage} */ -export function isErrorMessage(error: unknown): error is ErrorMessage { - return isPopulatedObject(error, ['message']) && typeof error.message === 'string'; +export function isErrorMessage(error: any): error is ErrorMessage { + return error && error.message !== undefined && typeof error.message === 'string'; } /** * Type guard to check if error is of type MLResponseError. * @export - * @param {unknown} error + * @param {any} error * @returns {error is MLResponseError} */ -export function isMLResponseError(error: unknown): error is MLResponseError { - return ( - isPopulatedObject(error, ['body']) && - isPopulatedObject(error.body, ['message']) && - 'message' in error.body - ); +export function isMLResponseError(error: any): error is MLResponseError { + return typeof error.body === 'object' && 'message' in error.body; } /** * Type guard to check if error is of type Boom. * @export - * @param {unknown} error + * @param {any} error * @returns {error is Boom.Boom} */ -export function isBoomError(error: unknown): error is Boom.Boom { - return isPopulatedObject(error, ['isBoom']) && error.isBoom === true; +export function isBoomError(error: any): error is Boom.Boom { + return error?.isBoom === true; } diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/test_providers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/test_providers.tsx index 7c9933942b270..b2a721329e1fa 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/test_providers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/test_providers.tsx @@ -35,9 +35,15 @@ export const TestProvidersComponent: React.FC = ({ children }) => { {children} diff --git a/x-pack/plugins/alerting/docs/openapi/bundled.json b/x-pack/plugins/alerting/docs/openapi/bundled.json index 8be61e53d2d69..55d195fcebeca 100644 --- a/x-pack/plugins/alerting/docs/openapi/bundled.json +++ b/x-pack/plugins/alerting/docs/openapi/bundled.json @@ -25,6 +25,86 @@ } ], "paths": { + "/s/{spaceId}/api/alerting/rule": { + "post": { + "summary": "Creates a rule with a randomly generated rule identifier.", + "operationId": "createRule", + "description": "You must have `all` privileges for the appropriate Kibana features, depending on the `consumer` and `rule_type_id` of the rule you're creating. For example, you must have privileges for the **Management > Stack rules** feature, **Analytics > Discover** and **Machine Learning** features, **Observability** features, or **Security** features. If the rule has actions, you must also have `read` privileges for the **Management > Actions and Connectors** feature. NOTE: This API supports only token-based authentication. When you create a rule, it identifies which roles you have at that point in time. Thereafter, when the rule performs queries, it uses those security privileges. If a user with different privileges updates the rule, its behavior might change.\n", + "tags": [ + "alerting" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/create_rule_request" + }, + "examples": { + "createRuleRequest": { + "$ref": "#/components/examples/create_rule_request" + } + } + } + } + }, + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/rule_response_properties" + }, + "examples": { + "createRuleResponse": { + "$ref": "#/components/examples/create_rule_response" + } + } + } + } + }, + "401": { + "description": "Authorization information is missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/401_response" + } + } + } + }, + "404": { + "description": "Object is not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/404_response" + } + } + } + } + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, "/s/{spaceId}/api/alerting/rule/{ruleId}": { "get": { "summary": "Retrieves a rule by its identifier.", @@ -134,8 +214,8 @@ ] }, "post": { - "summary": "Creates a rule.", - "operationId": "createRule", + "summary": "Creates a rule with a specific rule identifier.", + "operationId": "createRuleId", "description": "You must have `all` privileges for the appropriate Kibana features, depending on the `consumer` and `rule_type_id` of the rule you're creating. For example, you must have privileges for the **Management > Stack rules** feature, **Analytics > Discover** and **Machine Learning** features, **Observability** features, or **Security** features. If the rule has actions, you must also have `read` privileges for the **Management > Actions and Connectors** feature. NOTE: This API supports only token-based authentication. When you create a rule, it identifies which roles you have at that point in time. Thereafter, when the rule performs queries, it uses those security privileges. If a user with different privileges updates the rule, its behavior might change.\n", "tags": [ "alerting" @@ -166,7 +246,7 @@ "$ref": "#/components/schemas/create_rule_request" }, "examples": { - "createCaseRequest": { + "createRuleIdRequest": { "$ref": "#/components/examples/create_rule_request" } } @@ -182,7 +262,7 @@ "$ref": "#/components/schemas/rule_response_properties" }, "examples": { - "createRuleResponse": { + "createRuleIdResponse": { "$ref": "#/components/examples/create_rule_response" } } @@ -242,7 +322,7 @@ "$ref": "#/components/schemas/update_rule_request" }, "examples": { - "updateCaseRequest": { + "updateRuleRequest": { "$ref": "#/components/examples/update_rule_request" } } @@ -2409,15 +2489,14 @@ } }, "parameters": { - "rule_id": { - "in": "path", - "name": "ruleId", - "description": "An identifier for the rule.", - "required": true, + "kbn_xsrf": { "schema": { - "type": "string", - "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" - } + "type": "string" + }, + "in": "header", + "name": "kbn-xsrf", + "description": "Cross-site request forgery protection", + "required": true }, "space_id": { "in": "path", @@ -2429,14 +2508,15 @@ "example": "default" } }, - "kbn_xsrf": { + "rule_id": { + "in": "path", + "name": "ruleId", + "description": "An identifier for the rule.", + "required": true, "schema": { - "type": "string" - }, - "in": "header", - "name": "kbn-xsrf", - "description": "Cross-site request forgery protection", - "required": true + "type": "string", + "example": "ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74" + } }, "alert_id": { "in": "path", @@ -2642,6 +2722,18 @@ } } }, + "consumer": { + "type": "string", + "description": "The name of the application or feature that owns the rule. For example: `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`.\n" + }, + "enabled_rule": { + "type": "boolean", + "description": "Indicates whether you want to run the rule on an interval basis after it is created." + }, + "name_rule": { + "type": "string", + "description": "The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.\n" + }, "schedule": { "type": "object", "description": "The check interval, which specifies how frequently the rule conditions are checked. The interval is specified in seconds, minutes, hours, or days.", @@ -2660,308 +2752,3501 @@ }, "default": [] }, - "rule_response_properties": { - "title": "Rule response properties", + "create_anomaly_detection_alert_rule_request": { + "title": "Create anomaly detection rule request", + "description": "A rule that checks if the anomaly detection job results contain anomalies that match the rule conditions. \n", "type": "object", "required": [ - "actions", - "api_key_owner", "consumer", - "created_at", - "created_by", - "enabled", - "execution_status", - "id", - "mute_all", - "muted_alert_ids", "name", "params", "rule_type_id", - "schedule", - "tags", - "throttle", - "updated_at", - "updated_by" + "schedule" ], "properties": { "actions": { "$ref": "#/components/schemas/actions" }, - "api_key_created_by_user": { - "type": "boolean", - "description": "Indicates whether the API key that is associated with the rule was created by the user.", - "example": false - }, - "api_key_owner": { - "type": "string", - "description": "The owner of the API key that is associated with the rule and used to run background tasks.\n", - "nullable": true, - "example": "elastic" - }, "consumer": { - "type": "string", - "description": "The application or feature that owns the rule. For example, `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`.", - "example": "alerts" - }, - "created_at": { - "type": "string", - "description": "The date and time that the rule was created.", - "format": "date-time", - "example": "2022-12-05T23:36:58.284Z" - }, - "created_by": { - "type": "string", - "description": "The identifier for the user that created the rule.", - "nullable": true, - "example": "elastic" + "$ref": "#/components/schemas/consumer" }, "enabled": { - "type": "boolean", - "description": "Indicates whether the rule is currently enabled.", - "example": true - }, - "execution_status": { - "type": "object", - "properties": { - "last_duration": { - "type": "integer", - "example": 55 - }, - "last_execution_date": { - "type": "string", - "format": "date-time", - "example": "2022-12-06T00:13:43.890Z" - }, - "status": { - "type": "string", - "example": "ok" - } - } - }, - "id": { - "type": "string", - "description": "The identifier for the rule.", - "example": "b530fed0-74f5-11ed-9801-35303b735aef" - }, - "last_run": { - "type": "object", - "properties": { - "alerts_count": { - "type": "object", - "properties": { - "active": { - "type": "integer" - }, - "ignored": { - "type": "integer" - }, - "new": { - "type": "integer" - }, - "recovered": { - "type": "integer" - } - } - }, - "outcome": { - "type": "string", - "example": "succeeded" - }, - "outcome_msg": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "outcome_order": { - "type": "integer" - }, - "warning": { - "type": "string", - "nullable": true, - "example": null - } - } - }, - "muted_alert_ids": { - "type": "array", - "nullable": true, - "items": { - "type": "string" - } - }, - "mute_all": { - "type": "boolean", - "example": false + "$ref": "#/components/schemas/enabled_rule" }, "name": { - "type": "string", - "description": "The name of the rule.", - "example": "cluster_health_rule" - }, - "next_run": { - "type": "string", - "format": "date-time", - "nullable": true, - "example": "2022-12-06T00:14:43.818Z" + "$ref": "#/components/schemas/name_rule" }, "notify_when": { "$ref": "#/components/schemas/notify_when" }, "params": { "type": "object", - "description": "The parameters for the rule.", + "description": "The parameters for an anomaly detection rule.", "additionalProperties": true }, - "revision": { - "type": "integer", - "description": "The rule revision number." - }, "rule_type_id": { "type": "string", - "description": "The identifier for the type of rule. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`.\n", - "example": "monitoring_alert_cluster_health" - }, - "running": { - "type": "boolean", - "description": "Indicates whether the rule is running." + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "xpack.ml.anomaly_detection_alert" + ] }, "schedule": { "$ref": "#/components/schemas/schedule" }, - "scheduled_task_id": { + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_anomaly_detection_jobs_health_rule_request": { + "title": "Create anomaly detection jobs health rule request", + "description": "An rule that monitors job health and alerts if an operational issue occurred that may prevent the job from detecting anomalies.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for an anomaly detection jobs health rule.", + "additionalProperties": true + }, + "rule_type_id": { "type": "string", - "example": "b530fed0-74f5-11ed-9801-35303b735aef" + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "xpack.ml.anomaly_detection_jobs_health" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" }, "tags": { "$ref": "#/components/schemas/tags" }, "throttle": { "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_apm_anomaly": { + "required": [ + "windowSize", + "windowUnit", + "environment", + "anomalySeverityType" + ], + "properties": { + "serviceName": { + "type": "string", + "description": "The service name from APM" }, - "updated_at": { + "transactionType": { "type": "string", - "description": "The date and time that the rule was updated most recently.", - "example": "2022-12-05T23:36:58.284Z" + "description": "The transaction type from APM" }, - "updated_by": { + "windowSize": { + "type": "number", + "example": 6, + "description": "The window size" + }, + "windowUnit": { "type": "string", - "description": "The identifier for the user that updated this rule most recently.", - "nullable": true, - "example": "elastic" + "description": "The window size unit", + "enum": [ + "m", + "h", + "d" + ] + }, + "environment": { + "type": "string", + "description": "The environment from APM" + }, + "anomalySeverityType": { + "type": "string", + "description": "The anomaly threshold value", + "enum": [ + "critical", + "major", + "minor", + "warning" + ] } } }, - "401_response": { + "create_apm_anomaly_rule_request": { + "title": "Create APM anomaly rule rule request", + "description": "A rule that detects when either the latency, throughput, or failed transaction rate of a service is anomalous.", "type": "object", - "title": "Unsuccessful rule API response", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], "properties": { - "error": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_apm_anomaly" + }, + "rule_type_id": { "type": "string", - "example": "Unauthorized", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", "enum": [ - "Unauthorized" + "apm.anomaly" ] }, - "message": { - "type": "string" + "schedule": { + "$ref": "#/components/schemas/schedule" }, - "statusCode": { - "type": "integer", - "example": 401, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_apm_error_count": { + "required": [ + "windowSize", + "windowUnit", + "threshold", + "environment" + ], + "properties": { + "serviceName": { + "type": "string", + "description": "The service name from APM" + }, + "windowSize": { + "type": "number", + "description": "The window size", + "example": 6 + }, + "windowUnit": { + "type": "string", + "description": "The window size unit", "enum": [ - 401 + "m", + "h", + "d" ] + }, + "environment": { + "type": "string", + "description": "The environment from APM" + }, + "threshold": { + "type": "number", + "description": "The error count threshold value" + }, + "groupBy": { + "type": "array", + "default": [ + "service.name", + "service.environment" + ], + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "service.name", + "service.environment", + "transaction.name", + "error.grouping_key" + ] + } + }, + "errorGroupingKey": { + "type": "string" } } }, - "404_response": { + "create_apm_error_count_rule_request": { + "title": "Create APM error count rule request", + "description": "A rule that detects when the number of errors in a service exceeds a defined threshold.", "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], "properties": { - "error": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_apm_error_count" + }, + "rule_type_id": { "type": "string", - "example": "Not Found", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", "enum": [ - "Not Found" + "apm.error_rate" ] }, - "message": { + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_apm_transaction_duration": { + "required": [ + "windowSize", + "windowUnit", + "threshold", + "environment", + "aggregationType" + ], + "properties": { + "serviceName": { "type": "string", - "example": "Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found" + "description": "The service name from APM" }, - "statusCode": { - "type": "integer", - "example": 404, + "transactionType": { + "type": "string", + "description": "The transaction type from APM" + }, + "transactionName": { + "type": "string", + "description": "The transaction name from APM" + }, + "windowSize": { + "type": "number", + "description": "The window size", + "example": 6 + }, + "windowUnit": { + "type": "string", + "description": "ç", "enum": [ - 404 + "m", + "h", + "d" + ] + }, + "environment": { + "type": "string" + }, + "threshold": { + "type": "number", + "description": "The latency threshold value" + }, + "groupBy": { + "type": "array", + "default": [ + "service.name", + "service.environment", + "transaction.type" + ], + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "service.name", + "service.environment", + "transaction.type", + "transaction.name" + ] + } + }, + "aggregationType": { + "type": "string", + "enum": [ + "avg", + "95th", + "99th" ] } } }, - "update_rule_request": { - "title": "Update rule request", - "description": "The update rule API request body varies depending on the type of rule and actions.", + "create_apm_transaction_duration_rule_request": { + "title": "Create latency threshold rule request", + "description": "A rule that detects when the latency of a specific transaction type in a service exceeds a threshold.", "type": "object", "required": [ + "consumer", "name", "params", + "rule_type_id", "schedule" ], "properties": { "actions": { "$ref": "#/components/schemas/actions" }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, "name": { - "type": "string", - "description": "The name of the rule.", - "example": "cluster_health_rule" + "$ref": "#/components/schemas/name_rule" }, "notify_when": { "$ref": "#/components/schemas/notify_when" }, "params": { - "type": "object", - "description": "The parameters for the rule.", - "additionalProperties": true + "$ref": "#/components/schemas/params_property_apm_transaction_duration" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "apm.transaction_duration" + ] }, "schedule": { "$ref": "#/components/schemas/schedule" }, - "tags": { - "$ref": "#/components/schemas/tags" + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_apm_transaction_error_rate": { + "required": [ + "windowSize", + "windowUnit", + "threshold", + "environment" + ], + "properties": { + "serviceName": { + "type": "string", + "description": "The service name from APM" + }, + "transactionType": { + "type": "string", + "description": "The transaction type from APM" + }, + "transactionName": { + "type": "string", + "description": "The transaction name from APM" + }, + "windowSize": { + "type": "number", + "description": "The window size", + "example": 6 + }, + "windowUnit": { + "type": "string", + "description": "The window size unit", + "enum": [ + "m", + "h", + "d" + ] + }, + "environment": { + "type": "string", + "description": "The environment from APM" + }, + "threshold": { + "type": "number", + "description": "The error rate threshold value" + }, + "groupBy": { + "type": "array", + "default": [ + "service.name", + "service.environment", + "transaction.type" + ], + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "service.name", + "service.environment", + "transaction.type", + "transaction.name" + ] + } + } + } + }, + "create_apm_transaction_error_rate_rule_request": { + "title": "Create APM transaction error rate rule request", + "description": "A rule that sends notifications when the rate of transaction errors in a service exceeds a threshold.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_apm_transaction_error_rate" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "apm.transaction_error_rate" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_es_query_rule_request": { + "title": "Create Elasticsearch query rule request", + "description": "A rule that runs a user-configured query, compares the number of matches to a configured threshold, and schedules actions to run when the threshold condition is met. \n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for an Elasticsearch query rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + ".es-query" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_geo_containment_rule_request": { + "title": "Create traacking containment rule request", + "description": "A rule that runs an Elasticsearch query over indices to determine whether any documents are currently contained within any boundaries from the specified boundary index. In the event that an entity is contained within a boundary, an alert may be generated. \n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for an tracking containment rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + ".geo-containment" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_index_threshold_rule_request": { + "title": "Create index threshold rule request", + "description": "A rule that runs an Elasticsearch query, aggregates field values from documents, compares them to threshold values, and schedules actions to run when the thresholds are met.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for an index threshold rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + ".index-threshold" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_infra_inventory": { + "properties": { + "criteria": { + "type": "array", + "items": { + "type": "object", + "properties": { + "metric": { + "type": "string", + "enum": [ + "count", + "cpu", + "diskLatency", + "load", + "memory", + "memoryTotal", + "tx", + "rx", + "logRate", + "diskIOReadBytes", + "diskIOWriteBytes", + "s3TotalRequests", + "s3NumberOfObjects", + "s3BucketSize", + "s3DownloadBytes", + "s3UploadBytes", + "rdsConnections", + "rdsQueriesExecuted", + "rdsActiveTransactions", + "rdsLatency", + "sqsMessagesVisible", + "sqsMessagesDelayed", + "sqsMessagesSent", + "sqsMessagesEmpty", + "sqsOldestMessage", + "custom" + ] + }, + "timeSize": { + "type": "number" + }, + "timeUnit": { + "type": "string", + "enum": [ + "s", + "m", + "h", + "d" + ] + }, + "sourceId": { + "type": "string" + }, + "threshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "comparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + }, + "customMetric": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "custom" + ] + }, + "field": { + "type": "string" + }, + "aggregation": { + "type": "string", + "enum": [ + "avg", + "max", + "min", + "rate" + ] + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + } + } + }, + "warningThreshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "warningComparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + } + } + } + }, + "filterQuery": { + "type": "string" + }, + "filterQueryText": { + "type": "string" + }, + "nodeType": { + "type": "string", + "enum": [ + "host", + "pod", + "container", + "awsEC2", + "awsS3", + "awsSQS", + "awsRDS" + ] + }, + "sourceId": { + "type": "string" + }, + "alertOnNoData": { + "type": "boolean" + } + } + }, + "create_infra_inventory_rule_request": { + "title": "Create infra inventory rule request", + "description": "A rule that sends notifications when a metric has reached or exceeded a value for a specific resource or a group of resources within your infrastructure.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_infra_inventory" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "metrics.alert.inventory.threshold" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_infra_metric_anomaly_rule_request": { + "title": "Create infrastructure anomaly rule request", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for an infrastructure anomaly rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "metrics.alert.anomaly" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_infra_metric_threshold": { + "properties": { + "criteria": { + "type": "array", + "items": { + "oneOf": [ + { + "title": "non count criterion", + "type": "object", + "properties": { + "threshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "comparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + }, + "timeUnit": { + "type": "string" + }, + "timeSize": { + "type": "number" + }, + "warningThreshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "warningComparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + }, + "metric": { + "type": "string" + }, + "aggType": { + "type": "string", + "enum": [ + "avg", + "max", + "min", + "cardinality", + "rate", + "count", + "sum", + "p95", + "p99", + "custom" + ] + } + } + }, + { + "title": "count criterion", + "type": "object", + "properties": { + "threshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "comparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + }, + "timeUnit": { + "type": "string" + }, + "timeSize": { + "type": "number" + }, + "warningThreshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "warningComparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + }, + "aggType": { + "type": "string", + "enum": [ + "count" + ] + } + } + }, + { + "title": "custom criterion", + "type": "object", + "properties": { + "threshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "comparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + }, + "timeUnit": { + "type": "string" + }, + "timeSize": { + "type": "number" + }, + "warningThreshold": { + "type": "array", + "items": { + "type": "number" + } + }, + "warningComparator": { + "type": "string", + "enum": [ + "<", + "<=", + ">", + ">=", + "between", + "outside" + ] + }, + "aggType": { + "type": "string", + "enum": [ + "custom" + ] + }, + "customMetric": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "aggType": { + "type": "string", + "enum": [ + "avg", + "sum", + "max", + "min", + "cardinality" + ] + }, + "field": { + "type": "string" + } + } + }, + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "aggType": { + "type": "string", + "enum": [ + "count" + ] + }, + "filter": { + "type": "string" + } + } + } + ] + } + }, + "equation": { + "type": "string" + }, + "label": { + "type": "string" + } + } + } + ] + } + }, + "groupBy": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "filterQuery": { + "type": "string" + }, + "sourceId": { + "type": "string" + }, + "alertOnNoData": { + "type": "boolean" + }, + "alertOnGroupDisappear": { + "type": "boolean" + } + } + }, + "create_infra_metric_threshold_rule_request": { + "title": "Create infra metric threshold rule request", + "description": "A rule that sends notifications when a metric has reached or exceeded a value for a specific time period.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_infra_metric_threshold" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "metrics.alert.threshold" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_jvm_memory_usage_rule_request": { + "title": "Create JVM memory usage rule request", + "description": "A rule that detects when a node reports high memory usage.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a JVM memory usage rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_jvm_memory_usage" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_log_threshold": { + "oneOf": [ + { + "title": "Count", + "type": "object", + "required": [ + "count", + "timeSize", + "timeUnit", + "logView" + ], + "properties": { + "criteria": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "example": "my.field" + }, + "comparator": { + "type": "string", + "enum": [ + "more than", + "more than or equals", + "less than", + "less than or equals", + "equals", + "does not equal", + "matches", + "does not match", + "matches phrase", + "does not match phrase" + ] + }, + "value": { + "oneOf": [ + { + "type": "number", + "example": 42 + }, + { + "type": "string", + "example": "value" + } + ] + } + } + } + }, + "count": { + "type": "object", + "properties": { + "comparator": { + "type": "string", + "enum": [ + "more than", + "more than or equals", + "less than", + "less than or equals", + "equals", + "does not equal", + "matches", + "does not match", + "matches phrase", + "does not match phrase" + ] + }, + "value": { + "type": "number", + "example": 100 + } + } + }, + "timeSize": { + "type": "number", + "example": 6 + }, + "timeUnit": { + "type": "string", + "enum": [ + "s", + "m", + "h", + "d" + ] + }, + "logView": { + "type": "object", + "properties": { + "logViewId": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "log-view-reference" + ], + "example": "log-view-reference" + } + } + }, + "groupBy": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "title": "Ratio", + "type": "object", + "required": [ + "count", + "timeSize", + "timeUnit", + "logView" + ], + "properties": { + "criteria": { + "type": "array", + "items": { + "minItems": 2, + "maxItems": 2, + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "example": "my.field" + }, + "comparator": { + "type": "string", + "enum": [ + "more than", + "more than or equals", + "less than", + "less than or equals", + "equals", + "does not equal", + "matches", + "does not match", + "matches phrase", + "does not match phrase" + ] + }, + "value": { + "oneOf": [ + { + "type": "number", + "example": 42 + }, + { + "type": "string", + "example": "value" + } + ] + } + } + } + } + }, + "count": { + "type": "object", + "properties": { + "comparator": { + "type": "string", + "enum": [ + "more than", + "more than or equals", + "less than", + "less than or equals", + "equals", + "does not equal", + "matches", + "does not match", + "matches phrase", + "does not match phrase" + ] + }, + "value": { + "type": "number", + "example": 100 + } + } + }, + "timeSize": { + "type": "number", + "example": 6 + }, + "timeUnit": { + "type": "string", + "enum": [ + "s", + "m", + "h", + "d" + ] + }, + "logView": { + "type": "object", + "properties": { + "logViewId": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "log-view-reference" + ], + "example": "log-view-reference" + } + } + }, + "groupBy": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] + }, + "create_log_threshold_rule_request": { + "title": "Create log threshold rule request", + "description": "A rule that detects when a log aggregation exceeds a threshold.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_log_threshold" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "logs.alert.document.count" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_ccr_exceptions_rule_request": { + "title": "Create CCR read exceptions rule request", + "description": "A rule that detects cross-cluster replication (CCR) read exceptions.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a CCR read exceptions rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_ccr_read_exceptions" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_cluster_health_rule_request": { + "title": "Create cluster health rule request", + "description": "A rule that detects when the health of the cluster changes.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a cluster health rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_cluster_health" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_cpu_usage_rule_request": { + "title": "Create CPU usage rule request", + "description": "A rule that detects when the CPU load for a node is consistently high.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a CPU usage rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_cpu_usage" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_disk_usage_rule_request": { + "title": "Create disk usage rule request", + "description": "A rule that detects when the disk usage for a node is consistently high.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a disk usage rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_disk_usage" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_elasticsearch_version_mismatch_rule_request": { + "title": "Create Elasticsearch version mismatch rule request", + "description": "A rule that detects when the cluster has multipe versions of Elasticsearch.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a Elasticsearch version mismatch rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_elasticsearch_version_mismatch" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_license_expiration_rule_request": { + "title": "Create license expiration rule request", + "description": "A rule that detects when the cluster license is about to expire.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a license expiration rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_license_expiration" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_kibana_version_mismatch_rule_request": { + "title": "Create Kibana version mismatch rule request", + "description": "A rule that detects when the cluster has multiple versions of Kibana.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a Kibana version mismatch rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_kibana_version_mismatch" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_logstash_version_mismatch_rule_request": { + "title": "Create Logstash version mismatch rule request", + "description": "A rule that detects when the cluster has multiple versions of Logstash.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a Logstash version mismatch rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_logstash_version_mismatch" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_missing_data_rule_request": { + "title": "Create missing monitoring data rule request", + "description": "A rule that detects when monitoring data is missing.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a missing monitoring data rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_missing_monitoring_data" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_nodes_changed_rule_request": { + "title": "Create nodes changed rule request", + "description": "A rule that detects when nodes are added, removed, or restarted.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a nodes changed rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_nodes_changed" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_shard_size_rule_request": { + "title": "Create shard size rule request", + "description": "A rule that detects when the average shard size is larger than a threshold.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a shard size rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_shard_size" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_thread_pool_search_rejections_rule_request": { + "title": "Create thread pool search rejections rule request", + "description": "A rule that detects when the number of rejections in the thread pool exceeds a threshold.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a thread pool search rejections rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_thread_pool_search_rejections" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_monitoring_thread_pool_write_rejections_rule_request": { + "title": "Create thread pool write rejections rule request", + "description": "A rule that detects when the number of rejections in the write thread pool exceeds a threshold.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a thread pool write rejections rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "monitoring_alert_thread_pool_write_rejections" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_eql_rule_request": { + "title": "Create event correlation rule request", + "description": "A rule that uses Event Query Language (EQL) to match events, generate sequences, and stack data.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for an event correlation rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.eqlRule" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_indicator_rule_request": { + "title": "Create indicator match rule request", + "description": "A rule that uses indicators from intelligence sources to detect matching events and alerts.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for an indicator match rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.indicatorRule" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_ml_rule_request": { + "title": "Create machine learning rule request", + "description": "A rule that detects when a machine learning job discovers an anomaly above the defined threshold.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a machine learning rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.mlRule" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_new_terms_rule_request": { + "title": "Create new terms rule request", + "description": "A rule that finds documents with values that appear for the first time.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a new terms rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.newTermsRule" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_notifications_rule_request": { + "title": "Create security solution notification (legacy) rule request", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a notification rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.notifications" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_query_rule_request": { + "title": "Create custom query rule request", + "description": "A rule that uses KQL or Lucene to detect issues across indices.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a custom query rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.queryRule" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_saved_query_rule_request": { + "title": "Create saved query rule request", + "description": "A rule that searches the defined indices and creates an alert when a document matches the saved search.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a saved query rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.savedQueryRule" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_siem_threshold_rule_request": { + "title": "Create threshold rule request", + "description": "A rule that aggregates query results to detect when the number of matches exceeds a threshold.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a threshold rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "siem.thresholdRule" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_slo_burn_rate": { + "properties": { + "sloId": { + "description": "The SLO identifier used by the rule", + "type": "string", + "example": "8853df00-ae2e-11ed-90af-09bb6422b258" + }, + "burnRateThreshold": { + "description": "The burn rate threshold used to trigger the alert", + "type": "number", + "example": 14.4 + }, + "maxBurnRateThreshold": { + "description": "The maximum burn rate threshold value defined by the SLO error budget", + "type": "number", + "example": 168 + }, + "longWindow": { + "description": "The duration of the long window used to compute the burn rate", + "type": "object", + "properties": { + "value": { + "description": "The duration value", + "type": "number", + "example": 6 + }, + "unit": { + "description": "The duration unit", + "type": "string", + "example": "h" + } + } + }, + "shortWindow": { + "description": "The duration of the short window used to compute the burn rate", + "type": "object", + "properties": { + "value": { + "description": "The duration value", + "type": "number", + "example": 30 + }, + "unit": { + "description": "The duration unit", + "type": "string", + "example": "m" + } + } + } + } + }, + "create_slo_burn_rate_rule_request": { + "title": "Create slo burn rate rule request", + "description": "A rule that detects when the burn rate is above a defined threshold for two different lookback periods. The two periods are a long period and a short period that is 1/12th of the long period. For each lookback period, the burn rate is computed as the error rate divided by the error budget. When the burn rates for both periods surpass the threshold, an alert occurs.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_slo_burn_rate" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "slo.rules.burnRate" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_synthetics_monitor_status_rule_request": { + "title": "Create synthetics monitor status rule request", + "description": "A rule that detects when a monitor is down or an availability threshold is breached.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for the synthetics monitor status rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "xpack.synthetics.alerts.monitorStatus" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_synthetics_uptime_duration_anomaly_rule_request": { + "title": "Create synthetics uptime duration anomaly rule request", + "description": "A rule that detects response durations for all of the geographic locations of each monitor. When a monitor runs for an unusual amount of time, at a particular time, an anomaly is recorded.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for the uptime duration anomaly rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "xpack.uptime.alerts.durationAnomaly" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_synthetics_uptime_tls": { + "properties": { + "search": { + "type": "string" + }, + "certExpirationThreshold": { + "type": "number" + }, + "certAgeThreshold": { + "type": "number" + } + } + }, + "create_synthetics_uptime_tls_rule_request": { + "title": "Create synthetics uptime TLS rule request", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_synthetics_uptime_tls" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "xpack.uptime.alerts.tls" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_synthetics_uptime_tls_certificate_rule_request": { + "title": "Create TLS certificate rule request", + "description": "A rule that detects when a monitor has a TLS certificate expiring or when it exceeds an age limit.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a TLS certificate rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "xpack.uptime.alerts.tlsCertificate" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_transform_health_rule_request": { + "title": "Create transform health rule request", + "description": "A rule that monitors transforms health and alerts if an operational issue occurred.\n", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for a transform health rule.", + "additionalProperties": true + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "transform_health" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "params_property_synthetics_monitor_status": { + "required": [ + "numTimes", + "shouldCheckStatus", + "shouldCheckAvailability" + ], + "properties": { + "availability": { + "type": "object", + "properties": { + "range": { + "type": "number" + }, + "rangeUnit": { + "type": "string" + }, + "threshold": { + "type": "string" + } + } + }, + "filters": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "deprecated": true, + "properties": { + "monitor.type": { + "type": "array", + "items": { + "type": "string" + } + }, + "observer.geo.name": { + "type": "array", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "url.port": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] + }, + "locations": { + "deprecated": true, + "type": "array", + "items": { + "type": "string" + } + }, + "numTimes": { + "type": "number" + }, + "search": { + "type": "string" + }, + "shouldCheckStatus": { + "type": "boolean" + }, + "shouldCheckAvailability": { + "type": "boolean" + }, + "timerangeCount": { + "type": "number" + }, + "timerangeUnit": { + "type": "string" + }, + "timerange": { + "deprecated": true, + "type": "object", + "properties": { + "from": { + "type": "string" + }, + "to": { + "type": "string" + } + } + }, + "version": { + "type": "number" + }, + "isAutoGenerated": { + "type": "boolean" + } + } + }, + "create_uptime_monitor_status_rule_request": { + "title": "Create uptime monitor status rule request", + "description": "A rule that detects monitor errors and outages.", + "type": "object", + "required": [ + "consumer", + "name", + "params", + "rule_type_id", + "schedule" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "consumer": { + "$ref": "#/components/schemas/consumer" + }, + "enabled": { + "$ref": "#/components/schemas/enabled_rule" + }, + "name": { + "$ref": "#/components/schemas/name_rule" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "$ref": "#/components/schemas/params_property_synthetics_monitor_status" + }, + "rule_type_id": { + "type": "string", + "description": "The ID of the rule type that you want to call when the rule is scheduled to run.", + "enum": [ + "xpack.uptime.alerts.monitorStatus" + ] + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + } + } + }, + "create_rule_request": { + "title": "Create rule request body properties", + "description": "The properties vary depending on the rule type.", + "oneOf": [ + { + "$ref": "#/components/schemas/create_anomaly_detection_alert_rule_request" + }, + { + "$ref": "#/components/schemas/create_anomaly_detection_jobs_health_rule_request" + }, + { + "$ref": "#/components/schemas/create_apm_anomaly_rule_request" + }, + { + "$ref": "#/components/schemas/create_apm_error_count_rule_request" + }, + { + "$ref": "#/components/schemas/create_apm_transaction_duration_rule_request" + }, + { + "$ref": "#/components/schemas/create_apm_transaction_error_rate_rule_request" + }, + { + "$ref": "#/components/schemas/create_es_query_rule_request" + }, + { + "$ref": "#/components/schemas/create_geo_containment_rule_request" + }, + { + "$ref": "#/components/schemas/create_index_threshold_rule_request" + }, + { + "$ref": "#/components/schemas/create_infra_inventory_rule_request" + }, + { + "$ref": "#/components/schemas/create_infra_metric_anomaly_rule_request" + }, + { + "$ref": "#/components/schemas/create_infra_metric_threshold_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_jvm_memory_usage_rule_request" + }, + { + "$ref": "#/components/schemas/create_log_threshold_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_ccr_exceptions_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_cluster_health_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_cpu_usage_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_disk_usage_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_elasticsearch_version_mismatch_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_license_expiration_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_kibana_version_mismatch_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_logstash_version_mismatch_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_missing_data_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_nodes_changed_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_shard_size_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_thread_pool_search_rejections_rule_request" + }, + { + "$ref": "#/components/schemas/create_monitoring_thread_pool_write_rejections_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_eql_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_indicator_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_ml_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_new_terms_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_notifications_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_query_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_saved_query_rule_request" + }, + { + "$ref": "#/components/schemas/create_siem_threshold_rule_request" + }, + { + "$ref": "#/components/schemas/create_slo_burn_rate_rule_request" + }, + { + "$ref": "#/components/schemas/create_synthetics_monitor_status_rule_request" + }, + { + "$ref": "#/components/schemas/create_synthetics_uptime_duration_anomaly_rule_request" + }, + { + "$ref": "#/components/schemas/create_synthetics_uptime_tls_rule_request" + }, + { + "$ref": "#/components/schemas/create_synthetics_uptime_tls_certificate_rule_request" + }, + { + "$ref": "#/components/schemas/create_transform_health_rule_request" + }, + { + "$ref": "#/components/schemas/create_uptime_monitor_status_rule_request" + } + ], + "discriminator": { + "propertyName": "rule_type_id" + } + }, + "rule_response_properties": { + "title": "Rule response properties", + "type": "object", + "required": [ + "actions", + "api_key_owner", + "consumer", + "created_at", + "created_by", + "enabled", + "execution_status", + "id", + "mute_all", + "muted_alert_ids", + "name", + "params", + "rule_type_id", + "schedule", + "tags", + "throttle", + "updated_at", + "updated_by" + ], + "properties": { + "actions": { + "$ref": "#/components/schemas/actions" + }, + "api_key_created_by_user": { + "type": "boolean", + "description": "Indicates whether the API key that is associated with the rule was created by the user.", + "example": false + }, + "api_key_owner": { + "type": "string", + "description": "The owner of the API key that is associated with the rule and used to run background tasks.\n", + "nullable": true, + "example": "elastic" + }, + "consumer": { + "type": "string", + "description": "The application or feature that owns the rule. For example, `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`.", + "example": "alerts" + }, + "created_at": { + "type": "string", + "description": "The date and time that the rule was created.", + "format": "date-time", + "example": "2022-12-05T23:36:58.284Z" + }, + "created_by": { + "type": "string", + "description": "The identifier for the user that created the rule.", + "nullable": true, + "example": "elastic" + }, + "enabled": { + "type": "boolean", + "description": "Indicates whether the rule is currently enabled.", + "example": true + }, + "execution_status": { + "type": "object", + "properties": { + "last_duration": { + "type": "integer", + "example": 55 + }, + "last_execution_date": { + "type": "string", + "format": "date-time", + "example": "2022-12-06T00:13:43.890Z" + }, + "status": { + "type": "string", + "example": "ok" + } + } + }, + "id": { + "type": "string", + "description": "The identifier for the rule.", + "example": "b530fed0-74f5-11ed-9801-35303b735aef" + }, + "last_run": { + "type": "object", + "properties": { + "alerts_count": { + "type": "object", + "properties": { + "active": { + "type": "integer" + }, + "ignored": { + "type": "integer" + }, + "new": { + "type": "integer" + }, + "recovered": { + "type": "integer" + } + } + }, + "outcome": { + "type": "string", + "example": "succeeded" + }, + "outcome_msg": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "outcome_order": { + "type": "integer" + }, + "warning": { + "type": "string", + "nullable": true, + "example": null + } + } + }, + "muted_alert_ids": { + "type": "array", + "nullable": true, + "items": { + "type": "string" + } + }, + "mute_all": { + "type": "boolean", + "example": false + }, + "name": { + "type": "string", + "description": "The name of the rule.", + "example": "cluster_health_rule" + }, + "next_run": { + "type": "string", + "format": "date-time", + "nullable": true, + "example": "2022-12-06T00:14:43.818Z" + }, + "notify_when": { + "$ref": "#/components/schemas/notify_when" + }, + "params": { + "type": "object", + "description": "The parameters for the rule.", + "additionalProperties": true + }, + "revision": { + "type": "integer", + "description": "The rule revision number." + }, + "rule_type_id": { + "type": "string", + "description": "The identifier for the type of rule. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`.\n", + "example": "monitoring_alert_cluster_health" + }, + "running": { + "type": "boolean", + "description": "Indicates whether the rule is running." + }, + "schedule": { + "$ref": "#/components/schemas/schedule" + }, + "scheduled_task_id": { + "type": "string", + "example": "b530fed0-74f5-11ed-9801-35303b735aef" + }, + "tags": { + "$ref": "#/components/schemas/tags" + }, + "throttle": { + "$ref": "#/components/schemas/throttle" + }, + "updated_at": { + "type": "string", + "description": "The date and time that the rule was updated most recently.", + "example": "2022-12-05T23:36:58.284Z" + }, + "updated_by": { + "type": "string", + "description": "The identifier for the user that updated this rule most recently.", + "nullable": true, + "example": "elastic" + } + } + }, + "401_response": { + "type": "object", + "title": "Unsuccessful rule API response", + "properties": { + "error": { + "type": "string", + "example": "Unauthorized", + "enum": [ + "Unauthorized" + ] + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "integer", + "example": 401, + "enum": [ + 401 + ] + } + } + }, + "404_response": { + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Not Found", + "enum": [ + "Not Found" + ] + }, + "message": { + "type": "string", + "example": "Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found" }, - "throttle": { - "$ref": "#/components/schemas/throttle" + "statusCode": { + "type": "integer", + "example": 404, + "enum": [ + 404 + ] } } }, - "create_rule_request": { - "title": "Create rule request", - "description": "The create rule API request body varies depending on the type of rule and actions.", + "update_rule_request": { + "title": "Update rule request", + "description": "The update rule API request body varies depending on the type of rule and actions.", "type": "object", "required": [ - "consumer", "name", "params", - "rule_type_id", "schedule" ], "properties": { "actions": { "$ref": "#/components/schemas/actions" }, - "consumer": { - "type": "string", - "description": "The name of the application or feature that owns the rule. For example: `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`.\n" - }, - "enabled": { - "type": "boolean", - "description": "Indicates whether you want to run the rule on an interval basis after it is created." - }, "name": { "type": "string", - "description": "The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.", + "description": "The name of the rule.", "example": "cluster_health_rule" }, "notify_when": { @@ -2972,10 +6257,6 @@ "description": "The parameters for the rule.", "additionalProperties": true }, - "rule_type_id": { - "type": "string", - "description": "The ID of the rule type that you want to call when the rule is scheduled to run. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`.\n" - }, "schedule": { "$ref": "#/components/schemas/schedule" }, @@ -3101,6 +6382,117 @@ } }, "examples": { + "create_rule_request": { + "summary": "Create an index threshold rule.", + "value": { + "actions": [ + { + "id": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2", + "frequency": { + "notify_when": "onActionGroupChange", + "summary": false + }, + "group": "threshold met", + "params": { + "level": "info", + "message": "alert '{{alertName}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}" + } + } + ], + "consumer": "alerts", + "name": "my rule", + "params": { + "aggType": "avg", + "termSize": 6, + "thresholdComparator": ">", + "timeWindowSize": 5, + "timeWindowUnit": "m", + "groupBy": "top", + "threshold": [ + 1000 + ], + "index": [ + ".test-index" + ], + "timeField": "@timestamp", + "aggField": "sheet.version", + "termField": "name.keyword" + }, + "rule_type_id": ".index-threshold", + "schedule": { + "interval": "1m" + }, + "tags": [ + "cpu" + ] + } + }, + "create_rule_response": { + "summary": "The create rule API returns a JSON object that contains details about the rule.", + "value": { + "actions": [ + { + "group": "threshold met", + "id": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2", + "uuid": "07aef2a0-9eed-4ef9-94ec-39ba58eb609d", + "frequency": { + "notify_when": "onActionGroupChange", + "summary": false, + "throttle": null + }, + "params": { + "level": "info", + "message": "alert {{alertName}} is active for group {{context.group} :\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}" + } + } + ], + "api_key_created_by_user": false, + "api_key_owner": "elastic", + "consumer": "alerts", + "created_at": "2022-06-08T17:20:31.632Z", + "created_by": "elastic", + "enabled": true, + "execution_status": { + "last_execution_date": "2022-06-08T17:20:31.632Z", + "status": "pending" + }, + "id": "41893910-6bca-11eb-9e0d-85d233e3ee35", + "muted_alert_ids": [], + "mute_all": false, + "name": "my rule", + "notify_when": "onActionGroupChange", + "params": { + "aggType": "avg", + "termSize": 6, + "thresholdComparator": ">", + "timeWindowSize": 5, + "timeWindowUnit": "m", + "groupBy": "top", + "threshold": [ + 1000 + ], + "index": [ + ".test-index" + ], + "timeField": "@timestamp", + "aggField": "sheet.version", + "termField": "name.keyword" + }, + "revision": 0, + "rule_type_id": ".index-threshold", + "running": false, + "schedule": { + "interval": "1m" + }, + "scheduled_task_id": "425b0800-6bca-11eb-9e0d-85d233e3ee35", + "tags": [ + "cpu" + ], + "throttle": null, + "updated_at": "2022-06-08T17:20:31.632Z", + "updated_by": "elastic" + } + }, "get_rule_response": { "summary": "The get rule API returns a JSON object that contains details about the rule.", "value": { @@ -3294,117 +6686,6 @@ "api_key_created_by_user": false } }, - "create_rule_request": { - "summary": "Create an index threshold rule.", - "value": { - "actions": [ - { - "id": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2", - "frequency": { - "notify_when": "onActionGroupChange", - "summary": false - }, - "group": "threshold met", - "params": { - "level": "info", - "message": "alert '{{alertName}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}" - } - } - ], - "consumer": "alerts", - "name": "my rule", - "params": { - "aggType": "avg", - "termSize": 6, - "thresholdComparator": ">", - "timeWindowSize": 5, - "timeWindowUnit": "m", - "groupBy": "top", - "threshold": [ - 1000 - ], - "index": [ - ".test-index" - ], - "timeField": "@timestamp", - "aggField": "sheet.version", - "termField": "name.keyword" - }, - "rule_type_id": ".index-threshold", - "schedule": { - "interval": "1m" - }, - "tags": [ - "cpu" - ] - } - }, - "create_rule_response": { - "summary": "The create rule API returns a JSON object that contains details about the rule.", - "value": { - "actions": [ - { - "group": "threshold met", - "id": "dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2", - "uuid": "07aef2a0-9eed-4ef9-94ec-39ba58eb609d", - "frequency": { - "notify_when": "onActionGroupChange", - "summary": false, - "throttle": null - }, - "params": { - "level": "info", - "message": "alert {{alertName}} is active for group {{context.group} :\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}" - } - } - ], - "api_key_created_by_user": false, - "api_key_owner": "elastic", - "consumer": "alerts", - "created_at": "2022-06-08T17:20:31.632Z", - "created_by": "elastic", - "enabled": true, - "execution_status": { - "last_execution_date": "2022-06-08T17:20:31.632Z", - "status": "pending" - }, - "id": "41893910-6bca-11eb-9e0d-85d233e3ee35", - "muted_alert_ids": [], - "mute_all": false, - "name": "my rule", - "notify_when": "onActionGroupChange", - "params": { - "aggType": "avg", - "termSize": 6, - "thresholdComparator": ">", - "timeWindowSize": 5, - "timeWindowUnit": "m", - "groupBy": "top", - "threshold": [ - 1000 - ], - "index": [ - ".test-index" - ], - "timeField": "@timestamp", - "aggField": "sheet.version", - "termField": "name.keyword" - }, - "revision": 0, - "rule_type_id": ".index-threshold", - "running": false, - "schedule": { - "interval": "1m" - }, - "scheduled_task_id": "425b0800-6bca-11eb-9e0d-85d233e3ee35", - "tags": [ - "cpu" - ], - "throttle": null, - "updated_at": "2022-06-08T17:20:31.632Z", - "updated_by": "elastic" - } - }, "find_rules_response": { "summary": "Retrieve information about a rule.", "value": { diff --git a/x-pack/plugins/alerting/docs/openapi/bundled.yaml b/x-pack/plugins/alerting/docs/openapi/bundled.yaml index 1d5881c0c2304..b5ac98b843b0d 100644 --- a/x-pack/plugins/alerting/docs/openapi/bundled.yaml +++ b/x-pack/plugins/alerting/docs/openapi/bundled.yaml @@ -15,6 +15,52 @@ servers: - url: http://localhost:5601 description: local paths: + /s/{spaceId}/api/alerting/rule: + post: + summary: Creates a rule with a randomly generated rule identifier. + operationId: createRule + description: | + You must have `all` privileges for the appropriate Kibana features, depending on the `consumer` and `rule_type_id` of the rule you're creating. For example, you must have privileges for the **Management > Stack rules** feature, **Analytics > Discover** and **Machine Learning** features, **Observability** features, or **Security** features. If the rule has actions, you must also have `read` privileges for the **Management > Actions and Connectors** feature. NOTE: This API supports only token-based authentication. When you create a rule, it identifies which roles you have at that point in time. Thereafter, when the rule performs queries, it uses those security privileges. If a user with different privileges updates the rule, its behavior might change. + tags: + - alerting + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + - $ref: '#/components/parameters/space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/create_rule_request' + examples: + createRuleRequest: + $ref: '#/components/examples/create_rule_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/rule_response_properties' + examples: + createRuleResponse: + $ref: '#/components/examples/create_rule_response' + '401': + description: Authorization information is missing or invalid. + content: + application/json: + schema: + $ref: '#/components/schemas/401_response' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '#/components/schemas/404_response' + servers: + - url: https://localhost:5601 + servers: + - url: https://localhost:5601 /s/{spaceId}/api/alerting/rule/{ruleId}: get: summary: Retrieves a rule by its identifier. @@ -79,8 +125,8 @@ paths: servers: - url: https://localhost:5601 post: - summary: Creates a rule. - operationId: createRule + summary: Creates a rule with a specific rule identifier. + operationId: createRuleId description: | You must have `all` privileges for the appropriate Kibana features, depending on the `consumer` and `rule_type_id` of the rule you're creating. For example, you must have privileges for the **Management > Stack rules** feature, **Analytics > Discover** and **Machine Learning** features, **Observability** features, or **Security** features. If the rule has actions, you must also have `read` privileges for the **Management > Actions and Connectors** feature. NOTE: This API supports only token-based authentication. When you create a rule, it identifies which roles you have at that point in time. Thereafter, when the rule performs queries, it uses those security privileges. If a user with different privileges updates the rule, its behavior might change. tags: @@ -103,7 +149,7 @@ paths: schema: $ref: '#/components/schemas/create_rule_request' examples: - createCaseRequest: + createRuleIdRequest: $ref: '#/components/examples/create_rule_request' responses: '200': @@ -113,7 +159,7 @@ paths: schema: $ref: '#/components/schemas/rule_response_properties' examples: - createRuleResponse: + createRuleIdResponse: $ref: '#/components/examples/create_rule_response' '401': description: Authorization information is missing or invalid. @@ -147,7 +193,7 @@ paths: schema: $ref: '#/components/schemas/update_rule_request' examples: - updateCaseRequest: + updateRuleRequest: $ref: '#/components/examples/update_rule_request' responses: '200': @@ -1515,14 +1561,13 @@ components: in: header name: ApiKey parameters: - rule_id: - in: path - name: ruleId - description: An identifier for the rule. - required: true + kbn_xsrf: schema: type: string - example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 + in: header + name: kbn-xsrf + description: Cross-site request forgery protection + required: true space_id: in: path name: spaceId @@ -1531,13 +1576,14 @@ components: schema: type: string example: default - kbn_xsrf: + rule_id: + in: path + name: ruleId + description: An identifier for the rule. + required: true schema: type: string - in: header - name: kbn-xsrf - description: Cross-site request forgery protection - required: true + example: ac4e6b90-6be7-11eb-ba0d-9b1c1f912d74 alert_id: in: path name: alertId @@ -1692,6 +1738,17 @@ components: type: string description: A universally unique identifier (UUID) for the action. example: 1c7a1280-f28c-4e06-96b2-e4e5f05d1d61 + consumer: + type: string + description: | + The name of the application or feature that owns the rule. For example: `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. + enabled_rule: + type: boolean + description: Indicates whether you want to run the rule on an interval basis after it is created. + name_rule: + type: string + description: | + The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule. schedule: type: object description: The check interval, which specifies how frequently the rule conditions are checked. The interval is specified in seconds, minutes, hours, or days. @@ -1705,218 +1762,118 @@ components: items: type: string default: [] - rule_response_properties: - title: Rule response properties + create_anomaly_detection_alert_rule_request: + title: Create anomaly detection rule request + description: | + A rule that checks if the anomaly detection job results contain anomalies that match the rule conditions. type: object required: - - actions - - api_key_owner - consumer - - created_at - - created_by - - enabled - - execution_status - - id - - mute_all - - muted_alert_ids - name - params - rule_type_id - schedule - - tags - - throttle - - updated_at - - updated_by properties: actions: $ref: '#/components/schemas/actions' - api_key_created_by_user: - type: boolean - description: Indicates whether the API key that is associated with the rule was created by the user. - example: false - api_key_owner: - type: string - description: | - The owner of the API key that is associated with the rule and used to run background tasks. - nullable: true - example: elastic consumer: - type: string - description: The application or feature that owns the rule. For example, `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. - example: alerts - created_at: - type: string - description: The date and time that the rule was created. - format: date-time - example: '2022-12-05T23:36:58.284Z' - created_by: - type: string - description: The identifier for the user that created the rule. - nullable: true - example: elastic + $ref: '#/components/schemas/consumer' enabled: - type: boolean - description: Indicates whether the rule is currently enabled. - example: true - execution_status: - type: object - properties: - last_duration: - type: integer - example: 55 - last_execution_date: - type: string - format: date-time - example: '2022-12-06T00:13:43.890Z' - status: - type: string - example: ok - id: - type: string - description: The identifier for the rule. - example: b530fed0-74f5-11ed-9801-35303b735aef - last_run: - type: object - properties: - alerts_count: - type: object - properties: - active: - type: integer - ignored: - type: integer - new: - type: integer - recovered: - type: integer - outcome: - type: string - example: succeeded - outcome_msg: - type: array - items: - type: string - nullable: true - outcome_order: - type: integer - warning: - type: string - nullable: true - example: null - muted_alert_ids: - type: array - nullable: true - items: - type: string - mute_all: - type: boolean - example: false + $ref: '#/components/schemas/enabled_rule' name: - type: string - description: The name of the rule. - example: cluster_health_rule - next_run: - type: string - format: date-time - nullable: true - example: '2022-12-06T00:14:43.818Z' + $ref: '#/components/schemas/name_rule' notify_when: $ref: '#/components/schemas/notify_when' params: type: object - description: The parameters for the rule. + description: The parameters for an anomaly detection rule. additionalProperties: true - revision: - type: integer - description: The rule revision number. rule_type_id: type: string - description: | - The identifier for the type of rule. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`. - example: monitoring_alert_cluster_health - running: - type: boolean - description: Indicates whether the rule is running. + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.ml.anomaly_detection_alert schedule: $ref: '#/components/schemas/schedule' - scheduled_task_id: - type: string - example: b530fed0-74f5-11ed-9801-35303b735aef tags: $ref: '#/components/schemas/tags' throttle: $ref: '#/components/schemas/throttle' - updated_at: - type: string - description: The date and time that the rule was updated most recently. - example: '2022-12-05T23:36:58.284Z' - updated_by: - type: string - description: The identifier for the user that updated this rule most recently. - nullable: true - example: elastic - 401_response: - type: object - title: Unsuccessful rule API response - properties: - error: - type: string - example: Unauthorized - enum: - - Unauthorized - message: - type: string - statusCode: - type: integer - example: 401 - enum: - - 401 - 404_response: - type: object - properties: - error: - type: string - example: Not Found - enum: - - Not Found - message: - type: string - example: Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found - statusCode: - type: integer - example: 404 - enum: - - 404 - update_rule_request: - title: Update rule request - description: The update rule API request body varies depending on the type of rule and actions. + create_anomaly_detection_jobs_health_rule_request: + title: Create anomaly detection jobs health rule request + description: | + An rule that monitors job health and alerts if an operational issue occurred that may prevent the job from detecting anomalies. type: object required: + - consumer - name - params + - rule_type_id - schedule properties: actions: $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' name: - type: string - description: The name of the rule. - example: cluster_health_rule + $ref: '#/components/schemas/name_rule' notify_when: $ref: '#/components/schemas/notify_when' params: type: object - description: The parameters for the rule. + description: The parameters for an anomaly detection jobs health rule. additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.ml.anomaly_detection_jobs_health schedule: $ref: '#/components/schemas/schedule' tags: $ref: '#/components/schemas/tags' throttle: $ref: '#/components/schemas/throttle' - create_rule_request: - title: Create rule request - description: The create rule API request body varies depending on the type of rule and actions. + params_property_apm_anomaly: + required: + - windowSize + - windowUnit + - environment + - anomalySeverityType + properties: + serviceName: + type: string + description: The service name from APM + transactionType: + type: string + description: The transaction type from APM + windowSize: + type: number + example: 6 + description: The window size + windowUnit: + type: string + description: The window size unit + enum: + - m + - h + - d + environment: + type: string + description: The environment from APM + anomalySeverityType: + type: string + description: The anomaly threshold value + enum: + - critical + - major + - minor + - warning + create_apm_anomaly_rule_request: + title: Create APM anomaly rule rule request + description: A rule that detects when either the latency, throughput, or failed transaction rate of a service is anomalous. type: object required: - consumer @@ -1928,15 +1885,2368 @@ components: actions: $ref: '#/components/schemas/actions' consumer: - type: string - description: | - The name of the application or feature that owns the rule. For example: `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. + $ref: '#/components/schemas/consumer' enabled: - type: boolean - description: Indicates whether you want to run the rule on an interval basis after it is created. + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_apm_anomaly' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.anomaly + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_apm_error_count: + required: + - windowSize + - windowUnit + - threshold + - environment + properties: + serviceName: + type: string + description: The service name from APM + windowSize: + type: number + description: The window size + example: 6 + windowUnit: + type: string + description: The window size unit + enum: + - m + - h + - d + environment: + type: string + description: The environment from APM + threshold: + type: number + description: The error count threshold value + groupBy: + type: array + default: + - service.name + - service.environment + uniqueItems: true + items: + type: string + enum: + - service.name + - service.environment + - transaction.name + - error.grouping_key + errorGroupingKey: + type: string + create_apm_error_count_rule_request: + title: Create APM error count rule request + description: A rule that detects when the number of errors in a service exceeds a defined threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_apm_error_count' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.error_rate + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_apm_transaction_duration: + required: + - windowSize + - windowUnit + - threshold + - environment + - aggregationType + properties: + serviceName: + type: string + description: The service name from APM + transactionType: + type: string + description: The transaction type from APM + transactionName: + type: string + description: The transaction name from APM + windowSize: + type: number + description: The window size + example: 6 + windowUnit: + type: string + description: ç + enum: + - m + - h + - d + environment: + type: string + threshold: + type: number + description: The latency threshold value + groupBy: + type: array + default: + - service.name + - service.environment + - transaction.type + uniqueItems: true + items: + type: string + enum: + - service.name + - service.environment + - transaction.type + - transaction.name + aggregationType: + type: string + enum: + - avg + - 95th + - 99th + create_apm_transaction_duration_rule_request: + title: Create latency threshold rule request + description: A rule that detects when the latency of a specific transaction type in a service exceeds a threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_apm_transaction_duration' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.transaction_duration + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_apm_transaction_error_rate: + required: + - windowSize + - windowUnit + - threshold + - environment + properties: + serviceName: + type: string + description: The service name from APM + transactionType: + type: string + description: The transaction type from APM + transactionName: + type: string + description: The transaction name from APM + windowSize: + type: number + description: The window size + example: 6 + windowUnit: + type: string + description: The window size unit + enum: + - m + - h + - d + environment: + type: string + description: The environment from APM + threshold: + type: number + description: The error rate threshold value + groupBy: + type: array + default: + - service.name + - service.environment + - transaction.type + uniqueItems: true + items: + type: string + enum: + - service.name + - service.environment + - transaction.type + - transaction.name + create_apm_transaction_error_rate_rule_request: + title: Create APM transaction error rate rule request + description: A rule that sends notifications when the rate of transaction errors in a service exceeds a threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_apm_transaction_error_rate' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.transaction_error_rate + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_es_query_rule_request: + title: Create Elasticsearch query rule request + description: | + A rule that runs a user-configured query, compares the number of matches to a configured threshold, and schedules actions to run when the threshold condition is met. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for an Elasticsearch query rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - .es-query + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_geo_containment_rule_request: + title: Create traacking containment rule request + description: | + A rule that runs an Elasticsearch query over indices to determine whether any documents are currently contained within any boundaries from the specified boundary index. In the event that an entity is contained within a boundary, an alert may be generated. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for an tracking containment rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - .geo-containment + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_index_threshold_rule_request: + title: Create index threshold rule request + description: A rule that runs an Elasticsearch query, aggregates field values from documents, compares them to threshold values, and schedules actions to run when the thresholds are met. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for an index threshold rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - .index-threshold + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_infra_inventory: + properties: + criteria: + type: array + items: + type: object + properties: + metric: + type: string + enum: + - count + - cpu + - diskLatency + - load + - memory + - memoryTotal + - tx + - rx + - logRate + - diskIOReadBytes + - diskIOWriteBytes + - s3TotalRequests + - s3NumberOfObjects + - s3BucketSize + - s3DownloadBytes + - s3UploadBytes + - rdsConnections + - rdsQueriesExecuted + - rdsActiveTransactions + - rdsLatency + - sqsMessagesVisible + - sqsMessagesDelayed + - sqsMessagesSent + - sqsMessagesEmpty + - sqsOldestMessage + - custom + timeSize: + type: number + timeUnit: + type: string + enum: + - s + - m + - h + - d + sourceId: + type: string + threshold: + type: array + items: + type: number + comparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + customMetric: + type: object + properties: + type: + type: string + enum: + - custom + field: + type: string + aggregation: + type: string + enum: + - avg + - max + - min + - rate + id: + type: string + label: + type: string + warningThreshold: + type: array + items: + type: number + warningComparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + filterQuery: + type: string + filterQueryText: + type: string + nodeType: + type: string + enum: + - host + - pod + - container + - awsEC2 + - awsS3 + - awsSQS + - awsRDS + sourceId: + type: string + alertOnNoData: + type: boolean + create_infra_inventory_rule_request: + title: Create infra inventory rule request + description: | + A rule that sends notifications when a metric has reached or exceeded a value for a specific resource or a group of resources within your infrastructure. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_infra_inventory' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - metrics.alert.inventory.threshold + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_infra_metric_anomaly_rule_request: + title: Create infrastructure anomaly rule request + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for an infrastructure anomaly rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - metrics.alert.anomaly + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_infra_metric_threshold: + properties: + criteria: + type: array + items: + oneOf: + - title: non count criterion + type: object + properties: + threshold: + type: array + items: + type: number + comparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + timeUnit: + type: string + timeSize: + type: number + warningThreshold: + type: array + items: + type: number + warningComparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + metric: + type: string + aggType: + type: string + enum: + - avg + - max + - min + - cardinality + - rate + - count + - sum + - p95 + - p99 + - custom + - title: count criterion + type: object + properties: + threshold: + type: array + items: + type: number + comparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + timeUnit: + type: string + timeSize: + type: number + warningThreshold: + type: array + items: + type: number + warningComparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + aggType: + type: string + enum: + - count + - title: custom criterion + type: object + properties: + threshold: + type: array + items: + type: number + comparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + timeUnit: + type: string + timeSize: + type: number + warningThreshold: + type: array + items: + type: number + warningComparator: + type: string + enum: + - < + - <= + - '>' + - '>=' + - between + - outside + aggType: + type: string + enum: + - custom + customMetric: + type: array + items: + oneOf: + - type: object + properties: + name: + type: string + aggType: + type: string + enum: + - avg + - sum + - max + - min + - cardinality + field: + type: string + - type: object + properties: + name: + type: string + aggType: + type: string + enum: + - count + filter: + type: string + equation: + type: string + label: + type: string + groupBy: + oneOf: + - type: string + - type: array + items: + type: string + filterQuery: + type: string + sourceId: + type: string + alertOnNoData: + type: boolean + alertOnGroupDisappear: + type: boolean + create_infra_metric_threshold_rule_request: + title: Create infra metric threshold rule request + description: | + A rule that sends notifications when a metric has reached or exceeded a value for a specific time period. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_infra_metric_threshold' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - metrics.alert.threshold + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_jvm_memory_usage_rule_request: + title: Create JVM memory usage rule request + description: A rule that detects when a node reports high memory usage. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a JVM memory usage rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_jvm_memory_usage + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_log_threshold: + oneOf: + - title: Count + type: object + required: + - count + - timeSize + - timeUnit + - logView + properties: + criteria: + type: array + items: + type: object + properties: + field: + type: string + example: my.field + comparator: + type: string + enum: + - more than + - more than or equals + - less than + - less than or equals + - equals + - does not equal + - matches + - does not match + - matches phrase + - does not match phrase + value: + oneOf: + - type: number + example: 42 + - type: string + example: value + count: + type: object + properties: + comparator: + type: string + enum: + - more than + - more than or equals + - less than + - less than or equals + - equals + - does not equal + - matches + - does not match + - matches phrase + - does not match phrase + value: + type: number + example: 100 + timeSize: + type: number + example: 6 + timeUnit: + type: string + enum: + - s + - m + - h + - d + logView: + type: object + properties: + logViewId: + type: string + type: + type: string + enum: + - log-view-reference + example: log-view-reference + groupBy: + type: array + items: + type: string + - title: Ratio + type: object + required: + - count + - timeSize + - timeUnit + - logView + properties: + criteria: + type: array + items: + minItems: 2 + maxItems: 2 + type: array + items: + type: object + properties: + field: + type: string + example: my.field + comparator: + type: string + enum: + - more than + - more than or equals + - less than + - less than or equals + - equals + - does not equal + - matches + - does not match + - matches phrase + - does not match phrase + value: + oneOf: + - type: number + example: 42 + - type: string + example: value + count: + type: object + properties: + comparator: + type: string + enum: + - more than + - more than or equals + - less than + - less than or equals + - equals + - does not equal + - matches + - does not match + - matches phrase + - does not match phrase + value: + type: number + example: 100 + timeSize: + type: number + example: 6 + timeUnit: + type: string + enum: + - s + - m + - h + - d + logView: + type: object + properties: + logViewId: + type: string + type: + type: string + enum: + - log-view-reference + example: log-view-reference + groupBy: + type: array + items: + type: string + create_log_threshold_rule_request: + title: Create log threshold rule request + description: A rule that detects when a log aggregation exceeds a threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_log_threshold' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - logs.alert.document.count + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_ccr_exceptions_rule_request: + title: Create CCR read exceptions rule request + description: A rule that detects cross-cluster replication (CCR) read exceptions. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a CCR read exceptions rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_ccr_read_exceptions + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_cluster_health_rule_request: + title: Create cluster health rule request + description: A rule that detects when the health of the cluster changes. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a cluster health rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_cluster_health + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_cpu_usage_rule_request: + title: Create CPU usage rule request + description: A rule that detects when the CPU load for a node is consistently high. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a CPU usage rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_cpu_usage + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_disk_usage_rule_request: + title: Create disk usage rule request + description: A rule that detects when the disk usage for a node is consistently high. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a disk usage rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_disk_usage + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_elasticsearch_version_mismatch_rule_request: + title: Create Elasticsearch version mismatch rule request + description: A rule that detects when the cluster has multipe versions of Elasticsearch. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a Elasticsearch version mismatch rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_elasticsearch_version_mismatch + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_license_expiration_rule_request: + title: Create license expiration rule request + description: A rule that detects when the cluster license is about to expire. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a license expiration rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_license_expiration + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_kibana_version_mismatch_rule_request: + title: Create Kibana version mismatch rule request + description: A rule that detects when the cluster has multiple versions of Kibana. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a Kibana version mismatch rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_kibana_version_mismatch + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_logstash_version_mismatch_rule_request: + title: Create Logstash version mismatch rule request + description: A rule that detects when the cluster has multiple versions of Logstash. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a Logstash version mismatch rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_logstash_version_mismatch + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_missing_data_rule_request: + title: Create missing monitoring data rule request + description: A rule that detects when monitoring data is missing. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a missing monitoring data rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_missing_monitoring_data + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_nodes_changed_rule_request: + title: Create nodes changed rule request + description: A rule that detects when nodes are added, removed, or restarted. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a nodes changed rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_nodes_changed + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_shard_size_rule_request: + title: Create shard size rule request + description: A rule that detects when the average shard size is larger than a threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a shard size rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_shard_size + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_thread_pool_search_rejections_rule_request: + title: Create thread pool search rejections rule request + description: A rule that detects when the number of rejections in the thread pool exceeds a threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a thread pool search rejections rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_thread_pool_search_rejections + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_monitoring_thread_pool_write_rejections_rule_request: + title: Create thread pool write rejections rule request + description: A rule that detects when the number of rejections in the write thread pool exceeds a threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a thread pool write rejections rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_thread_pool_write_rejections + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_eql_rule_request: + title: Create event correlation rule request + description: | + A rule that uses Event Query Language (EQL) to match events, generate sequences, and stack data. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for an event correlation rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.eqlRule + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_indicator_rule_request: + title: Create indicator match rule request + description: | + A rule that uses indicators from intelligence sources to detect matching events and alerts. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for an indicator match rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.indicatorRule + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_ml_rule_request: + title: Create machine learning rule request + description: | + A rule that detects when a machine learning job discovers an anomaly above the defined threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a machine learning rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.mlRule + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_new_terms_rule_request: + title: Create new terms rule request + description: A rule that finds documents with values that appear for the first time. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a new terms rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.newTermsRule + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_notifications_rule_request: + title: Create security solution notification (legacy) rule request + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a notification rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.notifications + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_query_rule_request: + title: Create custom query rule request + description: | + A rule that uses KQL or Lucene to detect issues across indices. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a custom query rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.queryRule + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_saved_query_rule_request: + title: Create saved query rule request + description: | + A rule that searches the defined indices and creates an alert when a document matches the saved search. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a saved query rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.savedQueryRule + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_siem_threshold_rule_request: + title: Create threshold rule request + description: | + A rule that aggregates query results to detect when the number of matches exceeds a threshold. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a threshold rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.thresholdRule + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_slo_burn_rate: + properties: + sloId: + description: The SLO identifier used by the rule + type: string + example: 8853df00-ae2e-11ed-90af-09bb6422b258 + burnRateThreshold: + description: The burn rate threshold used to trigger the alert + type: number + example: 14.4 + maxBurnRateThreshold: + description: The maximum burn rate threshold value defined by the SLO error budget + type: number + example: 168 + longWindow: + description: The duration of the long window used to compute the burn rate + type: object + properties: + value: + description: The duration value + type: number + example: 6 + unit: + description: The duration unit + type: string + example: h + shortWindow: + description: The duration of the short window used to compute the burn rate + type: object + properties: + value: + description: The duration value + type: number + example: 30 + unit: + description: The duration unit + type: string + example: m + create_slo_burn_rate_rule_request: + title: Create slo burn rate rule request + description: | + A rule that detects when the burn rate is above a defined threshold for two different lookback periods. The two periods are a long period and a short period that is 1/12th of the long period. For each lookback period, the burn rate is computed as the error rate divided by the error budget. When the burn rates for both periods surpass the threshold, an alert occurs. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_slo_burn_rate' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - slo.rules.burnRate + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_synthetics_monitor_status_rule_request: + title: Create synthetics monitor status rule request + description: A rule that detects when a monitor is down or an availability threshold is breached. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for the synthetics monitor status rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.synthetics.alerts.monitorStatus + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_synthetics_uptime_duration_anomaly_rule_request: + title: Create synthetics uptime duration anomaly rule request + description: | + A rule that detects response durations for all of the geographic locations of each monitor. When a monitor runs for an unusual amount of time, at a particular time, an anomaly is recorded. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for the uptime duration anomaly rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.durationAnomaly + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_synthetics_uptime_tls: + properties: + search: + type: string + certExpirationThreshold: + type: number + certAgeThreshold: + type: number + create_synthetics_uptime_tls_rule_request: + title: Create synthetics uptime TLS rule request + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_synthetics_uptime_tls' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.tls + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_synthetics_uptime_tls_certificate_rule_request: + title: Create TLS certificate rule request + description: | + A rule that detects when a monitor has a TLS certificate expiring or when it exceeds an age limit. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a TLS certificate rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.tlsCertificate + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_transform_health_rule_request: + title: Create transform health rule request + description: | + A rule that monitors transforms health and alerts if an operational issue occurred. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for a transform health rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - transform_health + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + params_property_synthetics_monitor_status: + required: + - numTimes + - shouldCheckStatus + - shouldCheckAvailability + properties: + availability: + type: object + properties: + range: + type: number + rangeUnit: + type: string + threshold: + type: string + filters: + oneOf: + - type: string + - type: object + deprecated: true + properties: + monitor.type: + type: array + items: + type: string + observer.geo.name: + type: array + items: + type: string + tags: + type: array + items: + type: string + url.port: + type: array + items: + type: string + locations: + deprecated: true + type: array + items: + type: string + numTimes: + type: number + search: + type: string + shouldCheckStatus: + type: boolean + shouldCheckAvailability: + type: boolean + timerangeCount: + type: number + timerangeUnit: + type: string + timerange: + deprecated: true + type: object + properties: + from: + type: string + to: + type: string + version: + type: number + isAutoGenerated: + type: boolean + create_uptime_monitor_status_rule_request: + title: Create uptime monitor status rule request + description: A rule that detects monitor errors and outages. + type: object + required: + - consumer + - name + - params + - rule_type_id + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' + consumer: + $ref: '#/components/schemas/consumer' + enabled: + $ref: '#/components/schemas/enabled_rule' + name: + $ref: '#/components/schemas/name_rule' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + $ref: '#/components/schemas/params_property_synthetics_monitor_status' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.monitorStatus + schedule: + $ref: '#/components/schemas/schedule' + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + create_rule_request: + title: Create rule request body properties + description: The properties vary depending on the rule type. + oneOf: + - $ref: '#/components/schemas/create_anomaly_detection_alert_rule_request' + - $ref: '#/components/schemas/create_anomaly_detection_jobs_health_rule_request' + - $ref: '#/components/schemas/create_apm_anomaly_rule_request' + - $ref: '#/components/schemas/create_apm_error_count_rule_request' + - $ref: '#/components/schemas/create_apm_transaction_duration_rule_request' + - $ref: '#/components/schemas/create_apm_transaction_error_rate_rule_request' + - $ref: '#/components/schemas/create_es_query_rule_request' + - $ref: '#/components/schemas/create_geo_containment_rule_request' + - $ref: '#/components/schemas/create_index_threshold_rule_request' + - $ref: '#/components/schemas/create_infra_inventory_rule_request' + - $ref: '#/components/schemas/create_infra_metric_anomaly_rule_request' + - $ref: '#/components/schemas/create_infra_metric_threshold_rule_request' + - $ref: '#/components/schemas/create_monitoring_jvm_memory_usage_rule_request' + - $ref: '#/components/schemas/create_log_threshold_rule_request' + - $ref: '#/components/schemas/create_monitoring_ccr_exceptions_rule_request' + - $ref: '#/components/schemas/create_monitoring_cluster_health_rule_request' + - $ref: '#/components/schemas/create_monitoring_cpu_usage_rule_request' + - $ref: '#/components/schemas/create_monitoring_disk_usage_rule_request' + - $ref: '#/components/schemas/create_monitoring_elasticsearch_version_mismatch_rule_request' + - $ref: '#/components/schemas/create_monitoring_license_expiration_rule_request' + - $ref: '#/components/schemas/create_monitoring_kibana_version_mismatch_rule_request' + - $ref: '#/components/schemas/create_monitoring_logstash_version_mismatch_rule_request' + - $ref: '#/components/schemas/create_monitoring_missing_data_rule_request' + - $ref: '#/components/schemas/create_monitoring_nodes_changed_rule_request' + - $ref: '#/components/schemas/create_monitoring_shard_size_rule_request' + - $ref: '#/components/schemas/create_monitoring_thread_pool_search_rejections_rule_request' + - $ref: '#/components/schemas/create_monitoring_thread_pool_write_rejections_rule_request' + - $ref: '#/components/schemas/create_siem_eql_rule_request' + - $ref: '#/components/schemas/create_siem_indicator_rule_request' + - $ref: '#/components/schemas/create_siem_ml_rule_request' + - $ref: '#/components/schemas/create_siem_new_terms_rule_request' + - $ref: '#/components/schemas/create_siem_notifications_rule_request' + - $ref: '#/components/schemas/create_siem_query_rule_request' + - $ref: '#/components/schemas/create_siem_saved_query_rule_request' + - $ref: '#/components/schemas/create_siem_threshold_rule_request' + - $ref: '#/components/schemas/create_slo_burn_rate_rule_request' + - $ref: '#/components/schemas/create_synthetics_monitor_status_rule_request' + - $ref: '#/components/schemas/create_synthetics_uptime_duration_anomaly_rule_request' + - $ref: '#/components/schemas/create_synthetics_uptime_tls_rule_request' + - $ref: '#/components/schemas/create_synthetics_uptime_tls_certificate_rule_request' + - $ref: '#/components/schemas/create_transform_health_rule_request' + - $ref: '#/components/schemas/create_uptime_monitor_status_rule_request' + discriminator: + propertyName: rule_type_id + rule_response_properties: + title: Rule response properties + type: object + required: + - actions + - api_key_owner + - consumer + - created_at + - created_by + - enabled + - execution_status + - id + - mute_all + - muted_alert_ids + - name + - params + - rule_type_id + - schedule + - tags + - throttle + - updated_at + - updated_by + properties: + actions: + $ref: '#/components/schemas/actions' + api_key_created_by_user: + type: boolean + description: Indicates whether the API key that is associated with the rule was created by the user. + example: false + api_key_owner: + type: string + description: | + The owner of the API key that is associated with the rule and used to run background tasks. + nullable: true + example: elastic + consumer: + type: string + description: The application or feature that owns the rule. For example, `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. + example: alerts + created_at: + type: string + description: The date and time that the rule was created. + format: date-time + example: '2022-12-05T23:36:58.284Z' + created_by: + type: string + description: The identifier for the user that created the rule. + nullable: true + example: elastic + enabled: + type: boolean + description: Indicates whether the rule is currently enabled. + example: true + execution_status: + type: object + properties: + last_duration: + type: integer + example: 55 + last_execution_date: + type: string + format: date-time + example: '2022-12-06T00:13:43.890Z' + status: + type: string + example: ok + id: + type: string + description: The identifier for the rule. + example: b530fed0-74f5-11ed-9801-35303b735aef + last_run: + type: object + properties: + alerts_count: + type: object + properties: + active: + type: integer + ignored: + type: integer + new: + type: integer + recovered: + type: integer + outcome: + type: string + example: succeeded + outcome_msg: + type: array + items: + type: string + nullable: true + outcome_order: + type: integer + warning: + type: string + nullable: true + example: null + muted_alert_ids: + type: array + nullable: true + items: + type: string + mute_all: + type: boolean + example: false + name: + type: string + description: The name of the rule. + example: cluster_health_rule + next_run: + type: string + format: date-time + nullable: true + example: '2022-12-06T00:14:43.818Z' + notify_when: + $ref: '#/components/schemas/notify_when' + params: + type: object + description: The parameters for the rule. + additionalProperties: true + revision: + type: integer + description: The rule revision number. + rule_type_id: + type: string + description: | + The identifier for the type of rule. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`. + example: monitoring_alert_cluster_health + running: + type: boolean + description: Indicates whether the rule is running. + schedule: + $ref: '#/components/schemas/schedule' + scheduled_task_id: + type: string + example: b530fed0-74f5-11ed-9801-35303b735aef + tags: + $ref: '#/components/schemas/tags' + throttle: + $ref: '#/components/schemas/throttle' + updated_at: + type: string + description: The date and time that the rule was updated most recently. + example: '2022-12-05T23:36:58.284Z' + updated_by: + type: string + description: The identifier for the user that updated this rule most recently. + nullable: true + example: elastic + 401_response: + type: object + title: Unsuccessful rule API response + properties: + error: + type: string + example: Unauthorized + enum: + - Unauthorized + message: + type: string + statusCode: + type: integer + example: 401 + enum: + - 401 + 404_response: + type: object + properties: + error: + type: string + example: Not Found + enum: + - Not Found + message: + type: string + example: Saved object [alert/caaad6d0-920c-11ed-b36a-874bd1548a00] not found + statusCode: + type: integer + example: 404 + enum: + - 404 + update_rule_request: + title: Update rule request + description: The update rule API request body varies depending on the type of rule and actions. + type: object + required: + - name + - params + - schedule + properties: + actions: + $ref: '#/components/schemas/actions' name: type: string - description: The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule. + description: The name of the rule. example: cluster_health_rule notify_when: $ref: '#/components/schemas/notify_when' @@ -1944,10 +4254,6 @@ components: type: object description: The parameters for the rule. additionalProperties: true - rule_type_id: - type: string - description: | - The ID of the rule type that you want to call when the rule is scheduled to run. For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`. schedule: $ref: '#/components/schemas/schedule' tags: @@ -2038,6 +4344,102 @@ components: nullable: true example: elastic examples: + create_rule_request: + summary: Create an index threshold rule. + value: + actions: + - id: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 + frequency: + notify_when: onActionGroupChange + summary: false + group: threshold met + params: + level: info + message: |- + alert '{{alertName}}' is active for group '{{context.group}}': + + - Value: {{context.value}} + - Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}} + - Timestamp: {{context.date}} + consumer: alerts + name: my rule + params: + aggType: avg + termSize: 6 + thresholdComparator: '>' + timeWindowSize: 5 + timeWindowUnit: m + groupBy: top + threshold: + - 1000 + index: + - .test-index + timeField: '@timestamp' + aggField: sheet.version + termField: name.keyword + rule_type_id: .index-threshold + schedule: + interval: 1m + tags: + - cpu + create_rule_response: + summary: The create rule API returns a JSON object that contains details about the rule. + value: + actions: + - group: threshold met + id: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 + uuid: 07aef2a0-9eed-4ef9-94ec-39ba58eb609d + frequency: + notify_when: onActionGroupChange + summary: false + throttle: null + params: + level: info + message: |- + alert {{alertName}} is active for group {{context.group} : + + - Value: {{context.value}} + - Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}} + - Timestamp: {{context.date}} + api_key_created_by_user: false + api_key_owner: elastic + consumer: alerts + created_at: '2022-06-08T17:20:31.632Z' + created_by: elastic + enabled: true + execution_status: + last_execution_date: '2022-06-08T17:20:31.632Z' + status: pending + id: 41893910-6bca-11eb-9e0d-85d233e3ee35 + muted_alert_ids: [] + mute_all: false + name: my rule + notify_when: onActionGroupChange + params: + aggType: avg + termSize: 6 + thresholdComparator: '>' + timeWindowSize: 5 + timeWindowUnit: m + groupBy: top + threshold: + - 1000 + index: + - .test-index + timeField: '@timestamp' + aggField: sheet.version + termField: name.keyword + revision: 0 + rule_type_id: .index-threshold + running: false + schedule: + interval: 1m + scheduled_task_id: 425b0800-6bca-11eb-9e0d-85d233e3ee35 + tags: + - cpu + throttle: null + updated_at: '2022-06-08T17:20:31.632Z' + updated_by: elastic get_rule_response: summary: The get rule API returns a JSON object that contains details about the rule. value: @@ -2207,102 +4609,6 @@ components: outcome: succeeded next_run: '2023-01-31T23:49:42.432Z' api_key_created_by_user: false - create_rule_request: - summary: Create an index threshold rule. - value: - actions: - - id: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 - frequency: - notify_when: onActionGroupChange - summary: false - group: threshold met - params: - level: info - message: |- - alert '{{alertName}}' is active for group '{{context.group}}': - - - Value: {{context.value}} - - Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}} - - Timestamp: {{context.date}} - consumer: alerts - name: my rule - params: - aggType: avg - termSize: 6 - thresholdComparator: '>' - timeWindowSize: 5 - timeWindowUnit: m - groupBy: top - threshold: - - 1000 - index: - - .test-index - timeField: '@timestamp' - aggField: sheet.version - termField: name.keyword - rule_type_id: .index-threshold - schedule: - interval: 1m - tags: - - cpu - create_rule_response: - summary: The create rule API returns a JSON object that contains details about the rule. - value: - actions: - - group: threshold met - id: dceeb5d0-6b41-11eb-802b-85b0c1bc8ba2 - uuid: 07aef2a0-9eed-4ef9-94ec-39ba58eb609d - frequency: - notify_when: onActionGroupChange - summary: false - throttle: null - params: - level: info - message: |- - alert {{alertName}} is active for group {{context.group} : - - - Value: {{context.value}} - - Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}} - - Timestamp: {{context.date}} - api_key_created_by_user: false - api_key_owner: elastic - consumer: alerts - created_at: '2022-06-08T17:20:31.632Z' - created_by: elastic - enabled: true - execution_status: - last_execution_date: '2022-06-08T17:20:31.632Z' - status: pending - id: 41893910-6bca-11eb-9e0d-85d233e3ee35 - muted_alert_ids: [] - mute_all: false - name: my rule - notify_when: onActionGroupChange - params: - aggType: avg - termSize: 6 - thresholdComparator: '>' - timeWindowSize: 5 - timeWindowUnit: m - groupBy: top - threshold: - - 1000 - index: - - .test-index - timeField: '@timestamp' - aggField: sheet.version - termField: name.keyword - revision: 0 - rule_type_id: .index-threshold - running: false - schedule: - interval: 1m - scheduled_task_id: 425b0800-6bca-11eb-9e0d-85d233e3ee35 - tags: - - cpu - throttle: null - updated_at: '2022-06-08T17:20:31.632Z' - updated_by: elastic find_rules_response: summary: Retrieve information about a rule. value: diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/consumer.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/consumer.yaml new file mode 100644 index 0000000000000..26932fba5ed72 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/consumer.yaml @@ -0,0 +1,4 @@ +type: string +description: > + The name of the application or feature that owns the rule. + For example: `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_anomaly_detection_alert_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_anomaly_detection_alert_rule_request.yaml new file mode 100644 index 0000000000000..d4bdb712f634d --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_anomaly_detection_alert_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create anomaly detection rule request +description: > + A rule that checks if the anomaly detection job results contain anomalies that match the rule conditions. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an anomaly detection rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.ml.anomaly_detection_alert + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_anomaly_detection_jobs_health_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_anomaly_detection_jobs_health_rule_request.yaml new file mode 100644 index 0000000000000..d9fd3b3a63ddb --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_anomaly_detection_jobs_health_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create anomaly detection jobs health rule request +description: > + An rule that monitors job health and alerts if an operational issue occurred that may prevent the job from detecting anomalies. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an anomaly detection jobs health rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.ml.anomaly_detection_jobs_health + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_anomaly_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_anomaly_rule_request.yaml new file mode 100644 index 0000000000000..7b091dc1abfd2 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_anomaly_rule_request.yaml @@ -0,0 +1,34 @@ +title: Create APM anomaly rule rule request +description: A rule that detects when either the latency, throughput, or failed transaction rate of a service is anomalous. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../apm/server/routes/alerts/rule_types/docs/params_property_apm_anomaly.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.anomaly + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_error_count_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_error_count_rule_request.yaml new file mode 100644 index 0000000000000..9bbe46301ceeb --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_error_count_rule_request.yaml @@ -0,0 +1,34 @@ +title: Create APM error count rule request +description: A rule that detects when the number of errors in a service exceeds a defined threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../apm/server/routes/alerts/rule_types/docs/params_property_apm_error_count.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.error_rate + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_transaction_duration_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_transaction_duration_rule_request.yaml new file mode 100644 index 0000000000000..eaff2c48ffbfc --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_transaction_duration_rule_request.yaml @@ -0,0 +1,34 @@ +title: Create latency threshold rule request +description: A rule that detects when the latency of a specific transaction type in a service exceeds a threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../apm/server/routes/alerts/rule_types/docs/params_property_apm_transaction_duration.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.transaction_duration + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_transaction_error_rate_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_transaction_error_rate_rule_request.yaml new file mode 100644 index 0000000000000..505e5b69f57fd --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_apm_transaction_error_rate_rule_request.yaml @@ -0,0 +1,34 @@ +title: Create APM transaction error rate rule request +description: A rule that sends notifications when the rate of transaction errors in a service exceeds a threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../apm/server/routes/alerts/rule_types/docs/params_property_apm_transaction_error_rate.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - apm.transaction_error_rate + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_es_query_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_es_query_rule_request.yaml new file mode 100644 index 0000000000000..1c42087c59895 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_es_query_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create Elasticsearch query rule request +description: > + A rule that runs a user-configured query, compares the number of matches to a configured threshold, and schedules actions to run when the threshold condition is met. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an Elasticsearch query rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - .es-query + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_geo_containment_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_geo_containment_rule_request.yaml new file mode 100644 index 0000000000000..ab6f0c3d3b054 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_geo_containment_rule_request.yaml @@ -0,0 +1,39 @@ +title: Create traacking containment rule request +description: > + A rule that runs an Elasticsearch query over indices to determine whether any documents are currently contained within any boundaries from the specified boundary index. + In the event that an entity is contained within a boundary, an alert may be generated. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an tracking containment rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - .geo-containment + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_index_threshold_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_index_threshold_rule_request.yaml new file mode 100644 index 0000000000000..4ac87e901beb6 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_index_threshold_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create index threshold rule request +description: >- + A rule that runs an Elasticsearch query, aggregates field values from documents, compares them to threshold values, and schedules actions to run when the thresholds are met. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an index threshold rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - .index-threshold + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_inventory_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_inventory_rule_request.yaml new file mode 100644 index 0000000000000..ddef0a3e4cdd1 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_inventory_rule_request.yaml @@ -0,0 +1,35 @@ +title: Create infra inventory rule request +description: > + A rule that sends notifications when a metric has reached or exceeded a value for a specific resource or a group of resources within your infrastructure. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../infra/server/lib/alerting/docs/params_property_infra_inventory.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - metrics.alert.inventory.threshold + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_metric_anomaly_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_metric_anomaly_rule_request.yaml new file mode 100644 index 0000000000000..4c80967fbe26a --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_metric_anomaly_rule_request.yaml @@ -0,0 +1,36 @@ +title: Create infrastructure anomaly rule request +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an infrastructure anomaly rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - metrics.alert.anomaly + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_metric_threshold_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_metric_threshold_rule_request.yaml new file mode 100644 index 0000000000000..775015ca6006e --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_infra_metric_threshold_rule_request.yaml @@ -0,0 +1,35 @@ +title: Create infra metric threshold rule request +description: > + A rule that sends notifications when a metric has reached or exceeded a value for a specific time period. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../infra/server/lib/alerting/docs/params_property_infra_metric_threshold.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - metrics.alert.threshold + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_log_threshold_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_log_threshold_rule_request.yaml new file mode 100644 index 0000000000000..ce4baaf78ac68 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_log_threshold_rule_request.yaml @@ -0,0 +1,34 @@ +title: Create log threshold rule request +description: A rule that detects when a log aggregation exceeds a threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../infra/server/lib/alerting/docs/params_property_log_threshold.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - logs.alert.document.count + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_ccr_exceptions_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_ccr_exceptions_rule_request.yaml new file mode 100644 index 0000000000000..cf031888d89fc --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_ccr_exceptions_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create CCR read exceptions rule request +description: A rule that detects cross-cluster replication (CCR) read exceptions. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a CCR read exceptions rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_ccr_read_exceptions + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_cluster_health_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_cluster_health_rule_request.yaml new file mode 100644 index 0000000000000..e32c121272538 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_cluster_health_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create cluster health rule request +description: A rule that detects when the health of the cluster changes. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a cluster health rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_cluster_health + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_cpu_usage_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_cpu_usage_rule_request.yaml new file mode 100644 index 0000000000000..b1d31b6365df6 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_cpu_usage_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create CPU usage rule request +description: A rule that detects when the CPU load for a node is consistently high. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a CPU usage rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_cpu_usage + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_disk_usage_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_disk_usage_rule_request.yaml new file mode 100644 index 0000000000000..df7b66a234a14 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_disk_usage_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create disk usage rule request +description: A rule that detects when the disk usage for a node is consistently high. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a disk usage rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_disk_usage + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_elasticsearch_version_mismatch_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_elasticsearch_version_mismatch_rule_request.yaml new file mode 100644 index 0000000000000..87be34ef18d11 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_elasticsearch_version_mismatch_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create Elasticsearch version mismatch rule request +description: A rule that detects when the cluster has multipe versions of Elasticsearch. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a Elasticsearch version mismatch rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_elasticsearch_version_mismatch + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_jvm_memory_usage_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_jvm_memory_usage_rule_request.yaml new file mode 100644 index 0000000000000..8ba1e561010e3 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_jvm_memory_usage_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create JVM memory usage rule request +description: A rule that detects when a node reports high memory usage. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a JVM memory usage rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_jvm_memory_usage + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_kibana_version_mismatch_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_kibana_version_mismatch_rule_request.yaml new file mode 100644 index 0000000000000..2b0fbe88f5442 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_kibana_version_mismatch_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create Kibana version mismatch rule request +description: A rule that detects when the cluster has multiple versions of Kibana. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a Kibana version mismatch rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_kibana_version_mismatch + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_license_expiration_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_license_expiration_rule_request.yaml new file mode 100644 index 0000000000000..c11db425738ce --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_license_expiration_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create license expiration rule request +description: A rule that detects when the cluster license is about to expire. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a license expiration rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_license_expiration + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_logstash_version_mismatch_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_logstash_version_mismatch_rule_request.yaml new file mode 100644 index 0000000000000..bac07fd3d9e39 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_logstash_version_mismatch_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create Logstash version mismatch rule request +description: A rule that detects when the cluster has multiple versions of Logstash. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a Logstash version mismatch rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_logstash_version_mismatch + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_missing_data_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_missing_data_rule_request.yaml new file mode 100644 index 0000000000000..8e2484db9b892 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_missing_data_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create missing monitoring data rule request +description: A rule that detects when monitoring data is missing. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a missing monitoring data rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_missing_monitoring_data + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_nodes_changed_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_nodes_changed_rule_request.yaml new file mode 100644 index 0000000000000..c8af9bb84c151 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_nodes_changed_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create nodes changed rule request +description: A rule that detects when nodes are added, removed, or restarted. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a nodes changed rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_nodes_changed + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_shard_size_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_shard_size_rule_request.yaml new file mode 100644 index 0000000000000..0d75dca26cf24 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_shard_size_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create shard size rule request +description: A rule that detects when the average shard size is larger than a threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a shard size rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_shard_size + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_thread_pool_search_rejections_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_thread_pool_search_rejections_rule_request.yaml new file mode 100644 index 0000000000000..fbf20b7b867c5 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_thread_pool_search_rejections_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create thread pool search rejections rule request +description: A rule that detects when the number of rejections in the thread pool exceeds a threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a thread pool search rejections rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_thread_pool_search_rejections + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_thread_pool_write_rejections_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_thread_pool_write_rejections_rule_request.yaml new file mode 100644 index 0000000000000..741d2af4a9b13 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_monitoring_thread_pool_write_rejections_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create thread pool write rejections rule request +description: A rule that detects when the number of rejections in the write thread pool exceeds a threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a thread pool write rejections rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - monitoring_alert_thread_pool_write_rejections + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_rule_request.yaml index ca143eeb51cd8..19027992be7ac 100644 --- a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_rule_request.yaml +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_rule_request.yaml @@ -1,44 +1,48 @@ -title: Create rule request -description: >- - The create rule API request body varies depending on the type of rule and actions. -type: object -required: - - consumer - - name - - params - - rule_type_id - - schedule -properties: - actions: - $ref: 'actions.yaml' - consumer: - type: string - description: > - The name of the application or feature that owns the rule. For example: - `alerts`, `apm`, `discover`, `infrastructure`, `logs`, `metrics`, `ml`, - `monitoring`, `securitySolution`, `siem`, `stackAlerts`, or `uptime`. - enabled: - type: boolean - description: Indicates whether you want to run the rule on an interval basis after it is created. - name: - type: string - description: The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule. - example: cluster_health_rule - notify_when: - $ref: 'notify_when.yaml' - params: - type: object - description: The parameters for the rule. - additionalProperties: true - rule_type_id: - type: string - description: > - The ID of the rule type that you want to call when the rule is scheduled to run. - For example, `.es-query`, `.index-threshold`, `logs.alert.document.count`, - `monitoring_alert_cluster_health`, `siem.thresholdRule`, or `xpack.ml.anomaly_detection_alert`. - schedule: - $ref: 'schedule.yaml' - tags: - $ref: 'tags.yaml' - throttle: - $ref: 'throttle.yaml' \ No newline at end of file +title: Create rule request body properties +description: The properties vary depending on the rule type. +oneOf: + - $ref: 'create_anomaly_detection_alert_rule_request.yaml' + - $ref: 'create_anomaly_detection_jobs_health_rule_request.yaml' + - $ref: 'create_apm_anomaly_rule_request.yaml' + - $ref: 'create_apm_error_count_rule_request.yaml' + - $ref: 'create_apm_transaction_duration_rule_request.yaml' + - $ref: 'create_apm_transaction_error_rate_rule_request.yaml' + - $ref: 'create_es_query_rule_request.yaml' + - $ref: 'create_geo_containment_rule_request.yaml' + - $ref: 'create_index_threshold_rule_request.yaml' + - $ref: 'create_infra_inventory_rule_request.yaml' + - $ref: 'create_infra_metric_anomaly_rule_request.yaml' + - $ref: 'create_infra_metric_threshold_rule_request.yaml' + - $ref: 'create_monitoring_jvm_memory_usage_rule_request.yaml' + - $ref: 'create_log_threshold_rule_request.yaml' + - $ref: 'create_monitoring_ccr_exceptions_rule_request.yaml' + - $ref: 'create_monitoring_cluster_health_rule_request.yaml' + - $ref: 'create_monitoring_cpu_usage_rule_request.yaml' + - $ref: 'create_monitoring_disk_usage_rule_request.yaml' + - $ref: 'create_monitoring_elasticsearch_version_mismatch_rule_request.yaml' + - $ref: 'create_monitoring_license_expiration_rule_request.yaml' + - $ref: 'create_monitoring_kibana_version_mismatch_rule_request.yaml' + - $ref: 'create_monitoring_logstash_version_mismatch_rule_request.yaml' + - $ref: 'create_monitoring_missing_data_rule_request.yaml' + - $ref: 'create_monitoring_nodes_changed_rule_request.yaml' + - $ref: 'create_monitoring_shard_size_rule_request.yaml' + - $ref: 'create_monitoring_thread_pool_search_rejections_rule_request.yaml' + - $ref: 'create_monitoring_thread_pool_write_rejections_rule_request.yaml' + - $ref: 'create_siem_eql_rule_request.yaml' + - $ref: 'create_siem_indicator_rule_request.yaml' + - $ref: 'create_siem_ml_rule_request.yaml' + - $ref: 'create_siem_new_terms_rule_request.yaml' + - $ref: 'create_siem_notifications_rule_request.yaml' + - $ref: 'create_siem_query_rule_request.yaml' + - $ref: 'create_siem_saved_query_rule_request.yaml' + - $ref: 'create_siem_threshold_rule_request.yaml' + - $ref: 'create_slo_burn_rate_rule_request.yaml' + - $ref: 'create_synthetics_monitor_status_rule_request.yaml' + - $ref: 'create_synthetics_uptime_duration_anomaly_rule_request.yaml' + - $ref: 'create_synthetics_uptime_tls_rule_request.yaml' + - $ref: 'create_synthetics_uptime_tls_certificate_rule_request.yaml' + - $ref: 'create_transform_health_rule_request.yaml' + - $ref: 'create_uptime_monitor_status_rule_request.yaml' +discriminator: + propertyName: rule_type_id + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_eql_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_eql_rule_request.yaml new file mode 100644 index 0000000000000..8eb332ed2ded5 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_eql_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create event correlation rule request +description: > + A rule that uses Event Query Language (EQL) to match events, generate sequences, and stack data. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an event correlation rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.eqlRule + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_indicator_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_indicator_rule_request.yaml new file mode 100644 index 0000000000000..744217e788bf6 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_indicator_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create indicator match rule request +description: > + A rule that uses indicators from intelligence sources to detect matching events and alerts. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for an indicator match rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.indicatorRule + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_ml_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_ml_rule_request.yaml new file mode 100644 index 0000000000000..90a4146066ddd --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_ml_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create machine learning rule request +description: > + A rule that detects when a machine learning job discovers an anomaly above the defined threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a machine learning rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.mlRule + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_new_terms_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_new_terms_rule_request.yaml new file mode 100644 index 0000000000000..19cc1ff3a2516 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_new_terms_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create new terms rule request +description: A rule that finds documents with values that appear for the first time. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a new terms rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.newTermsRule + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_notifications_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_notifications_rule_request.yaml new file mode 100644 index 0000000000000..4190f31ce1160 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_notifications_rule_request.yaml @@ -0,0 +1,36 @@ +title: Create security solution notification (legacy) rule request +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a notification rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.notifications + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_query_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_query_rule_request.yaml new file mode 100644 index 0000000000000..9cd8f3ec92744 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_query_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create custom query rule request +description: > + A rule that uses KQL or Lucene to detect issues across indices. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a custom query rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.queryRule + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_saved_query_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_saved_query_rule_request.yaml new file mode 100644 index 0000000000000..3048c922e492a --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_saved_query_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create saved query rule request +description: > + A rule that searches the defined indices and creates an alert when a document matches the saved search. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a saved query rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.savedQueryRule + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_threshold_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_threshold_rule_request.yaml new file mode 100644 index 0000000000000..67b5642a26681 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_siem_threshold_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create threshold rule request +description: > + A rule that aggregates query results to detect when the number of matches exceeds a threshold. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a threshold rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - siem.thresholdRule + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_slo_burn_rate_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_slo_burn_rate_rule_request.yaml new file mode 100644 index 0000000000000..dcb6e5932a60d --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_slo_burn_rate_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create slo burn rate rule request +description: > + A rule that detects when the burn rate is above a defined threshold for two different lookback periods. + The two periods are a long period and a short period that is 1/12th of the long period. + For each lookback period, the burn rate is computed as the error rate divided by the error budget. + When the burn rates for both periods surpass the threshold, an alert occurs. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../observability/server/lib/rules/slo_burn_rate/docs/params_property_slo_burn_rate.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - slo.rules.burnRate + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_monitor_status_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_monitor_status_rule_request.yaml new file mode 100644 index 0000000000000..d392630259d19 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_monitor_status_rule_request.yaml @@ -0,0 +1,37 @@ +title: Create synthetics monitor status rule request +description: A rule that detects when a monitor is down or an availability threshold is breached. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for the synthetics monitor status rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.synthetics.alerts.monitorStatus + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_duration_anomaly_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_duration_anomaly_rule_request.yaml new file mode 100644 index 0000000000000..76fb45e99bd9a --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_duration_anomaly_rule_request.yaml @@ -0,0 +1,39 @@ +title: Create synthetics uptime duration anomaly rule request +description: > + A rule that detects response durations for all of the geographic locations of each monitor. + When a monitor runs for an unusual amount of time, at a particular time, an anomaly is recorded. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for the uptime duration anomaly rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.durationAnomaly + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_tls_certificate_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_tls_certificate_rule_request.yaml new file mode 100644 index 0000000000000..883342ce74619 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_tls_certificate_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create TLS certificate rule request +description: > + A rule that detects when a monitor has a TLS certificate expiring or when it exceeds an age limit. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a TLS certificate rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.tlsCertificate + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_tls_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_tls_rule_request.yaml new file mode 100644 index 0000000000000..a7f48c2d29234 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_synthetics_uptime_tls_rule_request.yaml @@ -0,0 +1,33 @@ +title: Create synthetics uptime TLS rule request +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../synthetics/server/legacy_uptime/lib/alerts/docs/params_property_synthetics_uptime_tls.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.tls + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_transform_health_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_transform_health_rule_request.yaml new file mode 100644 index 0000000000000..ebe92de8c5cf2 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_transform_health_rule_request.yaml @@ -0,0 +1,38 @@ +title: Create transform health rule request +description: > + A rule that monitors transforms health and alerts if an operational issue occurred. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + type: object + description: The parameters for a transform health rule. + # TO-DO: Add the parameter details for this rule. + additionalProperties: true + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - transform_health + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/create_uptime_monitor_status_rule_request.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_uptime_monitor_status_rule_request.yaml new file mode 100644 index 0000000000000..1df817c570e70 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/create_uptime_monitor_status_rule_request.yaml @@ -0,0 +1,34 @@ +title: Create uptime monitor status rule request +description: A rule that detects monitor errors and outages. +type: object +required: + - consumer + - name + - params + - rule_type_id + - schedule +properties: + actions: + $ref: 'actions.yaml' + consumer: + $ref: 'consumer.yaml' + enabled: + $ref: 'enabled_rule.yaml' + name: + $ref: 'name_rule.yaml' + notify_when: + $ref: 'notify_when.yaml' + params: + $ref: '../../../../../synthetics/server/legacy_uptime/lib/alerts/docs/params_property_synthetics_monitor_status.yaml' + rule_type_id: + type: string + description: The ID of the rule type that you want to call when the rule is scheduled to run. + enum: + - xpack.uptime.alerts.monitorStatus + schedule: + $ref: 'schedule.yaml' + tags: + $ref: 'tags.yaml' + throttle: + $ref: 'throttle.yaml' + \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/enabled_rule.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/enabled_rule.yaml new file mode 100644 index 0000000000000..e6834fb05d7c1 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/enabled_rule.yaml @@ -0,0 +1,2 @@ +type: boolean +description: Indicates whether you want to run the rule on an interval basis after it is created. diff --git a/x-pack/plugins/alerting/docs/openapi/components/schemas/name_rule.yaml b/x-pack/plugins/alerting/docs/openapi/components/schemas/name_rule.yaml new file mode 100644 index 0000000000000..74263c63c7fdc --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/components/schemas/name_rule.yaml @@ -0,0 +1,4 @@ +type: string +description: > + The name of the rule. + While this name does not have to be unique, a distinctive name can help you identify a rule. diff --git a/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml b/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml index 52b1babd68c8c..5e73a74c058a0 100644 --- a/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml +++ b/x-pack/plugins/alerting/docs/openapi/entrypoint.yaml @@ -15,6 +15,8 @@ servers: - url: 'http://localhost:5601' description: local paths: + '/s/{spaceId}/api/alerting/rule': + $ref: 'paths/s@{spaceid}@api@alerting@rule.yaml' '/s/{spaceId}/api/alerting/rule/{ruleId}': $ref: 'paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml' '/s/{spaceId}/api/alerting/rule/{ruleId}/_disable': diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule.yaml new file mode 100644 index 0000000000000..2683ac99672e8 --- /dev/null +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule.yaml @@ -0,0 +1,52 @@ +post: + summary: Creates a rule with a randomly generated rule identifier. + operationId: createRule + description: > + You must have `all` privileges for the appropriate Kibana features, depending on the `consumer` and `rule_type_id` of the rule you're creating. + For example, you must have privileges for the **Management > Stack rules** feature, **Analytics > Discover** and **Machine Learning** features, **Observability** features, or **Security** features. + If the rule has actions, you must also have `read` privileges for the **Management > Actions and Connectors** feature. + NOTE: This API supports only token-based authentication. + When you create a rule, it identifies which roles you have at that point in time. + Thereafter, when the rule performs queries, it uses those security privileges. + If a user with different privileges updates the rule, its behavior might change. + tags: + - alerting + parameters: + - $ref: ../components/headers/kbn_xsrf.yaml + - $ref: '../components/parameters/space_id.yaml' + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/create_rule_request.yaml' + examples: + createRuleRequest: + $ref: '../components/examples/create_rule_request.yaml' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '../components/schemas/rule_response_properties.yaml' + examples: + createRuleResponse: + $ref: '../components/examples/create_rule_response.yaml' + '401': + description: Authorization information is missing or invalid. + content: + application/json: + schema: + $ref: '../components/schemas/401_response.yaml' + '404': + description: Object is not found. + content: + application/json: + schema: + $ref: '../components/schemas/404_response.yaml' + servers: + - url: https://localhost:5601 + +servers: + - url: https://localhost:5601 \ No newline at end of file diff --git a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml index 01ca92a7d0cd1..7ede8da710ea0 100644 --- a/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml +++ b/x-pack/plugins/alerting/docs/openapi/paths/s@{spaceid}@api@alerting@rule@{ruleid}.yaml @@ -72,8 +72,8 @@ delete: - url: https://localhost:5601 post: - summary: Creates a rule. - operationId: createRule + summary: Creates a rule with a specific rule identifier. + operationId: createRuleId description: > You must have `all` privileges for the appropriate Kibana features, depending on the `consumer` and `rule_type_id` of the rule you're creating. @@ -105,9 +105,9 @@ post: content: application/json: schema: - $ref: '../components/schemas/create_rule_request.yaml' + $ref: '../components/schemas/create_rule_request.yaml' examples: - createCaseRequest: + createRuleIdRequest: $ref: '../components/examples/create_rule_request.yaml' responses: '200': @@ -117,7 +117,7 @@ post: schema: $ref: '../components/schemas/rule_response_properties.yaml' examples: - createRuleResponse: + createRuleIdResponse: $ref: '../components/examples/create_rule_response.yaml' '401': description: Authorization information is missing or invalid. @@ -165,7 +165,7 @@ put: schema: $ref: '../components/schemas/update_rule_request.yaml' examples: - updateCaseRequest: + updateRuleRequest: $ref: '../components/examples/update_rule_request.yaml' responses: '200': diff --git a/x-pack/plugins/apm/common/apm_feature_flags.ts b/x-pack/plugins/apm/common/apm_feature_flags.ts index c928c8a0dec6a..0685555d02c1e 100644 --- a/x-pack/plugins/apm/common/apm_feature_flags.ts +++ b/x-pack/plugins/apm/common/apm_feature_flags.ts @@ -15,8 +15,6 @@ export enum ApmFeatureFlagName { InfraUiAvailable = 'infraUiAvailable', MigrationToFleetAvailable = 'migrationToFleetAvailable', SourcemapApiAvailable = 'sourcemapApiAvailable', - SpacesAvailable = 'spacesAvailable', - SchemaAvailable = 'schemaAvailable', StorageExplorerAvailable = 'storageExplorerAvailable', } @@ -45,14 +43,6 @@ const apmFeatureFlagMap = { default: true, type: t.boolean, }, - [ApmFeatureFlagName.SpacesAvailable]: { - default: true, - type: t.boolean, - }, - [ApmFeatureFlagName.SchemaAvailable]: { - default: true, - type: t.boolean, - }, [ApmFeatureFlagName.StorageExplorerAvailable]: { default: true, type: t.boolean, diff --git a/x-pack/plugins/apm/common/rules/get_all_groupby_fields.ts b/x-pack/plugins/apm/common/rules/get_all_groupby_fields.ts new file mode 100644 index 0000000000000..696a30df3a78c --- /dev/null +++ b/x-pack/plugins/apm/common/rules/get_all_groupby_fields.ts @@ -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 { union } from 'lodash'; +import { ApmRuleType } from './apm_rule_types'; +import { + SERVICE_ENVIRONMENT, + SERVICE_NAME, + TRANSACTION_TYPE, +} from '../es_fields/apm'; + +export const getAllGroupByFields = ( + ruleType: string, + ruleParamsGroupByFields: string[] | undefined = [] +) => { + let predefinedGroupByFields: string[] = []; + + switch (ruleType) { + case ApmRuleType.TransactionDuration: + case ApmRuleType.TransactionErrorRate: + predefinedGroupByFields = [ + SERVICE_NAME, + SERVICE_ENVIRONMENT, + TRANSACTION_TYPE, + ]; + break; + case ApmRuleType.ErrorCount: + predefinedGroupByFields = [SERVICE_NAME, SERVICE_ENVIRONMENT]; + break; + } + + return union(predefinedGroupByFields, ruleParamsGroupByFields); +}; diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/onboarding/onboarding.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/onboarding/onboarding.cy.ts new file mode 100644 index 0000000000000..e7298607de8e6 --- /dev/null +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/onboarding/onboarding.cy.ts @@ -0,0 +1,167 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import { synthtrace } from '../../../../synthtrace'; + +const start = Date.now() - 1000; +const end = Date.now(); + +function generateData({ from, to }: { from: number; to: number }) { + const range = timerange(from, to); + const synthGo1 = apm + .service({ + name: 'synth-go-1', + environment: 'production', + agentName: 'go', + }) + .instance('my-instance'); + + return range.interval('1m').generator((timestamp) => { + return [ + synthGo1 + .transaction({ transactionName: 'GET /apple 🍎' }) + .timestamp(timestamp) + .duration(1000) + .success(), + ]; + }); +} + +describe('APM Onboarding', () => { + describe('General navigation', () => { + beforeEach(() => { + cy.loginAsEditorUser(); + cy.visitKibana('/app/apm/onboarding'); + }); + + it('includes section for APM Agents', () => { + cy.contains('APM Agents'); + cy.contains('Node.js'); + cy.contains('Django'); + cy.contains('Flask'); + cy.contains('Ruby on Rails'); + cy.contains('Rack'); + cy.contains('Go'); + cy.contains('Java'); + cy.contains('.NET'); + cy.contains('PHP'); + cy.contains('OpenTelemetry'); + }); + + it('navigation to different Tabs', () => { + cy.contains('Django').click(); + cy.contains('pip install elastic-apm'); + + cy.contains('Flask').click(); + cy.contains('pip install elastic-apm[flask]'); + + cy.contains('Ruby on Rails').click(); + cy.contains("gem 'elastic-apm'"); + + cy.contains('Rack').click(); + cy.contains("gem 'elastic-apm'"); + + cy.contains('Go').click(); + cy.contains('go get go.elastic.co/apm'); + + cy.contains('Java').click(); + cy.contains('-javaagent'); + + cy.contains('.NET').click(); + cy.contains('Elastic.Apm.NetCoreAll'); + + cy.contains('PHP').click(); + cy.contains('apk add --allow-untrusted .apk'); + + cy.contains('OpenTelemetry').click(); + cy.contains('Download the OpenTelemetry APM Agent or SDK'); + }); + }); + + describe('check Agent Status', () => { + beforeEach(() => { + cy.loginAsEditorUser(); + cy.visitKibana('/app/apm/onboarding'); + }); + it('when no data is present', () => { + cy.intercept('GET', '/internal/apm/observability_overview/has_data').as( + 'hasData' + ); + cy.getByTestSubj('checkAgentStatus').click(); + cy.wait('@hasData'); + cy.getByTestSubj('agentStatusWarningCallout').should('exist'); + }); + + it('when data is present', () => { + synthtrace.index( + generateData({ + from: new Date(start).getTime(), + to: new Date(end).getTime(), + }) + ); + cy.intercept('GET', '/internal/apm/observability_overview/has_data').as( + 'hasData' + ); + cy.getByTestSubj('checkAgentStatus').click(); + cy.wait('@hasData'); + cy.getByTestSubj('agentStatusSuccessCallout').should('exist'); + synthtrace.clean(); + }); + }); + + describe('create API Key', () => { + it('create the key successfully', () => { + cy.loginAsApmManageOwnAndCreateAgentKeys(); + cy.visitKibana('/app/apm/onboarding'); + cy.intercept('POST', '/api/apm/agent_keys').as('createApiKey'); + cy.getByTestSubj('createApiKeyAndId').click(); + cy.wait('@createApiKey'); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('Django').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('Flask').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('Ruby on Rails').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('Rack').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('Go').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('Java').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('.NET').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('PHP').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + + cy.contains('OpenTelemetry').click(); + cy.getByTestSubj('apiKeySuccessCallout').should('exist'); + }); + + it('fails to create the key due to missing privileges', () => { + cy.loginAsEditorUser(); + cy.visitKibana('/app/apm/onboarding'); + cy.intercept('POST', '/api/apm/agent_keys').as('createApiKey'); + cy.getByTestSubj('createApiKeyAndId').click(); + cy.wait('@createApiKey'); + cy.getByTestSubj('apiKeyWarningCallout').should('exist'); + cy.get('@createApiKey') + .its('response') + .then((res) => { + expect(res.statusCode).to.equal(403); + }); + }); + }); +}); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts index e0af1e1a84729..22f9090049a60 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts @@ -26,6 +26,13 @@ Cypress.Commands.add('loginAsMonitorUser', () => { }); }); +Cypress.Commands.add('loginAsApmManageOwnAndCreateAgentKeys', () => { + return cy.loginAs({ + username: ApmUsername.apmManageOwnAndCreateAgentKeys, + password: 'changeme', + }); +}); + Cypress.Commands.add( 'loginAs', ({ username, password }: { username: string; password: string }) => { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts index d9675f2536315..b4c1ef54ceb9b 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts @@ -10,6 +10,9 @@ declare namespace Cypress { loginAsViewerUser(): Cypress.Chainable>; loginAsEditorUser(): Cypress.Chainable>; loginAsMonitorUser(): Cypress.Chainable>; + loginAsApmManageOwnAndCreateAgentKeys(): Cypress.Chainable< + Cypress.Response + >; loginAs(params: { username: string; password: string; diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx index d01f1f0a45dea..d14eac462609a 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/error_count_rule_type/index.tsx @@ -18,7 +18,11 @@ import { EuiFormRow } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { asInteger } from '../../../../../common/utils/formatters'; -import { useFetcher } from '../../../../hooks/use_fetcher'; +import { + FETCH_STATUS, + isPending, + useFetcher, +} from '../../../../hooks/use_fetcher'; import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; import { ChartPreview } from '../../ui_components/chart_preview'; import { @@ -36,6 +40,11 @@ import { TRANSACTION_NAME, ERROR_GROUP_ID, } from '../../../../../common/es_fields/apm'; +import { + ErrorState, + LoadingState, + NoDataState, +} from '../../ui_components/chart_preview/chart_preview_helper'; export interface RuleParams { windowSize?: number; @@ -72,13 +81,13 @@ export function ErrorCountRuleType(props: Props) { } ); - const { data } = useFetcher( + const { data, status } = useFetcher( (callApmApi) => { const { interval, start, end } = getIntervalAndTimeRange({ windowSize: params.windowSize, windowUnit: params.windowUnit, }); - if (interval && start && end) { + if (params.windowSize && start && end) { return callApmApi( 'GET /internal/apm/rule_types/error_count/chart_preview', { @@ -90,6 +99,7 @@ export function ErrorCountRuleType(props: Props) { interval, start, end, + groupBy: params.groupBy, }, }, } @@ -102,6 +112,7 @@ export function ErrorCountRuleType(props: Props) { params.environment, params.serviceName, params.errorGroupingKey, + params.groupBy, ] ); @@ -162,16 +173,28 @@ export function ErrorCountRuleType(props: Props) { />, ]; - // hide preview chart until https://github.com/elastic/kibana/pull/156625 gets merged - const showChartPreview = false; - const chartPreview = showChartPreview ? ( + const errorCountChartPreview = data?.errorCountChartPreview; + const series = errorCountChartPreview?.series ?? []; + const hasData = series.length > 0; + const totalGroups = errorCountChartPreview?.totalGroups ?? 0; + + const chartPreview = isPending(status) ? ( + + ) : !hasData ? ( + + ) : status === FETCH_STATUS.SUCCESS ? ( - ) : null; + ) : ( + + ); const groupAlertsBy = ( <> diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx index 9d51adfeebc05..dcde3f4dd3e88 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_duration_rule_type/index.tsx @@ -20,7 +20,11 @@ import { EuiSpacer } from '@elastic/eui'; import { AggregationType } from '../../../../../common/rules/apm_rule_types'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { getDurationFormatter } from '../../../../../common/utils/formatters'; -import { useFetcher } from '../../../../hooks/use_fetcher'; +import { + FETCH_STATUS, + isPending, + useFetcher, +} from '../../../../hooks/use_fetcher'; import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; import { getMaxY, @@ -44,6 +48,11 @@ import { TRANSACTION_NAME, TRANSACTION_TYPE, } from '../../../../../common/es_fields/apm'; +import { + ErrorState, + LoadingState, + NoDataState, +} from '../../ui_components/chart_preview/chart_preview_helper'; export interface RuleParams { aggregationType: AggregationType; @@ -101,13 +110,13 @@ export function TransactionDurationRuleType(props: Props) { } ); - const { data } = useFetcher( + const { data, status } = useFetcher( (callApmApi) => { const { interval, start, end } = getIntervalAndTimeRange({ windowSize: params.windowSize, windowUnit: params.windowUnit, }); - if (interval && start && end) { + if (params.windowSize && start && end) { return callApmApi( 'GET /internal/apm/rule_types/transaction_duration/chart_preview', { @@ -121,6 +130,7 @@ export function TransactionDurationRuleType(props: Props) { interval, start, end, + groupBy: params.groupBy, }, }, } @@ -135,28 +145,39 @@ export function TransactionDurationRuleType(props: Props) { params.transactionName, params.windowSize, params.windowUnit, + params.groupBy, ] ); - const latencyChartPreview = data?.latencyChartPreview ?? []; + const latencyChartPreview = data?.latencyChartPreview; + const series = latencyChartPreview?.series ?? []; + const hasData = series.length > 0; + const totalGroups = latencyChartPreview?.totalGroups ?? 0; - const maxY = getMaxY(latencyChartPreview); + const maxY = getMaxY(series); const formatter = getDurationFormatter(maxY); const yTickFormat = getResponseTimeTickFormatter(formatter); // The threshold from the form is in ms. Convert to µs. const thresholdMs = params.threshold * 1000; - // hide preview chart until https://github.com/elastic/kibana/pull/156625 gets merged - const showChartPreview = false; - const chartPreview = showChartPreview ? ( + const chartPreview = isPending(status) ? ( + + ) : !hasData ? ( + + ) : status === FETCH_STATUS.SUCCESS ? ( - ) : null; + ) : ( + + ); const onGroupByChange = useCallback( (group: string[] | null) => { diff --git a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx index e7d45114c1f8f..cec7f8cc7f129 100644 --- a/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/rule_types/transaction_error_rate_rule_type/index.tsx @@ -18,7 +18,11 @@ import { EuiFormRow } from '@elastic/eui'; import { EuiSpacer } from '@elastic/eui'; import { ENVIRONMENT_ALL } from '../../../../../common/environment_filter_values'; import { asPercent } from '../../../../../common/utils/formatters'; -import { useFetcher } from '../../../../hooks/use_fetcher'; +import { + FETCH_STATUS, + isPending, + useFetcher, +} from '../../../../hooks/use_fetcher'; import { createCallApmApi } from '../../../../services/rest/create_call_apm_api'; import { ChartPreview } from '../../ui_components/chart_preview'; import { @@ -37,6 +41,11 @@ import { TRANSACTION_TYPE, TRANSACTION_NAME, } from '../../../../../common/es_fields/apm'; +import { + ErrorState, + LoadingState, + NoDataState, +} from '../../ui_components/chart_preview/chart_preview_helper'; export interface RuleParams { windowSize?: number; @@ -74,15 +83,13 @@ export function TransactionErrorRateRuleType(props: Props) { } ); - const thresholdAsPercent = (params.threshold ?? 0) / 100; - - const { data } = useFetcher( + const { data, status } = useFetcher( (callApmApi) => { const { interval, start, end } = getIntervalAndTimeRange({ windowSize: params.windowSize, windowUnit: params.windowUnit, }); - if (interval && start && end) { + if (params.windowSize && start && end) { return callApmApi( 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', { @@ -95,6 +102,7 @@ export function TransactionErrorRateRuleType(props: Props) { interval, start, end, + groupBy: params.groupBy, }, }, } @@ -108,6 +116,7 @@ export function TransactionErrorRateRuleType(props: Props) { params.serviceName, params.windowSize, params.windowUnit, + params.groupBy, ] ); @@ -171,16 +180,28 @@ export function TransactionErrorRateRuleType(props: Props) { />, ]; - // hide preview chart until https://github.com/elastic/kibana/pull/156625 gets merged - const showChartPreview = false; - const chartPreview = showChartPreview ? ( + const errorRateChartPreview = data?.errorRateChartPreview; + const series = errorRateChartPreview?.series ?? []; + const hasData = series.length > 0; + const totalGroups = errorRateChartPreview?.totalGroups ?? 0; + + const chartPreview = isPending(status) ? ( + + ) : !hasData ? ( + + ) : status === FETCH_STATUS.SUCCESS ? ( asPercent(d, 1)} - threshold={thresholdAsPercent} + series={series} + yTickFormat={(d: number | null) => asPercent(d, 100)} + threshold={params.threshold} uiSettings={services.uiSettings} + timeSize={params.windowSize} + timeUnit={params.windowUnit} + totalGroups={totalGroups} /> - ) : null; + ) : ( + + ); const groupAlertsBy = ( <> diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/chart_preview_helper.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/chart_preview_helper.tsx new file mode 100644 index 0000000000000..f47a4293df675 --- /dev/null +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/chart_preview_helper.tsx @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiLoadingChart } from '@elastic/eui'; +import { EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { Coordinate } from '../../../../../typings/timeseries'; + +export const TIME_LABELS = { + s: i18n.translate('xpack.apm.alerts.timeLabels.seconds', { + defaultMessage: 'seconds', + }), + m: i18n.translate('xpack.apm.alerts.timeLabels.minutes', { + defaultMessage: 'minutes', + }), + h: i18n.translate('xpack.apm.alerts.timeLabels.hours', { + defaultMessage: 'hours', + }), + d: i18n.translate('xpack.apm.alerts.timeLabels.days', { + defaultMessage: 'days', + }), +}; + +export const getDomain = ( + series: Array<{ name?: string; data: Coordinate[] }> +) => { + const xValues = series.flatMap((item) => item.data.map((d) => d.x)); + const yValues = series.flatMap((item) => item.data.map((d) => d.y || 0)); + return { + xMax: Math.max(...xValues), + xMin: Math.min(...xValues), + yMax: Math.max(...yValues), + yMin: Math.min(...yValues), + }; +}; + +const EmptyContainer: React.FC = ({ children }) => ( +
    + {children} +
    +); + +export function NoDataState() { + return ( + + + + + + ); +} + +export function LoadingState() { + return ( + + + + + + ); +} + +export function ErrorState() { + return ( + + + + + + ); +} + +interface PreviewChartLabel { + lookback: number; + timeLabel: string; + displayedGroups: number; + totalGroups: number; +} + +export function TimeLabelForData({ + lookback, + timeLabel, + displayedGroups, + totalGroups, +}: PreviewChartLabel) { + return ( +
    + + + +
    + ); +} diff --git a/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/index.tsx b/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/index.tsx index 0e0b09109387c..083b52280deff 100644 --- a/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/index.tsx +++ b/x-pack/plugins/apm/public/components/alerting/ui_components/chart_preview/index.tsx @@ -11,26 +11,39 @@ import { BarSeries, Chart, LineAnnotation, - niceTimeFormatter, Position, RectAnnotation, RectAnnotationDatum, ScaleType, Settings, TickFormatter, + TooltipProps, + niceTimeFormatter, } from '@elastic/charts'; import { EuiSpacer } from '@elastic/eui'; -import React, { useState } from 'react'; +import React, { useMemo } from 'react'; import { IUiSettingsClient } from '@kbn/core/public'; +import { TimeUnitChar } from '@kbn/observability-plugin/common'; +import { UI_SETTINGS } from '@kbn/data-plugin/public'; +import moment from 'moment'; import { Coordinate } from '../../../../../typings/timeseries'; import { useTheme } from '../../../../hooks/use_theme'; import { getTimeZone } from '../../../shared/charts/helper/timezone'; +import { + TimeLabelForData, + TIME_LABELS, + getDomain, +} from './chart_preview_helper'; +import { ALERT_PREVIEW_BUCKET_SIZE } from '../../utils/helper'; interface ChartPreviewProps { yTickFormat?: TickFormatter; threshold: number; uiSettings?: IUiSettingsClient; series: Array<{ name?: string; data: Coordinate[] }>; + timeSize?: number; + timeUnit?: TimeUnitChar; + totalGroups: number; } export function ChartPreview({ @@ -38,21 +51,12 @@ export function ChartPreview({ threshold, uiSettings, series, + timeSize = 5, + timeUnit = 'm', + totalGroups, }: ChartPreviewProps) { - const [yMax, setYMax] = useState(threshold); - const theme = useTheme(); const thresholdOpacity = 0.3; - const timestamps = series.flatMap(({ data }) => data.map(({ x }) => x)); - const xMin = Math.min(...timestamps); - const xMax = Math.max(...timestamps); - const xFormatter = niceTimeFormatter([xMin, xMax]); - - function updateYMax() { - // Make the maximum Y value either the actual max or 20% more than the threshold - const values = series.flatMap(({ data }) => data.map((d) => d.y ?? 0)); - setYMax(Math.max(...values, threshold * 1.2)); - } const style = { fill: theme.eui.euiColorVis2, @@ -64,36 +68,69 @@ export function ChartPreview({ opacity: thresholdOpacity, }; + const DEFAULT_DATE_FORMAT = 'Y-MM-DD HH:mm:ss'; + + const tooltipProps: TooltipProps = { + headerFormatter: ({ value }) => { + const dateFormat = + (uiSettings && uiSettings.get(UI_SETTINGS.DATE_FORMAT)) || + DEFAULT_DATE_FORMAT; + return moment(value).format(dateFormat); + }, + }; + + const barSeries = useMemo(() => { + return series.flatMap((serie) => + serie.data.map((point) => ({ ...point, groupBy: serie.name })) + ); + }, [series]); + + const timeZone = getTimeZone(uiSettings); + + const legendSize = + series.length > 1 ? Math.ceil(series.length / 2) * 30 : series.length * 35; + + const chartSize = 150; + + const { yMin, yMax, xMin, xMax } = getDomain(series); + const chartDomain = { + max: Math.max(yMax, threshold) * 1.1, // Add 10% headroom. + min: Math.min(yMin, threshold) * 0.9, // Add 10% headroom. + }; + + const dateFormatter = useMemo( + () => niceTimeFormatter([xMin, xMax]), + [xMin, xMax] + ); + + const lookback = timeSize * ALERT_PREVIEW_BUCKET_SIZE; + const timeLabel = TIME_LABELS[timeUnit as keyof typeof TIME_LABELS]; + const rectDataValues: RectAnnotationDatum[] = [ { coordinates: { - x0: null, - x1: null, + x0: xMin, + x1: xMax, y0: threshold, - y1: null, + y1: chartDomain.max, }, }, ]; - const timeZone = getTimeZone(uiSettings); - const legendSize = Math.ceil(series.length / 2) * 30; - const chartSize = 150; - return ( <> 1 ? chartSize + legendSize : chartSize, + height: chartSize + legendSize, }} data-test-subj="ChartPreview" > 1} + tooltip={tooltipProps} + showLegend={true} legendPosition={'bottom'} legendSize={legendSize} - onLegendItemClick={updateYMax} /> + - {series.map(({ name, data }, index) => ( - - ))} + {series.length > 0 && ( + + )} ); } diff --git a/x-pack/plugins/apm/public/components/alerting/utils/helper.ts b/x-pack/plugins/apm/public/components/alerting/utils/helper.ts index e5dc2a78b5a1c..7cc0d958aaf9e 100644 --- a/x-pack/plugins/apm/public/components/alerting/utils/helper.ts +++ b/x-pack/plugins/apm/public/components/alerting/utils/helper.ts @@ -16,7 +16,7 @@ export interface AlertMetadata { end?: string; } -const BUCKET_SIZE = 20; +export const ALERT_PREVIEW_BUCKET_SIZE = 5; export function getIntervalAndTimeRange({ windowSize, @@ -28,7 +28,8 @@ export function getIntervalAndTimeRange({ const end = Date.now(); const start = end - - moment.duration(windowSize, windowUnit).asMilliseconds() * BUCKET_SIZE; + moment.duration(windowSize, windowUnit).asMilliseconds() * + ALERT_PREVIEW_BUCKET_SIZE; return { interval: `${windowSize}${windowUnit}`, diff --git a/x-pack/plugins/apm/public/components/app/onboarding/agent_config_table.tsx b/x-pack/plugins/apm/public/components/app/onboarding/agent_config_table.tsx index 33359b1713ab5..8f73bef94e581 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/agent_config_table.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/agent_config_table.tsx @@ -13,9 +13,10 @@ import { EuiText, EuiBasicTableColumn, EuiButton, + EuiButtonIcon, + copyToClipboard, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; - function ConfigurationValueColumn({ columnKey, value, @@ -46,9 +47,19 @@ function ConfigurationValueColumn({ } return ( - - {value} - + <> + + {value} + + {value && ( + copyToClipboard(value)} + /> + )} + ); } diff --git a/x-pack/plugins/apm/public/components/app/onboarding/agent_status_instructions.tsx b/x-pack/plugins/apm/public/components/app/onboarding/agent_status_instructions.tsx new file mode 100644 index 0000000000000..ff89206483381 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/onboarding/agent_status_instructions.tsx @@ -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'; +import { + EuiButton, + EuiCallOut, + EuiMarkdownFormat, + EuiSpacer, +} from '@elastic/eui'; +import React from 'react'; +import { EuiStepStatus } from '@elastic/eui/src/components/steps/step_number'; + +function AgentStatusWarningCallout() { + return ( + + {i18n.translate( + 'xpack.apm.onboarding.agentStatus.warning.calloutMessage', + { + defaultMessage: 'No data has been received from agents yet', + } + )} + + ); +} + +function AgentStatusSuccessCallout() { + return ( + + {i18n.translate( + 'xpack.apm.onboarding.agentStatus.success.calloutMessage', + { + defaultMessage: 'Data successfully received from one or more agents', + } + )} + + ); +} + +export function agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, +}: { + checkAgentStatus: () => void; + agentStatus?: boolean; + agentStatusLoading: boolean; +}) { + let status: EuiStepStatus = 'incomplete'; + let statusCallout = <>; + // Explicit false check required as this value can be null initially. API returns true/false based on data present + if (agentStatus === false) { + status = 'warning'; + statusCallout = ; + } + if (agentStatus) { + status = 'complete'; + statusCallout = ; + } + return { + title: i18n.translate('xpack.apm.onboarding.agentStatusCheck.title', { + defaultMessage: 'Agent status', + }), + children: ( + <> + + {i18n.translate('xpack.apm.onboarding.agentStatusCheck.textPre', { + defaultMessage: + 'Make sure your application is running and the agents are sending data.', + })} + + + + {i18n.translate('xpack.apm.onboarding.agentStatus.check', { + defaultMessage: 'Check Agent Status', + })} + + + {statusCallout} + + ), + status, + }; +} diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/django.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/django.ts index 993138c69110e..47c7f595ae6b5 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/django.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/django.ts @@ -8,18 +8,16 @@ import { i18n } from '@kbn/i18n'; export const djangoVariables = (secretToken?: string) => ({ - apmServiceName: 'SERVICE_NAME', ...(secretToken && { secretToken: 'SECRET_TOKEN' }), ...(!secretToken && { apiKey: 'API_KEY' }), apmServerUrl: 'SERVER_URL', - apmEnvironment: 'ENVIRONMENT', }); export const djangoHighlightLang = 'py'; export const djangoLineNumbers = () => ({ start: 1, - highlight: '1, 3, 5, 7, 9, 12, 15, 18-19, 21, 23, 25', + highlight: '1, 3, 5, 7, 9, 12, 15, 18-19, 21, 23, 25', }); export const django = `INSTALLED_APPS = ( @@ -35,7 +33,7 @@ export const django = `INSTALLED_APPS = ( ELASTIC_APM = { # {{serviceNameHint}} - 'SERVICE_NAME': 'my-service-name', + 'SERVICE_NAME': '', {{^secretToken}} # {{apiKeyHint}} @@ -50,7 +48,7 @@ ELASTIC_APM = { 'SERVER_URL': '{{{apmServerUrl}}}', # {{{serviceEnvironmentHint}}} - 'ENVIRONMENT': 'my-environment', + 'ENVIRONMENT': '', } MIDDLEWARE = ( diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/dotnet.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/dotnet.ts index 84c1b2a3f2603..7a77694b62920 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/dotnet.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/dotnet.ts @@ -4,15 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { i18n } from '@kbn/i18n'; export const dotnetVariables = (secretToken?: string) => ({ - apmServiceName: 'ServiceName', ...(secretToken && { secretToken: 'SecretToken' }), ...(!secretToken && { apiKey: 'ApiKey' }), apmServerUrl: 'ServerUrl', - apmEnvironment: 'Environment', }); export const dotnetHighlightLang = 'dotnet'; @@ -30,7 +27,7 @@ export const dotnet = `{ defaultMessage: 'Default is the entry assembly of the application.', } )} - "ServiceName": "my-service-name", + "ServiceName": "", {{^secretToken}} /// {{apiKeyHint}} "ApiKey": "{{{apiKey}}}", @@ -42,6 +39,6 @@ export const dotnet = `{ /// {{{serverUrlHint}}} "ServerUrl": "{{{apmServerUrl}}}", /// {{{serviceEnvironmentHint}}} - "Environment": "my-environment", + "Environment": "", } }`; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/flask.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/flask.ts index a95d64a11a318..e05cd88875cf4 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/flask.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/flask.ts @@ -8,18 +8,16 @@ import { i18n } from '@kbn/i18n'; export const flaskVariables = (secretToken?: string) => ({ - apmServiceName: 'SERVICE_NAME', ...(secretToken && { secretToken: 'SECRET_TOKEN' }), ...(!secretToken && { apiKey: 'API_KEY' }), apmServerUrl: 'SERVER_URL', - apmEnvironment: 'ENVIRONMENT', }); export const flaskHighlightLang = 'py'; export const flaskLineNumbers = () => ({ start: 1, - highlight: '2-4, 7-8, 10, 13, 16, 19-22', + highlight: '2-4, 7-8, 10, 12, 15, 18-21', }); export const flask = `# ${i18n.translate( @@ -41,8 +39,7 @@ apm = ElasticAPM(app) from elasticapm.contrib.flask import ElasticAPM app.config['ELASTIC_APM'] = { # {{serviceNameHint}} - 'SERVICE_NAME': 'my-service-name', - + 'SERVICE_NAME': '', {{^secretToken}} # {{apiKeyHint}} 'API_KEY': '{{{apiKey}}}', @@ -55,8 +52,8 @@ app.config['ELASTIC_APM'] = { # {{{serverUrlHint}}} 'SERVER_URL': '{{{apmServerUrl}}}', - {{{serviceEnvironmentHint}}} - 'ENVIRONMENT': 'my-environment', + # {{{serviceEnvironmentHint}}} + 'ENVIRONMENT': '', } apm = ElasticAPM(app)`; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/get_apm_agent_commands.test.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/get_apm_agent_commands.test.ts index 2ff78a0321e93..b26c8da82d916 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/get_apm_agent_commands.test.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/get_apm_agent_commands.test.ts @@ -25,10 +25,10 @@ describe('getCommands', () => { }); expect(commands).toMatchInlineSnapshot(` "java -javaagent:/path/to/elastic-apm-agent-.jar \\\\ - -Delastic.apm.service_name=my-service-name \\\\ + -Delastic.apm.service_name= \\\\\\\\ -Delastic.apm.api_key= \\\\ -Delastic.apm.server_url= \\\\ - -Delastic.apm.environment=my-environment \\\\ + -Delastic.apm.environment= \\\\\\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -42,10 +42,10 @@ describe('getCommands', () => { expect(commands).not.toBe(''); expect(commands).toMatchInlineSnapshot(` "java -javaagent:/path/to/elastic-apm-agent-.jar \\\\ - -Delastic.apm.service_name=my-service-name \\\\ + -Delastic.apm.service_name= \\\\\\\\ -Delastic.apm.secret_token=foobar \\\\ -Delastic.apm.server_url=localhost:8220 \\\\ - -Delastic.apm.environment=my-environment \\\\ + -Delastic.apm.environment= \\\\\\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -60,10 +60,10 @@ describe('getCommands', () => { expect(commands).not.toBe(''); expect(commands).toMatchInlineSnapshot(` "java -javaagent:/path/to/elastic-apm-agent-.jar \\\\ - -Delastic.apm.service_name=my-service-name \\\\ + -Delastic.apm.service_name= \\\\\\\\ -Delastic.apm.secret_token=foobar \\\\ -Delastic.apm.server_url=localhost:8220 \\\\ - -Delastic.apm.environment=my-environment \\\\ + -Delastic.apm.environment= \\\\\\\\ -Delastic.apm.application_packages=org.example \\\\ -jar my-service-name.jar" `); @@ -79,9 +79,8 @@ describe('getCommands', () => { expect(commands).toMatchInlineSnapshot(` "// Add this to the very top of the first file loaded in your app var apm = require('elastic-apm-node').start({ - // The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Overrides the service name in package.json. - serviceName: 'my-service-name', + serviceName: '', // Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. apiKey: '', @@ -90,7 +89,7 @@ describe('getCommands', () => { serverUrl: '', // The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment' + environment: '' })" `); }); @@ -104,9 +103,8 @@ describe('getCommands', () => { expect(commands).toMatchInlineSnapshot(` "// Add this to the very top of the first file loaded in your app var apm = require('elastic-apm-node').start({ - // The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Overrides the service name in package.json. - serviceName: 'my-service-name', + serviceName: '', // Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. secretToken: 'foobar', @@ -115,7 +113,7 @@ describe('getCommands', () => { serverUrl: 'localhost:8220', // The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment' + environment: '' })" `); }); @@ -130,9 +128,8 @@ describe('getCommands', () => { expect(commands).toMatchInlineSnapshot(` "// Add this to the very top of the first file loaded in your app var apm = require('elastic-apm-node').start({ - // The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Overrides the service name in package.json. - serviceName: 'my-service-name', + serviceName: '', // Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. secretToken: 'foobar', @@ -141,7 +138,7 @@ describe('getCommands', () => { serverUrl: 'localhost:8220', // The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment' + environment: '' })" `); }); @@ -161,7 +158,7 @@ describe('getCommands', () => { ELASTIC_APM = { # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - 'SERVICE_NAME': 'my-service-name', + 'SERVICE_NAME': '', # Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. 'API_KEY': '', @@ -170,7 +167,7 @@ describe('getCommands', () => { 'SERVER_URL': '', # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - 'ENVIRONMENT': 'my-environment', + 'ENVIRONMENT': '', } MIDDLEWARE = ( @@ -196,7 +193,7 @@ describe('getCommands', () => { ELASTIC_APM = { # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - 'SERVICE_NAME': 'my-service-name', + 'SERVICE_NAME': '', # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. 'SECRET_TOKEN': 'foobar', @@ -205,7 +202,7 @@ describe('getCommands', () => { 'SERVER_URL': 'localhost:8220', # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - 'ENVIRONMENT': 'my-environment', + 'ENVIRONMENT': '', } MIDDLEWARE = ( @@ -232,7 +229,7 @@ describe('getCommands', () => { ELASTIC_APM = { # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - 'SERVICE_NAME': 'my-service-name', + 'SERVICE_NAME': '', # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. 'SECRET_TOKEN': 'foobar', @@ -241,7 +238,7 @@ describe('getCommands', () => { 'SERVER_URL': 'localhost:8220', # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - 'ENVIRONMENT': 'my-environment', + 'ENVIRONMENT': '', } MIDDLEWARE = ( @@ -268,16 +265,15 @@ describe('getCommands', () => { from elasticapm.contrib.flask import ElasticAPM app.config['ELASTIC_APM'] = { # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - 'SERVICE_NAME': 'my-service-name', - + 'SERVICE_NAME': '', # Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. 'API_KEY': '', # Set the custom APM Server URL (default: http://localhost:8200). The URL must be fully qualified, including protocol (http or https) and port. 'SERVER_URL': '', - The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - 'ENVIRONMENT': 'my-environment', + # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. + 'ENVIRONMENT': '', } apm = ElasticAPM(app)" @@ -300,16 +296,15 @@ describe('getCommands', () => { from elasticapm.contrib.flask import ElasticAPM app.config['ELASTIC_APM'] = { # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - 'SERVICE_NAME': 'my-service-name', - + 'SERVICE_NAME': '', # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. 'SECRET_TOKEN': 'foobar', # Set the custom APM Server URL (default: http://localhost:8200). The URL must be fully qualified, including protocol (http or https) and port. 'SERVER_URL': 'localhost:8220', - The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - 'ENVIRONMENT': 'my-environment', + # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. + 'ENVIRONMENT': '', } apm = ElasticAPM(app)" @@ -333,16 +328,15 @@ describe('getCommands', () => { from elasticapm.contrib.flask import ElasticAPM app.config['ELASTIC_APM'] = { # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - 'SERVICE_NAME': 'my-service-name', - + 'SERVICE_NAME': '', # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. 'SECRET_TOKEN': 'foobar', # Set the custom APM Server URL (default: http://localhost:8200). The URL must be fully qualified, including protocol (http or https) and port. 'SERVER_URL': 'localhost:8220', - The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - 'ENVIRONMENT': 'my-environment', + # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. + 'ENVIRONMENT': '', } apm = ElasticAPM(app)" @@ -359,7 +353,7 @@ describe('getCommands', () => { "# config/elastic_apm.yml: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Defaults to the name of your Rails app. - service_name: 'my-service-name' + service_name: '' # Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. api_key: '' @@ -368,7 +362,7 @@ describe('getCommands', () => { server_url: '' # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment'" + environment: ''" `); }); it('renders with secret token and url', () => { @@ -382,7 +376,7 @@ describe('getCommands', () => { "# config/elastic_apm.yml: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Defaults to the name of your Rails app. - service_name: 'my-service-name' + service_name: '' # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. secret_token: 'foobar' @@ -391,7 +385,7 @@ describe('getCommands', () => { server_url: 'localhost:8220' # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment'" + environment: ''" `); }); it('renders with api key even though secret token is present', () => { @@ -406,7 +400,7 @@ describe('getCommands', () => { "# config/elastic_apm.yml: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Defaults to the name of your Rails app. - service_name: 'my-service-name' + service_name: '' # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. secret_token: 'foobar' @@ -415,7 +409,7 @@ describe('getCommands', () => { server_url: 'localhost:8220' # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment'" + environment: ''" `); }); }); @@ -429,7 +423,7 @@ describe('getCommands', () => { "# config/elastic_apm.yml: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Defaults to the name of your Rack app's class. - service_name: 'my-service-name' + service_name: '' # Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. api_key: '' @@ -438,7 +432,7 @@ describe('getCommands', () => { server_url: '' # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment'" + environment: ''" `); }); it('renders with secret token and url', () => { @@ -452,7 +446,7 @@ describe('getCommands', () => { "# config/elastic_apm.yml: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Defaults to the name of your Rack app's class. - service_name: 'my-service-name' + service_name: '' # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. secret_token: 'foobar' @@ -461,7 +455,7 @@ describe('getCommands', () => { server_url: 'localhost:8220' # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment'" + environment: ''" `); }); it('renders with api key even though secret token is present', () => { @@ -476,7 +470,7 @@ describe('getCommands', () => { "# config/elastic_apm.yml: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Defaults to the name of your Rack app's class. - service_name: 'my-service-name' + service_name: '' # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. secret_token: 'foobar' @@ -485,7 +479,7 @@ describe('getCommands', () => { server_url: 'localhost:8220' # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - environment: 'my-environment'" + environment: ''" `); }); }); @@ -499,7 +493,7 @@ describe('getCommands', () => { "# Initialize using environment variables: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. If not specified, the executable name will be used. - export ELASTIC_APM_SERVICE_NAME=my-service-name + export ELASTIC_APM_SERVICE_NAME= # Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. export ELASTIC_APM_API_KEY= @@ -508,7 +502,7 @@ describe('getCommands', () => { export ELASTIC_APM_SERVER_URL= # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - export ELASTIC_APM_ENVIRONMENT=my-environment + export ELASTIC_APM_ENVIRONMENT= " `); }); @@ -523,7 +517,7 @@ describe('getCommands', () => { "# Initialize using environment variables: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. If not specified, the executable name will be used. - export ELASTIC_APM_SERVICE_NAME=my-service-name + export ELASTIC_APM_SERVICE_NAME= # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. export ELASTIC_APM_SECRET_TOKEN=foobar @@ -532,7 +526,7 @@ describe('getCommands', () => { export ELASTIC_APM_SERVER_URL=localhost:8220 # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - export ELASTIC_APM_ENVIRONMENT=my-environment + export ELASTIC_APM_ENVIRONMENT= " `); }); @@ -548,7 +542,7 @@ describe('getCommands', () => { "# Initialize using environment variables: # The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. If not specified, the executable name will be used. - export ELASTIC_APM_SERVICE_NAME=my-service-name + export ELASTIC_APM_SERVICE_NAME= # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. export ELASTIC_APM_SECRET_TOKEN=foobar @@ -557,7 +551,7 @@ describe('getCommands', () => { export ELASTIC_APM_SERVER_URL=localhost:8220 # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - export ELASTIC_APM_ENVIRONMENT=my-environment + export ELASTIC_APM_ENVIRONMENT= " `); }); @@ -572,13 +566,13 @@ describe('getCommands', () => { "{ \\"ElasticApm\\": { /// The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application. - \\"ServiceName\\": \\"my-service-name\\", + \\"ServiceName\\": \\"\\", /// Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. \\"ApiKey\\": \\"\\", /// Set the custom APM Server URL (default: http://localhost:8200). The URL must be fully qualified, including protocol (http or https) and port. \\"ServerUrl\\": \\"\\", /// The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - \\"Environment\\": \\"my-environment\\", + \\"Environment\\": \\"\\", } }" `); @@ -594,13 +588,13 @@ describe('getCommands', () => { "{ \\"ElasticApm\\": { /// The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application. - \\"ServiceName\\": \\"my-service-name\\", + \\"ServiceName\\": \\"\\", /// Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. \\"SecretToken\\": \\"foobar\\", /// Set the custom APM Server URL (default: http://localhost:8200). The URL must be fully qualified, including protocol (http or https) and port. \\"ServerUrl\\": \\"localhost:8220\\", /// The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - \\"Environment\\": \\"my-environment\\", + \\"Environment\\": \\"\\", } }" `); @@ -617,13 +611,13 @@ describe('getCommands', () => { "{ \\"ElasticApm\\": { /// The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. Default is the entry assembly of the application. - \\"ServiceName\\": \\"my-service-name\\", + \\"ServiceName\\": \\"\\", /// Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. \\"SecretToken\\": \\"foobar\\", /// Set the custom APM Server URL (default: http://localhost:8200). The URL must be fully qualified, including protocol (http or https) and port. \\"ServerUrl\\": \\"localhost:8220\\", /// The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - \\"Environment\\": \\"my-environment\\", + \\"Environment\\": \\"\\", } }" `); @@ -637,7 +631,7 @@ describe('getCommands', () => { expect(commands).not.toBe(''); expect(commands).toMatchInlineSnapshot(` "# The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - elastic_apm.service_name=\\"my-service-name\\" + elastic_apm.service_name=\\"\\" # Use if APM Server requires an API Key. This is used to ensure that only your agents can send data to your APM server. Agents can use API keys as a replacement of secret token, APM server can have multiple API keys. When both secret token and API key are used, API key has priority and secret token is ignored. elastic_apm.api_key=\\"\\" @@ -646,7 +640,7 @@ describe('getCommands', () => { elastic_apm.server_url=\\"\\" # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - elastic_apm.environment=\\"my-environment\\"" + elastic_apm.environment=\\"\\"" `); }); it('renders with secret token and url', () => { @@ -658,7 +652,7 @@ describe('getCommands', () => { expect(commands).not.toBe(''); expect(commands).toMatchInlineSnapshot(` "# The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - elastic_apm.service_name=\\"my-service-name\\" + elastic_apm.service_name=\\"\\" # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. elastic_apm.secret_token=\\"foobar\\" @@ -667,7 +661,7 @@ describe('getCommands', () => { elastic_apm.server_url=\\"localhost:8220\\" # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - elastic_apm.environment=\\"my-environment\\"" + elastic_apm.environment=\\"\\"" `); }); it('renders with api key even though secret token is present', () => { @@ -680,7 +674,7 @@ describe('getCommands', () => { expect(commands).not.toBe(''); expect(commands).toMatchInlineSnapshot(` "# The service name is the primary filter in the APM UI and is used to group errors and trace data together. Allowed characters are a-z, A-Z, 0-9, -, _, and space. - elastic_apm.service_name=\\"my-service-name\\" + elastic_apm.service_name=\\"\\" # Use if APM Server requires a secret token. Both the agent and APM Server must be configured with the same token. This ensures that only your agents can send data to your APM server. elastic_apm.secret_token=\\"foobar\\" @@ -689,7 +683,7 @@ describe('getCommands', () => { elastic_apm.server_url=\\"localhost:8220\\" # The name of the environment this service is deployed in, e.g., \\"production\\" or \\"staging\\". Environments allow you to easily filter data on a global level in the APM UI. It's important to be consistent when naming environments across agents. - elastic_apm.environment=\\"my-environment\\"" + elastic_apm.environment=\\"\\"" `); }); }); diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/go.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/go.ts index c95cb30606c85..b3d26e715fd0c 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/go.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/go.ts @@ -8,11 +8,9 @@ import { i18n } from '@kbn/i18n'; export const goVariables = (secretToken?: string) => ({ - apmServiceName: 'ELASTIC_APM_SERVICE_NAME', ...(secretToken && { secretToken: 'ELASTIC_APM_SECRET_TOKEN' }), ...(!secretToken && { apiKey: 'ELASTIC_APM_API_KEY' }), apmServerUrl: 'ELASTIC_APM_SERVER_URL', - apmEnvironment: 'ELASTIC_APM_ENVIRONMENT', }); export const goHighlightLang = 'go'; @@ -35,7 +33,7 @@ export const go = `# ${i18n.translate( defaultMessage: 'If not specified, the executable name will be used.', } )} -export ELASTIC_APM_SERVICE_NAME=my-service-name +export ELASTIC_APM_SERVICE_NAME= {{^secretToken}} # {{apiKeyHint}} @@ -50,5 +48,5 @@ export ELASTIC_APM_SECRET_TOKEN={{{secretToken}}} export ELASTIC_APM_SERVER_URL={{{apmServerUrl}}} # {{{serviceEnvironmentHint}}} -export ELASTIC_APM_ENVIRONMENT=my-environment +export ELASTIC_APM_ENVIRONMENT= `; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/java.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/java.ts index f093b0b241af0..fd8ffec78e29d 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/java.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/java.ts @@ -14,11 +14,9 @@ import { } from './shared_hints'; export const javaVariables = (secretToken?: string) => ({ - apmServiceName: 'Delastic.apm.service_name', ...(secretToken && { secretToken: 'Delastic.apm.secret_token' }), ...(!secretToken && { apiKey: 'Delastic.apm.api_key' }), apmServerUrl: 'Delastic.apm.server_url', - apmEnvironment: 'Delastic.apm.environment', }); export const javaHighlightLang = 'java'; @@ -34,7 +32,7 @@ export const javaLineNumbers = (apiKey?: string | null) => ({ }, }); export const java = `java -javaagent:/path/to/elastic-apm-agent-.jar \\ --Delastic.apm.service_name=my-service-name \\ +-Delastic.apm.service_name= \\\\ {{^secretToken}} -Delastic.apm.api_key={{{apiKey}}} \\ {{/secretToken}} @@ -42,6 +40,6 @@ export const java = `java -javaagent:/path/to/elastic-apm-agent-.jar \\ -Delastic.apm.secret_token={{{secretToken}}} \\ {{/secretToken}} -Delastic.apm.server_url={{{apmServerUrl}}} \\ --Delastic.apm.environment=my-environment \\ +-Delastic.apm.environment= \\\\ -Delastic.apm.application_packages=org.example \\ -jar my-service-name.jar`; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/node.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/node.ts index 97e2ab0b43809..825a3d05ac800 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/node.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/node.ts @@ -7,18 +7,16 @@ import { i18n } from '@kbn/i18n'; export const nodeVariables = (secretToken?: string) => ({ - apmServiceName: 'serviceName', ...(secretToken && { secretToken: 'secretToken' }), ...(!secretToken && { apiKey: 'apiKey' }), apmServerUrl: 'serverUrl', - apmEnvironment: 'environment', }); export const nodeHighlightLang = 'js'; export const nodeLineNumbers = () => ({ start: 1, - highlight: '2, 5, 8, 11, 14-15', + highlight: '2, 4, 7, 10, 13-14', }); export const node = `// ${i18n.translate( @@ -29,14 +27,13 @@ export const node = `// ${i18n.translate( } )} var apm = require('elastic-apm-node').start({ - // {{serviceNameHint}} ${i18n.translate( 'xpack.apm.onboarding.nodeClient.createConfig.commands.serviceName', { defaultMessage: 'Overrides the service name in package.json.', } )} - serviceName: 'my-service-name', + serviceName: '', {{^secretToken}} // {{apiKeyHint}} @@ -51,5 +48,5 @@ var apm = require('elastic-apm-node').start({ serverUrl: '{{{apmServerUrl}}}', // {{{serviceEnvironmentHint}}} - environment: 'my-environment' + environment: '' })`; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/php.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/php.ts index c00fea44dc998..b6d5d55053312 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/php.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/php.ts @@ -5,11 +5,9 @@ * 2.0. */ export const phpVariables = (secretToken?: string) => ({ - apmServiceName: 'elastic_apm.service_name', ...(secretToken && { secretToken: 'elastic_apm.secret_token' }), ...(!secretToken && { apiKey: 'elastic_apm.api_key' }), apmServerUrl: 'elastic_apm.server_url', - apmEnvironment: 'elastic_apm.environment', }); export const phpHighlightLang = 'php'; @@ -20,7 +18,7 @@ export const phpLineNumbers = () => ({ }); export const php = `# {{serviceNameHint}} -elastic_apm.service_name="my-service-name" +elastic_apm.service_name="" {{^secretToken}} # {{apiKeyHint}} @@ -35,4 +33,4 @@ elastic_apm.secret_token="{{{secretToken}}}" elastic_apm.server_url="{{{apmServerUrl}}}" # {{{serviceEnvironmentHint}}} -elastic_apm.environment="my-environment"`; +elastic_apm.environment=""`; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/rack.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/rack.ts index 54d484d92c513..f8974cba45543 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/rack.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/rack.ts @@ -4,15 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { i18n } from '@kbn/i18n'; export const rackVariables = (secretToken?: string) => ({ - apmServiceName: 'service_name', ...(secretToken && { secretToken: 'secret_token' }), ...(!secretToken && { apiKey: 'api_key' }), apmServerUrl: 'server_url', - apmEnvironment: 'environment', }); export const rackHighlightLang = 'rb'; @@ -30,7 +27,7 @@ export const rack = `# config/elastic_apm.yml: defaultMessage: "Defaults to the name of your Rack app's class.", } )} -service_name: 'my-service-name' +service_name: '' {{^secretToken}} # {{apiKeyHint}} @@ -45,4 +42,4 @@ secret_token: '{{{secretToken}}}' server_url: '{{{apmServerUrl}}}' # {{{serviceEnvironmentHint}}} -environment: 'my-environment'`; +environment: ''`; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/commands/rails.ts b/x-pack/plugins/apm/public/components/app/onboarding/commands/rails.ts index 9f7bb313400eb..de8e0610a0f14 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/commands/rails.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/commands/rails.ts @@ -4,15 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { i18n } from '@kbn/i18n'; export const railsVariables = (secretToken?: string) => ({ - apmServiceName: 'service_name', ...(secretToken && { secretToken: 'secret_token' }), ...(!secretToken && { apiKey: 'api_key' }), apmServerUrl: 'server_url', - apmEnvironment: 'environment', }); export const railsHighlightLang = 'rb'; @@ -30,7 +27,7 @@ export const rails = `# config/elastic_apm.yml: defaultMessage: 'Defaults to the name of your Rails app.', } )} -service_name: 'my-service-name' +service_name: '' {{^secretToken}} # {{apiKeyHint}} @@ -45,4 +42,4 @@ secret_token: '{{{secretToken}}}' server_url: '{{{apmServerUrl}}}' # {{{serviceEnvironmentHint}}} -environment: 'my-environment'`; +environment: ''`; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/index.tsx b/x-pack/plugins/apm/public/components/app/onboarding/index.tsx index fdfc011a2d61f..3ce28542ce645 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/index.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { EuiSpacer } from '@elastic/eui'; import { callApmApi } from '../../../services/rest/create_call_apm_api'; @@ -25,6 +25,8 @@ export function Onboarding() { error: false, }); const [apiKeyLoading, setApiKeyLoading] = useState(false); + const [agentStatus, setAgentStatus] = useState(); + const [agentStatusLoading, setAgentStatusLoading] = useState(false); const { services } = useKibana(); const { config } = useApmPluginContext(); const { docLinks, observabilityShared } = services; @@ -34,7 +36,7 @@ export function Onboarding() { const baseUrl = docLinks?.ELASTIC_WEBSITE_URL || 'https://www.elastic.co/'; - const createAgentKey = useCallback(async () => { + const createAgentKey = async () => { try { setApiKeyLoading(true); const privileges: PrivilegeType[] = [PrivilegeType.EVENT]; @@ -55,8 +57,7 @@ export function Onboarding() { ); setAgentApiKey({ - apiKey: agentKey.api_key, - encodedKey: agentKey.encoded, + apiKey: agentKey.encoded, id: agentKey.id, error: false, }); @@ -69,7 +70,24 @@ export function Onboarding() { } finally { setApiKeyLoading(false); } - }, []); + }; + + const checkAgentStatus = async () => { + try { + setAgentStatusLoading(true); + const agentStatusCheck = await callApmApi( + 'GET /internal/apm/observability_overview/has_data', + { + signal: null, + } + ); + setAgentStatus(agentStatusCheck.hasData); + } catch (error) { + setAgentStatus(false); + } finally { + setAgentStatusLoading(false); + } + }; const instructionsExists = instructions.length > 0; @@ -81,13 +99,23 @@ export function Onboarding() { { baseUrl, config, + checkAgentStatus, + agentStatus, + agentStatusLoading, }, apiKeyLoading, agentApiKey, createAgentKey ), ]); - }, [agentApiKey, baseUrl, config, createAgentKey, apiKeyLoading]); + }, [ + agentApiKey, + baseUrl, + config, + apiKeyLoading, + agentStatus, + agentStatusLoading, + ]); const ObservabilityPageTemplate = observabilityShared.navigation.PageTemplate; return ( diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instruction_variants.ts b/x-pack/plugins/apm/public/components/app/onboarding/instruction_variants.ts index 7f9f0e6b62772..5ad4e8578b788 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instruction_variants.ts +++ b/x-pack/plugins/apm/public/components/app/onboarding/instruction_variants.ts @@ -50,7 +50,6 @@ export function getDisplayText(id: INSTRUCTION_VARIANT) { export interface AgentApiKey { apiKey: string | null; id?: string; - encodedKey?: string; error: boolean; errorMessage?: string; } @@ -67,4 +66,7 @@ export interface AgentInstructions { apmServerUrl: string; apiKeyDetails?: AgentApiDetails; secretToken?: string; + checkAgentStatus: () => void; + agentStatus?: boolean; + agentStatusLoading: boolean; } diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/api_key_callout.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/api_key_callout.tsx index 4601c7bfbfb97..79fea7a775de0 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/api_key_callout.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/api_key_callout.tsx @@ -30,6 +30,7 @@ export function ApiKeyCallout({ )} color="success" iconType="check" + data-test-subj="apiKeySuccessCallout" > {i18n.translate( 'xpack.apm.onboarding.apiKey.success.calloutMessage', @@ -57,6 +58,7 @@ export function ApiKeyCallout({ )} color="warning" iconType="warning" + data-test-subj="apiKeyWarningCallout" > {i18n.translate('xpack.apm.onboarding.apiKey.warning.calloutMessage', { defaultMessage: @@ -76,6 +78,7 @@ export function ApiKeyCallout({ })} color="danger" iconType="error" + data-test-subj="apiKeyErrorCallout" > {i18n.translate('xpack.apm.onboarding.apiKey.error.calloutMessage', { defaultMessage: 'Error: {errorMessage}', diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/django_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/django_agent.tsx index dfa430c63e195..8bc65ad277e64 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/django_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/django_agent.tsx @@ -15,11 +15,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createDjangoAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; return [ { title: i18n.translate('xpack.apm.onboarding.django.install.title', { @@ -86,5 +94,10 @@ APM services are created programmatically based on the `SERVICE_NAME`.', ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/dotnet_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/dotnet_agent.tsx index 62b5f6651c9b4..e0b4ec9b62e0b 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/dotnet_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/dotnet_agent.tsx @@ -16,11 +16,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createDotNetAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; const codeBlock = `public class Startup { public void Configure(IApplicationBuilder app, IHostingEnvironment env) @@ -147,5 +155,10 @@ export const createDotNetAgentInstructions = ( ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/flask_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/flask_agent.tsx index 9328b8f2a1d70..4e2dcd7898e7f 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/flask_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/flask_agent.tsx @@ -15,11 +15,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createFlaskAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; return [ { title: i18n.translate('xpack.apm.onboarding.flask.install.title', { @@ -86,5 +94,10 @@ APM services are created programmatically based on the `SERVICE_NAME`.', ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/go_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/go_agent.tsx index 8dbeed411a2b8..5c861cda2db87 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/go_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/go_agent.tsx @@ -15,11 +15,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createGoAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; const codeBlock = `\ import ( "net/http" @@ -130,5 +138,10 @@ guide to instrumenting Go source code.', ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/java_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/java_agent.tsx index 7805b0b8e5edb..ff0e5a14e713c 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/java_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/java_agent.tsx @@ -15,11 +15,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createJavaAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; return [ { title: i18n.translate('xpack.apm.onboarding.java.download.title', { @@ -100,5 +108,10 @@ export const createJavaAgentInstructions = ( ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/node_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/node_agent.tsx index c6a1ad120a064..afd035cded3c3 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/node_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/node_agent.tsx @@ -15,11 +15,19 @@ import { INSTRUCTION_VARIANT, AgentInstructions, } from '../instruction_variants'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createNodeAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; return [ { title: i18n.translate('xpack.apm.onboarding.node.install.title', { @@ -89,5 +97,10 @@ export const createNodeAgentInstructions = ( ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/otel_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/otel_agent.tsx index 5beb15acd1a96..bbe73c725ce2a 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/otel_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/otel_agent.tsx @@ -21,11 +21,19 @@ import { ValuesType } from 'utility-types'; import { FormattedMessage } from '@kbn/i18n-react'; import { AgentApiDetails, AgentInstructions } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createOpenTelemetryAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; return [ { title: i18n.translate('xpack.apm.onboarding.otel.download.title', { @@ -96,6 +104,11 @@ export const createOpenTelemetryAgentInstructions = ( ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; @@ -151,7 +164,7 @@ export function OpenTelemetryInstructions({ if (secretToken) { authHeaderValue = `Authorization=Bearer ${secretToken}`; } else { - authHeaderValue = `Authorization=ApiKey ${apiKeyDetails?.encodedKey}`; + authHeaderValue = `Authorization=ApiKey ${apiKeyDetails?.apiKey}`; } const items = [ { diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/php_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/php_agent.tsx index f8137b2835df5..9cd9a8356a4c2 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/php_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/php_agent.tsx @@ -15,11 +15,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createPhpAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; return [ { title: i18n.translate('xpack.apm.onboarding.php.download.title', { @@ -119,5 +127,10 @@ export const createPhpAgentInstructions = ( ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/rack_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/rack_agent.tsx index e637aa16a4287..97e160f81db65 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/rack_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/rack_agent.tsx @@ -15,11 +15,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createRackAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; const codeBlock = `# config.ru require 'sinatra/base' @@ -130,5 +138,10 @@ export const createRackAgentInstructions = ( ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/instructions/rails_agent.tsx b/x-pack/plugins/apm/public/components/app/onboarding/instructions/rails_agent.tsx index 60bd3b161dd56..a5d6f8ba0995d 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/instructions/rails_agent.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/instructions/rails_agent.tsx @@ -15,11 +15,19 @@ import { AgentInstructions, } from '../instruction_variants'; import { ApiKeyCallout } from './api_key_callout'; +import { agentStatusCheckInstruction } from '../agent_status_instructions'; export const createRailsAgentInstructions = ( commonOptions: AgentInstructions ): EuiStepProps[] => { - const { baseUrl, apmServerUrl, apiKeyDetails } = commonOptions; + const { + baseUrl, + apmServerUrl, + apiKeyDetails, + checkAgentStatus, + agentStatus, + agentStatusLoading, + } = commonOptions; return [ { title: i18n.translate('xpack.apm.onboarding.rails.install.title', { @@ -85,5 +93,10 @@ export const createRailsAgentInstructions = ( ), }, + agentStatusCheckInstruction({ + checkAgentStatus, + agentStatus, + agentStatusLoading, + }), ]; }; diff --git a/x-pack/plugins/apm/public/components/app/onboarding/serverless_instructions.tsx b/x-pack/plugins/apm/public/components/app/onboarding/serverless_instructions.ts similarity index 92% rename from x-pack/plugins/apm/public/components/app/onboarding/serverless_instructions.tsx rename to x-pack/plugins/apm/public/components/app/onboarding/serverless_instructions.ts index e414b07e30beb..568ad67bc3fe3 100644 --- a/x-pack/plugins/apm/public/components/app/onboarding/serverless_instructions.tsx +++ b/x-pack/plugins/apm/public/components/app/onboarding/serverless_instructions.ts @@ -29,9 +29,15 @@ export function serverlessInstructions( { baseUrl, config, + checkAgentStatus, + agentStatus, + agentStatusLoading, }: { baseUrl: string; config: ConfigSchema; + checkAgentStatus: () => void; + agentStatus?: boolean; + agentStatusLoading: boolean; }, apiKeyLoading: boolean, apiKeyDetails: AgentApiKey, @@ -43,6 +49,9 @@ export function serverlessInstructions( const commonOptions: AgentInstructions = { baseUrl, apmServerUrl: config.managedServiceUrl, + checkAgentStatus, + agentStatus, + agentStatusLoading, apiKeyDetails: { ...apiKeyDetails, displayApiKeySuccessCallout, diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.test.ts b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.test.ts index 2277808f023d6..1b74d4d897df4 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.test.ts +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.test.ts @@ -198,45 +198,9 @@ describe('orderServiceItems', () => { tiebreakerField: ServiceInventoryFieldName.ServiceName, items: [ { - serviceName: 'd-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: 'a-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: 'b-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: 'c-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: '0-service', + serviceName: '_other', healthStatus: ServiceHealthStatus.unknown, }, - ], - }); - - expect(sortedItems.map((item) => item.serviceName)).toEqual([ - '0-service', - 'a-service', - 'b-service', - 'c-service', - 'd-service', - ]); - }); - }); - - describe('when sorting by alphabetical fields, service overflow bucket always appears 1st', () => { - it('asc', () => { - const sortedItems = orderServiceItems({ - primarySortField: ServiceInventoryFieldName.ServiceName, - sortDirection: 'asc', - tiebreakerField: ServiceInventoryFieldName.ServiceName, - items: [ { serviceName: 'd-service', healthStatus: ServiceHealthStatus.unknown, @@ -257,64 +221,17 @@ describe('orderServiceItems', () => { serviceName: '0-service', healthStatus: ServiceHealthStatus.unknown, }, - { - serviceName: '_other', - healthStatus: ServiceHealthStatus.unknown, - }, ], }); expect(sortedItems.map((item) => item.serviceName)).toEqual([ - '_other', '0-service', + '_other', 'a-service', 'b-service', 'c-service', 'd-service', ]); }); - - it('desc', () => { - const sortedItems = orderServiceItems({ - primarySortField: ServiceInventoryFieldName.ServiceName, - sortDirection: 'desc', - tiebreakerField: ServiceInventoryFieldName.ServiceName, - items: [ - { - serviceName: 'd-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: 'a-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: 'b-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: 'c-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: '0-service', - healthStatus: ServiceHealthStatus.unknown, - }, - { - serviceName: '_other', - healthStatus: ServiceHealthStatus.unknown, - }, - ], - }); - - expect(sortedItems.map((item) => item.serviceName)).toEqual([ - '_other', - 'd-service', - 'c-service', - 'b-service', - 'a-service', - '0-service', - ]); - }); }); }); diff --git a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.ts b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.ts index 5bf62e072031e..89dade9d8d0cd 100644 --- a/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.ts +++ b/x-pack/plugins/apm/public/components/app/service_inventory/service_list/order_service_items.ts @@ -10,7 +10,6 @@ import { ServiceListItem, ServiceInventoryFieldName, } from '../../../../../common/service_inventory'; -import { OTHER_SERVICE_NAME } from '../../../shared/links/apm/service_link/service_max_groups_message'; type SortValueGetter = (item: ServiceListItem) => string | number; @@ -57,11 +56,6 @@ export function orderServiceItems({ // For healthStatus, sort items by healthStatus first, then by tie-breaker const sortFn = sorts[primarySortField as ServiceInventoryFieldName]; - const sortOtherBucketFirst = (item: ServiceListItem) => { - return item.serviceName === OTHER_SERVICE_NAME ? -1 : 0; - }; - - const sortOtherBucketFirstDirection = 'asc'; if (primarySortField === ServiceInventoryFieldName.HealthStatus) { const tiebreakerSortDirection = @@ -73,13 +67,9 @@ export function orderServiceItems({ return orderBy( items, - [sortOtherBucketFirst, sortFn, tiebreakerSortFn], - [sortOtherBucketFirstDirection, sortDirection, tiebreakerSortDirection] + [sortFn, tiebreakerSortFn], + [sortDirection, tiebreakerSortDirection] ); } - return orderBy( - items, - [sortOtherBucketFirst, sortFn], - [sortOtherBucketFirstDirection, sortDirection] - ); + return orderBy(items, [sortFn], [sortDirection]); } diff --git a/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx b/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx index a578dd585cb06..7604bd6781329 100644 --- a/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx +++ b/x-pack/plugins/apm/public/components/app/settings/general_settings/index.tsx @@ -19,6 +19,9 @@ import { apmAWSLambdaRequestCostPerMillion, apmEnableServiceMetrics, apmEnableContinuousRollups, + enableInfrastructureHostsView, + enableAwsLambdaMetrics, + enableAgentExplorerView, } from '@kbn/observability-plugin/common'; import { isEmpty } from 'lodash'; import React from 'react'; @@ -36,6 +39,9 @@ const apmSettingsKeys = [ apmAWSLambdaRequestCostPerMillion, apmEnableServiceMetrics, apmEnableContinuousRollups, + enableInfrastructureHostsView, + enableAwsLambdaMetrics, + enableAgentExplorerView, ]; export function GeneralSettings() { diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index c0c2c83e331ce..6400365aa87a1 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -217,7 +217,6 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { ); const router = useApmRouter(); - const isInfraTabAvailable = useApmFeatureFlag( ApmFeatureFlagName.InfrastructureTabAvailable ); diff --git a/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx b/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx index b214a79b7a1f8..e3604e67ebf5b 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/settings_template.stories.tsx @@ -25,6 +25,13 @@ const coreMock = { }, } as unknown as Partial; +const configMock = { + featureFlags: { + agentConfigurationAvailable: true, + configurableIndicesAvailable: true, + }, +}; + const stories: Meta = { title: 'routing/templates/SettingsTemplate', component: SettingsTemplate, @@ -36,7 +43,12 @@ const stories: Meta = { return ( diff --git a/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx b/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx index 7337be6c3d40e..11b81003f4ef4 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/settings_template.tsx @@ -46,7 +46,7 @@ export function SettingsTemplate({ children, selectedTab }: Props) { const agentConfigurationAvailable = useApmFeatureFlag( ApmFeatureFlagName.AgentConfigurationAvailable ); - const schemaTabAvailable = useApmFeatureFlag( + const migrationToFleetAvailable = useApmFeatureFlag( ApmFeatureFlagName.MigrationToFleetAvailable ); const indicesAvailable = useApmFeatureFlag( @@ -59,7 +59,7 @@ export function SettingsTemplate({ children, selectedTab }: Props) { router, defaultEnvironment, agentConfigurationAvailable, - schemaTabAvailable, + migrationToFleetAvailable, indicesAvailable, }); @@ -84,7 +84,7 @@ function getTabs({ router, defaultEnvironment, agentConfigurationAvailable, - schemaTabAvailable, + migrationToFleetAvailable, indicesAvailable, }: { core: CoreStart; @@ -92,7 +92,7 @@ function getTabs({ router: ApmRouter; defaultEnvironment: Environment; agentConfigurationAvailable: boolean; - schemaTabAvailable: boolean; + migrationToFleetAvailable: boolean; indicesAvailable: boolean; }) { const canReadMlJobs = !!core.application.capabilities.ml?.canGetJobs; @@ -171,7 +171,7 @@ function getTabs({ ] : []), - ...(schemaTabAvailable + ...(migrationToFleetAvailable ? [ { key: 'schema' as const, diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/max_groups_message.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/max_groups_message.tsx new file mode 100644 index 0000000000000..37b5e255c8ab8 --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/links/apm/max_groups_message.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 { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; +import { EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const OTHER_SERVICE_NAME = '_other'; + +export function MaxGroupsMessage() { + return ( + + {i18n.translate('xpack.apm.tooltip.link.apmServerDocs', { + defaultMessage: 'docs', + })} + + ), + }} + /> + ); +} diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx index 6bc15ea00b687..c3474f18d794c 100644 --- a/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/apm/service_link/index.tsx @@ -19,10 +19,7 @@ import { ApmRoutes } from '../../../../routing/apm_route_config'; import { AgentIcon } from '../../../agent_icon'; import { PopoverTooltip } from '../../../popover_tooltip'; import { TruncateWithTooltip } from '../../../truncate_with_tooltip'; -import { - OTHER_SERVICE_NAME, - ServiceMaxGroupsMessage, -} from './service_max_groups_message'; +import { OTHER_SERVICE_NAME, MaxGroupsMessage } from '../max_groups_message'; const StyledLink = euiStyled(EuiLink)`${truncate('100%')};`; @@ -69,7 +66,7 @@ export function ServiceLink({ iconType="warning" > - + diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/service_link/service_max_groups_message.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/service_link/service_max_groups_message.tsx deleted file mode 100644 index ca10becf6c629..0000000000000 --- a/x-pack/plugins/apm/public/components/shared/links/apm/service_link/service_max_groups_message.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FormattedMessage } from '@kbn/i18n-react'; -import React from 'react'; - -export const OTHER_SERVICE_NAME = '_other'; - -export function ServiceMaxGroupsMessage() { - return ( - - ); -} diff --git a/x-pack/plugins/apm/public/components/shared/links/apm/transaction_detail_link/index.tsx b/x-pack/plugins/apm/public/components/shared/links/apm/transaction_detail_link/index.tsx index 55fe30ef05bea..aec2497fdacde 100644 --- a/x-pack/plugins/apm/public/components/shared/links/apm/transaction_detail_link/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/links/apm/transaction_detail_link/index.tsx @@ -7,7 +7,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; import { identity, pickBy } from 'lodash'; import React from 'react'; import { useLocation } from 'react-router-dom'; @@ -20,6 +19,7 @@ import { getComparisonEnabled } from '../../../time_comparison/get_comparison_en import { TruncateWithTooltip } from '../../../truncate_with_tooltip'; import { APMQueryParams } from '../../url_helpers'; import { APMLinkExtendProps, getLegacyApmHref } from '../apm_link'; +import { MaxGroupsMessage } from '../max_groups_message'; export const txGroupsDroppedBucketName = '_other'; @@ -107,10 +107,7 @@ export function TransactionDetailLink({ iconType="warning" > - + diff --git a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx index c0bdc3b193a1c..70206814476b5 100644 --- a/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/transactions_table/index.tsx @@ -33,7 +33,6 @@ import { } from '../../../hooks/use_fetcher'; import { usePreferredDataSourceAndBucketSize } from '../../../hooks/use_preferred_data_source_and_bucket_size'; import { APIReturnType } from '../../../services/rest/create_call_apm_api'; -import { txGroupsDroppedBucketName } from '../links/apm/transaction_detail_link'; import { TransactionOverviewLink } from '../links/apm/transaction_overview_link'; import { fromQuery, toQuery } from '../links/url_helpers'; import { OverviewTableContainer } from '../overview_table_container'; @@ -179,12 +178,8 @@ export function TransactionsTable({ ).then((response) => { const currentPageTransactionGroups = orderBy( response.transactionGroups, - [ - (transactionItem) => - transactionItem.name === txGroupsDroppedBucketName ? -1 : 0, - field, - ], - ['asc', direction] + [field], + [direction] ).slice(index * size, (index + 1) * size); return { diff --git a/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx b/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx index 559e66437cda0..78ad49f465ed4 100644 --- a/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx +++ b/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx @@ -71,6 +71,15 @@ const mockConfig: ConfigSchema = { latestAgentVersionsUrl: '', serverlessOnboarding: false, managedServiceUrl: '', + featureFlags: { + agentConfigurationAvailable: true, + configurableIndicesAvailable: true, + infrastructureTabAvailable: true, + infraUiAvailable: true, + migrationToFleetAvailable: true, + sourcemapApiAvailable: true, + storageExplorerAvailable: true, + }, }; const urlService = new UrlService({ diff --git a/x-pack/plugins/apm/public/hooks/use_apm_feature_flag.ts b/x-pack/plugins/apm/public/hooks/use_apm_feature_flag.ts index e78ec26985cdd..f644aa3ae2eab 100644 --- a/x-pack/plugins/apm/public/hooks/use_apm_feature_flag.ts +++ b/x-pack/plugins/apm/public/hooks/use_apm_feature_flag.ts @@ -5,22 +5,17 @@ * 2.0. */ -import { useMemo } from 'react'; import { ApmFeatureFlagName, - getApmFeatureFlags, ValueOfApmFeatureFlag, } from '../../common/apm_feature_flags'; +import { useApmPluginContext } from '../context/apm_plugin/use_apm_plugin_context'; export function useApmFeatureFlag< TApmFeatureFlagName extends ApmFeatureFlagName >( featureFlag: TApmFeatureFlagName ): ValueOfApmFeatureFlag { - const featureFlags = useMemo(() => { - // this should be replaced with an API call - return getApmFeatureFlags(); - }, []); - - return featureFlags[featureFlag]; + const { config } = useApmPluginContext(); + return config.featureFlags[featureFlag]; } diff --git a/x-pack/plugins/apm/public/index.ts b/x-pack/plugins/apm/public/index.ts index 1dea751371137..b6aa22dab272a 100644 --- a/x-pack/plugins/apm/public/index.ts +++ b/x-pack/plugins/apm/public/index.ts @@ -16,6 +16,15 @@ export interface ConfigSchema { latestAgentVersionsUrl: string; serverlessOnboarding: boolean; managedServiceUrl: string; + featureFlags: { + agentConfigurationAvailable: boolean; + configurableIndicesAvailable: boolean; + infrastructureTabAvailable: boolean; + infraUiAvailable: boolean; + migrationToFleetAvailable: boolean; + sourcemapApiAvailable: boolean; + storageExplorerAvailable: boolean; + }; } export const plugin: PluginInitializer = ( diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index 42327cb1d636e..880a9d5e83a79 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -14,6 +14,15 @@ import { maxSuggestions } from '@kbn/observability-plugin/common'; import { SearchAggregatedTransactionSetting } from '../common/aggregated_transactions'; import { APMPlugin } from './plugin'; +const disabledOnServerless = schema.conditional( + schema.contextRef('serverless'), + true, + schema.boolean({ + defaultValue: false, + }), + schema.oneOf([schema.literal(true)], { defaultValue: true }) +); + // All options should be documented in the APM configuration settings: https://github.com/elastic/kibana/blob/main/docs/settings/apm-settings.asciidoc // and be included on cloud allow list unless there are specific reasons not to const configSchema = schema.object({ @@ -69,6 +78,15 @@ const configSchema = schema.object({ schema.string({ defaultValue: '' }), schema.never() ), + featureFlags: schema.object({ + agentConfigurationAvailable: disabledOnServerless, + configurableIndicesAvailable: disabledOnServerless, + infrastructureTabAvailable: disabledOnServerless, + infraUiAvailable: disabledOnServerless, + migrationToFleetAvailable: disabledOnServerless, + sourcemapApiAvailable: disabledOnServerless, + storageExplorerAvailable: disabledOnServerless, + }), }); // plugin config @@ -129,6 +147,7 @@ export const config: PluginConfigDescriptor = { latestAgentVersionsUrl: true, managedServiceUrl: true, serverlessOnboarding: true, + featureFlags: true, }, schema: configSchema, }; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index f91afd4ece8ed..618c1b388bfab 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -55,7 +55,6 @@ import { migrateLegacyAPMIndicesToSpaceAware } from './saved_objects/migrations/ import { scheduleSourceMapMigration } from './routes/source_maps/schedule_source_map_migration'; import { createApmSourceMapIndexTemplate } from './routes/source_maps/create_apm_source_map_index_template'; import { addApiKeysToEveryPackagePolicyIfMissing } from './routes/fleet/api_keys/add_api_keys_to_policies_if_missing'; -import { getApmFeatureFlags } from '../common/apm_feature_flags'; import { apmTutorialCustomIntegration } from '../common/tutorial/tutorials'; export class APMPlugin @@ -183,7 +182,7 @@ export class APMPlugin }, logger: this.logger, config: currentConfig, - featureFlags: getApmFeatureFlags(), + featureFlags: currentConfig.featureFlags, repository: getGlobalApmServerRouteRepository(), ruleDataClient, plugins: resourcePlugins, diff --git a/x-pack/plugins/apm/server/routes/alerts/route.ts b/x-pack/plugins/apm/server/routes/alerts/route.ts index 13b790155520f..8de52e452ca67 100644 --- a/x-pack/plugins/apm/server/routes/alerts/route.ts +++ b/x-pack/plugins/apm/server/routes/alerts/route.ts @@ -6,15 +6,10 @@ */ import * as t from 'io-ts'; -import { - getTransactionDurationChartPreview, - TransactionDurationChartPreviewResponse, -} from './rule_types/transaction_duration/get_transaction_duration_chart_preview'; +import { Coordinate } from '../../../typings/timeseries'; +import { getTransactionDurationChartPreview } from './rule_types/transaction_duration/get_transaction_duration_chart_preview'; import { getTransactionErrorCountChartPreview } from './rule_types/error_count/get_error_count_chart_preview'; -import { - getTransactionErrorRateChartPreview, - TransactionErrorRateChartPreviewResponse, -} from './rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview'; +import { getTransactionErrorRateChartPreview } from './rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, rangeRt } from '../default_api_types'; import { AggregationType } from '../../../common/rules/apm_rule_types'; @@ -37,8 +32,21 @@ const alertParamsRt = t.intersection([ t.type({ interval: t.string, }), + t.partial({ + groupBy: t.array(t.string), + }), ]); +export interface PreviewChartResponseItem { + name: string; + data: Coordinate[]; +} + +export interface PreviewChartResponse { + series: PreviewChartResponseItem[]; + totalGroups: number; +} + export type AlertParams = t.TypeOf; const transactionErrorRateChartPreview = createApmServerRoute({ @@ -48,7 +56,7 @@ const transactionErrorRateChartPreview = createApmServerRoute({ handler: async ( resources ): Promise<{ - errorRateChartPreview: TransactionErrorRateChartPreviewResponse; + errorRateChartPreview: PreviewChartResponse; }> => { const apmEventClient = await getApmEventClient(resources); const { params, config } = resources; @@ -70,7 +78,9 @@ const transactionErrorCountChartPreview = createApmServerRoute({ options: { tags: ['access:apm'] }, handler: async ( resources - ): Promise<{ errorCountChartPreview: Array<{ x: number; y: number }> }> => { + ): Promise<{ + errorCountChartPreview: PreviewChartResponse; + }> => { const apmEventClient = await getApmEventClient(resources); const { params } = resources; @@ -92,7 +102,7 @@ const transactionDurationChartPreview = createApmServerRoute({ handler: async ( resources ): Promise<{ - latencyChartPreview: TransactionDurationChartPreviewResponse; + latencyChartPreview: PreviewChartResponse; }> => { const apmEventClient = await getApmEventClient(resources); @@ -112,7 +122,6 @@ const transactionDurationChartPreview = createApmServerRoute({ export const alertsChartPreviewRouteRepository = { ...transactionErrorRateChartPreview, - ...transactionDurationChartPreview, ...transactionErrorCountChartPreview, ...transactionDurationChartPreview, }; diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts index 59ae52eab6a5a..cf87eea545a48 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/get_error_count_chart_preview.ts @@ -9,16 +9,19 @@ import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { ERROR_GROUP_ID, + PROCESSOR_EVENT, SERVICE_NAME, } from '../../../../../common/es_fields/apm'; -import { AlertParams } from '../../route'; +import { AlertParams, PreviewChartResponse } from '../../route'; import { environmentQuery } from '../../../../../common/utils/environment_query'; import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; - -export type TransactionErrorCountChartPreviewResponse = Array<{ - x: number; - y: number; -}>; +import { getGroupByTerms } from '../utils/get_groupby_terms'; +import { getAllGroupByFields } from '../../../../../common/rules/get_all_groupby_fields'; +import { ApmRuleType } from '../../../../../common/rules/apm_rule_types'; +import { + BarSeriesDataMap, + getFilteredBarSeries, +} from '../utils/get_filtered_series_for_preview_chart'; export async function getTransactionErrorCountChartPreview({ apmEventClient, @@ -26,17 +29,34 @@ export async function getTransactionErrorCountChartPreview({ }: { apmEventClient: APMEventClient; alertParams: AlertParams; -}): Promise { - const { serviceName, environment, errorGroupingKey, interval, start, end } = - alertParams; +}): Promise { + const { + serviceName, + environment, + errorGroupingKey, + interval, + start, + end, + groupBy: groupByFields, + } = alertParams; + + const allGroupByFields = getAllGroupByFields( + ApmRuleType.ErrorCount, + groupByFields + ); const query = { bool: { filter: [ - ...termQuery(SERVICE_NAME, serviceName), - ...termQuery(ERROR_GROUP_ID, errorGroupingKey), + ...termQuery(SERVICE_NAME, serviceName, { + queryEmptyString: false, + }), + ...termQuery(ERROR_GROUP_ID, errorGroupingKey, { + queryEmptyString: false, + }), ...rangeQuery(start, end), ...environmentQuery(environment), + { term: { [PROCESSOR_EVENT]: ProcessorEvent.error } }, ], }, }; @@ -51,6 +71,15 @@ export async function getTransactionErrorCountChartPreview({ max: end, }, }, + aggs: { + series: { + multi_terms: { + terms: getGroupByTerms(allGroupByFields), + size: 1000, + order: { _count: 'desc' as const }, + }, + }, + }, }, }; @@ -65,13 +94,37 @@ export async function getTransactionErrorCountChartPreview({ ); if (!resp.aggregations) { - return []; + return { series: [], totalGroups: 0 }; } - return resp.aggregations.timeseries.buckets.map((bucket) => { - return { - x: bucket.key, - y: bucket.doc_count, - }; - }); + const seriesDataMap = resp.aggregations.timeseries.buckets.reduce( + (acc, bucket) => { + const x = bucket.key; + bucket.series.buckets.forEach((seriesBucket) => { + const bucketKey = seriesBucket.key.join('_'); + const y = seriesBucket.doc_count; + + if (acc[bucketKey]) { + acc[bucketKey].push({ x, y }); + } else { + acc[bucketKey] = [{ x, y }]; + } + }); + + return acc; + }, + {} as BarSeriesDataMap + ); + + const series = Object.keys(seriesDataMap).map((key) => ({ + name: key, + data: seriesDataMap[key], + })); + + const filteredSeries = getFilteredBarSeries(series); + + return { + series: filteredSeries, + totalGroups: series.length, + }; } diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts index 812769a6a365a..7a18e2ef49aa2 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/error_count/register_error_count_rule_type.ts @@ -50,6 +50,7 @@ import { } from '../get_service_group_fields'; import { getGroupByTerms } from '../utils/get_groupby_terms'; import { getGroupByActionVariables } from '../utils/get_groupby_action_variables'; +import { getAllGroupByFields } from '../../../../../common/rules/get_all_groupby_fields'; const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.ErrorCount]; @@ -96,10 +97,9 @@ export function registerErrorCountRuleType({ spaceId, startedAt, }) => { - const predefinedGroupby = [SERVICE_NAME, SERVICE_ENVIRONMENT]; - - const allGroupbyFields = Array.from( - new Set([...predefinedGroupby, ...(ruleParams.groupBy ?? [])]) + const allGroupByFields = getAllGroupByFields( + ApmRuleType.ErrorCount, + ruleParams.groupBy ); const config = await firstValueFrom(config$); @@ -145,7 +145,7 @@ export function registerErrorCountRuleType({ aggs: { error_counts: { multi_terms: { - terms: getGroupByTerms(allGroupbyFields), + terms: getGroupByTerms(allGroupByFields), size: 1000, order: { _count: 'desc' as const }, }, @@ -164,7 +164,7 @@ export function registerErrorCountRuleType({ response.aggregations?.error_counts.buckets.map((bucket) => { const groupByFields = bucket.key.reduce( (obj, bucketKey, bucketIndex) => { - obj[allGroupbyFields[bucketIndex]] = bucketKey; + obj[allGroupByFields[bucketIndex]] = bucketKey; return obj; }, {} as Record diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts index f7b226216aef0..2aefb0598fcb9 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/get_transaction_duration_chart_preview.ts @@ -7,15 +7,17 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; -import { AggregationType } from '../../../../../common/rules/apm_rule_types'; +import { + AggregationType, + ApmRuleType, +} from '../../../../../common/rules/apm_rule_types'; import { SERVICE_NAME, - SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME, } from '../../../../../common/es_fields/apm'; import { environmentQuery } from '../../../../../common/utils/environment_query'; -import { AlertParams } from '../../route'; +import { AlertParams, PreviewChartResponse } from '../../route'; import { getSearchTransactionsEvents, getDocumentTypeFilterForTransactions, @@ -23,17 +25,17 @@ import { getProcessorEventForTransactions, } from '../../../../lib/helpers/transactions'; import { - ENVIRONMENT_NOT_DEFINED, - getEnvironmentLabel, -} from '../../../../../common/environment_filter_values'; -import { averageOrPercentileAgg } from './average_or_percentile_agg'; + averageOrPercentileAgg, + getMultiTermsSortOrder, +} from './average_or_percentile_agg'; import { APMConfig } from '../../../..'; import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; - -export type TransactionDurationChartPreviewResponse = Array<{ - name: string; - data: Array<{ x: number; y: number | null }>; -}>; +import { getGroupByTerms } from '../utils/get_groupby_terms'; +import { getAllGroupByFields } from '../../../../../common/rules/get_all_groupby_fields'; +import { + BarSeriesDataMap, + getFilteredBarSeries, +} from '../utils/get_filtered_series_for_preview_chart'; export async function getTransactionDurationChartPreview({ alertParams, @@ -43,7 +45,7 @@ export async function getTransactionDurationChartPreview({ alertParams: AlertParams; config: APMConfig; apmEventClient: APMEventClient; -}): Promise { +}): Promise { const { aggregationType = AggregationType.Avg, environment, @@ -53,6 +55,7 @@ export async function getTransactionDurationChartPreview({ interval, start, end, + groupBy: groupByFields, } = alertParams; const searchAggregatedTransactions = await getSearchTransactionsEvents({ config, @@ -63,9 +66,15 @@ export async function getTransactionDurationChartPreview({ const query = { bool: { filter: [ - ...termQuery(SERVICE_NAME, serviceName), - ...termQuery(TRANSACTION_TYPE, transactionType), - ...termQuery(TRANSACTION_NAME, transactionName), + ...termQuery(SERVICE_NAME, serviceName, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_TYPE, transactionType, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_NAME, transactionName, { + queryEmptyString: false, + }), ...rangeQuery(start, end), ...environmentQuery(environment), ...getDocumentTypeFilterForTransactions(searchAggregatedTransactions), @@ -77,6 +86,11 @@ export async function getTransactionDurationChartPreview({ searchAggregatedTransactions ); + const allGroupByFields = getAllGroupByFields( + ApmRuleType.TransactionDuration, + groupByFields + ); + const aggs = { timeseries: { date_histogram: { @@ -89,23 +103,18 @@ export async function getTransactionDurationChartPreview({ }, }, aggs: { - environment: { - terms: { - field: SERVICE_ENVIRONMENT, - missing: ENVIRONMENT_NOT_DEFINED.value, - size: 10, - order: { - [aggregationType === AggregationType.Avg - ? 'avgLatency' - : `pctLatency.${ - aggregationType === AggregationType.P95 ? 95 : 99 - }`]: 'desc', - } as Record, + series: { + multi_terms: { + terms: [...getGroupByTerms(allGroupByFields)], + size: 1000, + ...getMultiTermsSortOrder(aggregationType), + }, + aggs: { + ...averageOrPercentileAgg({ + aggregationType, + transactionDurationField, + }), }, - aggs: averageOrPercentileAgg({ - aggregationType, - transactionDurationField, - }), }, }, }, @@ -122,32 +131,39 @@ export async function getTransactionDurationChartPreview({ ); if (!resp.aggregations) { - return []; + return { series: [], totalGroups: 0 }; } - const environmentDataMap = resp.aggregations.timeseries.buckets.reduce( + const seriesDataMap = resp.aggregations.timeseries.buckets.reduce( (acc, bucket) => { const x = bucket.key; - bucket.environment.buckets.forEach((environmentBucket) => { - const env = environmentBucket.key as string; + bucket.series.buckets.forEach((seriesBucket) => { + const bucketKey = seriesBucket.key.join('_'); const y = - 'avgLatency' in environmentBucket - ? environmentBucket.avgLatency.value - : environmentBucket.pctLatency.values[0].value; - if (acc[env]) { - acc[env].push({ x, y }); + 'avgLatency' in seriesBucket + ? seriesBucket.avgLatency.value + : seriesBucket.pctLatency.values[0].value; + if (acc[bucketKey]) { + acc[bucketKey].push({ x, y }); } else { - acc[env] = [{ x, y }]; + acc[bucketKey] = [{ x, y }]; } }); return acc; }, - {} as Record> + {} as BarSeriesDataMap ); - return Object.keys(environmentDataMap).map((env) => ({ - name: getEnvironmentLabel(env), - data: environmentDataMap[env], + const series = Object.keys(seriesDataMap).map((key) => ({ + name: key, + data: seriesDataMap[key], })); + + const filteredSeries = getFilteredBarSeries(series); + + return { + series: filteredSeries, + totalGroups: series.length, + }; } diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts index 39b3dabd21d76..4f07f7f1fbf72 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_duration/register_transaction_duration_rule_type.ts @@ -64,6 +64,7 @@ import { getMultiTermsSortOrder, } from './average_or_percentile_agg'; import { getGroupByActionVariables } from '../utils/get_groupby_action_variables'; +import { getAllGroupByFields } from '../../../../../common/rules/get_all_groupby_fields'; const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.TransactionDuration]; @@ -103,14 +104,9 @@ export function registerTransactionDurationRuleType({ minimumLicenseRequired: 'basic', isExportable: true, executor: async ({ params: ruleParams, services, spaceId }) => { - const predefinedGroupby = [ - SERVICE_NAME, - SERVICE_ENVIRONMENT, - TRANSACTION_TYPE, - ]; - - const allGroupbyFields = Array.from( - new Set([...predefinedGroupby, ...(ruleParams.groupBy ?? [])]) + const allGroupByFields = getAllGroupByFields( + ApmRuleType.TransactionDuration, + ruleParams.groupBy ); const config = await firstValueFrom(config$); @@ -172,7 +168,7 @@ export function registerTransactionDurationRuleType({ aggs: { series: { multi_terms: { - terms: [...getGroupByTerms(allGroupbyFields)], + terms: [...getGroupByTerms(allGroupByFields)], size: 1000, ...getMultiTermsSortOrder(ruleParams.aggregationType), }, @@ -205,7 +201,7 @@ export function registerTransactionDurationRuleType({ for (const bucket of response.aggregations.series.buckets) { const groupByFields = bucket.key.reduce( (obj, bucketKey, bucketIndex) => { - obj[allGroupbyFields[bucketIndex]] = bucketKey; + obj[allGroupByFields[bucketIndex]] = bucketKey; return obj; }, {} as Record diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts index 3996ad5994710..f451fe7b188d6 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/get_transaction_error_rate_chart_preview.ts @@ -6,30 +6,29 @@ */ import { rangeQuery, termQuery } from '@kbn/observability-plugin/server'; +import { ApmRuleType } from '../../../../../common/rules/apm_rule_types'; import { SERVICE_NAME, TRANSACTION_TYPE, TRANSACTION_NAME, + EVENT_OUTCOME, } from '../../../../../common/es_fields/apm'; import { environmentQuery } from '../../../../../common/utils/environment_query'; -import { AlertParams } from '../../route'; +import { AlertParams, PreviewChartResponse } from '../../route'; import { getSearchTransactionsEvents, getDocumentTypeFilterForTransactions, getProcessorEventForTransactions, } from '../../../../lib/helpers/transactions'; -import { - calculateFailedTransactionRate, - getOutcomeAggregation, -} from '../../../../lib/helpers/transaction_error_rate'; import { APMConfig } from '../../../..'; import { APMEventClient } from '../../../../lib/helpers/create_es_client/create_apm_event_client'; -import { ApmDocumentType } from '../../../../../common/document_type'; - -export type TransactionErrorRateChartPreviewResponse = Array<{ - x: number; - y: number; -}>; +import { EventOutcome } from '../../../../../common/event_outcome'; +import { getGroupByTerms } from '../utils/get_groupby_terms'; +import { getAllGroupByFields } from '../../../../../common/rules/get_all_groupby_fields'; +import { + BarSeriesDataMap, + getFilteredBarSeries, +} from '../utils/get_filtered_series_for_preview_chart'; export async function getTransactionErrorRateChartPreview({ config, @@ -39,7 +38,7 @@ export async function getTransactionErrorRateChartPreview({ config: APMConfig; apmEventClient: APMEventClient; alertParams: AlertParams; -}): Promise { +}): Promise { const { serviceName, environment, @@ -48,16 +47,20 @@ export async function getTransactionErrorRateChartPreview({ start, end, transactionName, + groupBy: groupByFields, } = alertParams; const searchAggregatedTransactions = await getSearchTransactionsEvents({ config, apmEventClient, kuery: '', - start, - end, }); + const allGroupByFields = getAllGroupByFields( + ApmRuleType.TransactionErrorRate, + groupByFields + ); + const params = { apm: { events: [getProcessorEventForTransactions(searchAggregatedTransactions)], @@ -68,14 +71,25 @@ export async function getTransactionErrorRateChartPreview({ query: { bool: { filter: [ - ...termQuery(SERVICE_NAME, serviceName), - ...termQuery(TRANSACTION_TYPE, transactionType), - ...termQuery(TRANSACTION_NAME, transactionName), + ...termQuery(SERVICE_NAME, serviceName, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_TYPE, transactionType, { + queryEmptyString: false, + }), + ...termQuery(TRANSACTION_NAME, transactionName, { + queryEmptyString: false, + }), ...rangeQuery(start, end), ...environmentQuery(environment), ...getDocumentTypeFilterForTransactions( searchAggregatedTransactions ), + { + terms: { + [EVENT_OUTCOME]: [EventOutcome.failure, EventOutcome.success], + }, + }, ], }, }, @@ -89,11 +103,22 @@ export async function getTransactionErrorRateChartPreview({ max: end, }, }, - aggs: getOutcomeAggregation( - searchAggregatedTransactions - ? ApmDocumentType.TransactionMetric - : ApmDocumentType.TransactionEvent - ), + aggs: { + series: { + multi_terms: { + terms: [...getGroupByTerms(allGroupByFields)], + size: 1000, + order: { _count: 'desc' as const }, + }, + aggs: { + outcomes: { + terms: { + field: EVENT_OUTCOME, + }, + }, + }, + }, + }, }, }, }, @@ -105,13 +130,54 @@ export async function getTransactionErrorRateChartPreview({ ); if (!resp.aggregations) { - return []; + return { series: [], totalGroups: 0 }; } - return resp.aggregations.timeseries.buckets.map((bucket) => { - return { - x: bucket.key, - y: calculateFailedTransactionRate(bucket), - }; - }); + const seriesDataMap = resp.aggregations.timeseries.buckets.reduce( + (acc, bucket) => { + const x = bucket.key; + bucket.series.buckets.forEach((seriesBucket) => { + const bucketKey = seriesBucket.key.join('_'); + const y = calculateErrorRate(seriesBucket.outcomes.buckets); + + if (acc[bucketKey]) { + acc[bucketKey].push({ x, y }); + } else { + acc[bucketKey] = [{ x, y }]; + } + }); + + return acc; + }, + {} as BarSeriesDataMap + ); + + const series = Object.keys(seriesDataMap).map((key) => ({ + name: key, + data: seriesDataMap[key], + })); + + const filteredSeries = getFilteredBarSeries(series); + + return { + series: filteredSeries, + totalGroups: series.length, + }; } + +const calculateErrorRate = ( + buckets: Array<{ + doc_count: number; + key: string | number; + }> +) => { + const failed = + buckets.find((outcomeBucket) => outcomeBucket.key === EventOutcome.failure) + ?.doc_count ?? 0; + + const succesful = + buckets.find((outcomeBucket) => outcomeBucket.key === EventOutcome.success) + ?.doc_count ?? 0; + + return (failed / (failed + succesful)) * 100; +}; diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts index 3b3bcb6095c8a..4aef808b33f3a 100644 --- a/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/transaction_error_rate/register_transaction_error_rate_rule_type.ts @@ -59,6 +59,7 @@ import { } from '../get_service_group_fields'; import { getGroupByTerms } from '../utils/get_groupby_terms'; import { getGroupByActionVariables } from '../utils/get_groupby_action_variables'; +import { getAllGroupByFields } from '../../../../../common/rules/get_all_groupby_fields'; const ruleTypeConfig = RULE_TYPES_CONFIG[ApmRuleType.TransactionErrorRate]; @@ -106,14 +107,9 @@ export function registerTransactionErrorRateRuleType({ params: ruleParams, startedAt, }) => { - const predefinedGroupby = [ - SERVICE_NAME, - SERVICE_ENVIRONMENT, - TRANSACTION_TYPE, - ]; - - const allGroupbyFields = Array.from( - new Set([...predefinedGroupby, ...(ruleParams.groupBy ?? [])]) + const allGroupByFields = getAllGroupByFields( + ApmRuleType.TransactionErrorRate, + ruleParams.groupBy ); const config = await firstValueFrom(config$); @@ -183,7 +179,7 @@ export function registerTransactionErrorRateRuleType({ aggs: { series: { multi_terms: { - terms: [...getGroupByTerms(allGroupbyFields)], + terms: [...getGroupByTerms(allGroupByFields)], size: 1000, order: { _count: 'desc' as const }, }, @@ -214,7 +210,7 @@ export function registerTransactionErrorRateRuleType({ for (const bucket of response.aggregations.series.buckets) { const groupByFields = bucket.key.reduce( (obj, bucketKey, bucketIndex) => { - obj[allGroupbyFields[bucketIndex]] = bucketKey; + obj[allGroupByFields[bucketIndex]] = bucketKey; return obj; }, {} as Record diff --git a/x-pack/plugins/apm/server/routes/alerts/rule_types/utils/get_filtered_series_for_preview_chart.ts b/x-pack/plugins/apm/server/routes/alerts/rule_types/utils/get_filtered_series_for_preview_chart.ts new file mode 100644 index 0000000000000..243935adad9fd --- /dev/null +++ b/x-pack/plugins/apm/server/routes/alerts/rule_types/utils/get_filtered_series_for_preview_chart.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 { Coordinate } from '../../../../../typings/timeseries'; + +export type BarSeriesDataMap = Record; +type BarSeriesData = Array<{ name: string; data: Coordinate[] }>; + +const NUM_SERIES = 5; + +export const getFilteredBarSeries = (barSeries: BarSeriesData) => { + const sortedSeries = barSeries.sort((a, b) => { + const aMax = Math.max(...a.data.map((point) => point.y as number)); + const bMax = Math.max(...b.data.map((point) => point.y as number)); + return bMax - aMax; + }); + + return sortedSeries.slice(0, NUM_SERIES); +}; diff --git a/x-pack/plugins/cases/server/client/utils.test.ts b/x-pack/plugins/cases/server/client/utils.test.ts index 2b63f9c732105..50dbdb8981c9f 100644 --- a/x-pack/plugins/cases/server/client/utils.test.ts +++ b/x-pack/plugins/cases/server/client/utils.test.ts @@ -15,7 +15,7 @@ import { CaseSeverity } from '../../common/api'; import { createSavedObjectsSerializerMock } from './mocks'; import { arraysDifference, - buildNestedFilter, + buildFilter, buildRangeFilter, constructQueryOptions, constructSearch, @@ -24,6 +24,106 @@ import { import { CasePersistedSeverity, CasePersistedStatus } from '../common/types/case'; describe('utils', () => { + describe('buildFilter', () => { + it('returns undefined if filters is undefined', () => { + expect(buildFilter({ filters: undefined, field: 'abc', operator: 'or' })).toBeUndefined(); + }); + + it('returns undefined if filters is is an empty array', () => { + expect(buildFilter({ filters: [], field: 'abc', operator: 'or' })).toBeUndefined(); + }); + + it('returns a KueryNode using or operator', () => { + expect(buildFilter({ filters: ['value1'], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value1", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + + it("returns multiple nodes or'd together", () => { + expect(buildFilter({ filters: ['value1', 'value2'], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value1", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value2", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + + it('does not escape special kql characters in the filter values', () => { + const specialCharacters = 'awesome:()\\<>"*'; + + expect(buildFilter({ filters: [specialCharacters], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "awesome:()\\\\<>\\"*", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + }); + describe('convertSortField', () => { it('transforms status correctly', () => { expect(convertSortField('status')).toBe('status'); @@ -589,163 +689,6 @@ describe('utils', () => { }); }); - describe('buildNestedFilter', () => { - it('returns undefined if filters is undefined', () => { - expect(buildNestedFilter({ field: '', nestedField: '', operator: 'or' })).toBeUndefined(); - }); - - it('returns undefined when the filters array is empty', () => { - expect( - buildNestedFilter({ filters: [], field: '', nestedField: '', operator: 'or' }) - ).toBeUndefined(); - }); - - it('returns a KueryNode for a single filter', () => { - expect( - toElasticsearchQuery( - buildNestedFilter({ - filters: ['hello'], - field: 'uid', - nestedField: 'nestedField', - operator: 'or', - })! - ) - ).toMatchInlineSnapshot(` - Object { - "nested": Object { - "path": "cases.attributes.nestedField", - "query": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "cases.attributes.nestedField.uid": "hello", - }, - }, - ], - }, - }, - "score_mode": "none", - }, - } - `); - }); - - it("returns a KueryNode for multiple filters or'd together", () => { - expect( - toElasticsearchQuery( - buildNestedFilter({ - filters: ['uid1', 'uid2'], - field: 'uid', - nestedField: 'nestedField', - operator: 'or', - })! - ) - ).toMatchInlineSnapshot(` - Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "nested": Object { - "path": "cases.attributes.nestedField", - "query": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "cases.attributes.nestedField.uid": "uid1", - }, - }, - ], - }, - }, - "score_mode": "none", - }, - }, - Object { - "nested": Object { - "path": "cases.attributes.nestedField", - "query": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "cases.attributes.nestedField.uid": "uid2", - }, - }, - ], - }, - }, - "score_mode": "none", - }, - }, - ], - }, - } - `); - }); - - it("returns a KueryNode for multiple filters and'ed together", () => { - expect( - toElasticsearchQuery( - buildNestedFilter({ - filters: ['uid1', 'uid2'], - field: 'uid', - nestedField: 'nestedField', - operator: 'and', - })! - ) - ).toMatchInlineSnapshot(` - Object { - "bool": Object { - "filter": Array [ - Object { - "nested": Object { - "path": "cases.attributes.nestedField", - "query": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "cases.attributes.nestedField.uid": "uid1", - }, - }, - ], - }, - }, - "score_mode": "none", - }, - }, - Object { - "nested": Object { - "path": "cases.attributes.nestedField", - "query": Object { - "bool": Object { - "minimum_should_match": 1, - "should": Array [ - Object { - "match": Object { - "cases.attributes.nestedField.uid": "uid2", - }, - }, - ], - }, - }, - "score_mode": "none", - }, - }, - ], - }, - } - `); - }); - }); - describe('arraysDifference', () => { it('returns null if originalValue is null', () => { expect(arraysDifference(null, [])).toBeNull(); diff --git a/x-pack/plugins/cases/server/client/utils.ts b/x-pack/plugins/cases/server/client/utils.ts index 0f198a6c8ba75..b630d940ac6b8 100644 --- a/x-pack/plugins/cases/server/client/utils.ts +++ b/x-pack/plugins/cases/server/client/utils.ts @@ -197,10 +197,6 @@ interface FilterField { type?: string; } -interface NestedFilterField extends FilterField { - nestedField: string; -} - export const buildFilter = ({ filters, field, @@ -218,48 +214,7 @@ export const buildFilter = ({ } return nodeBuilder[operator]( - filtersAsArray.map((filter) => - nodeBuilder.is(`${escapeKuery(type)}.attributes.${escapeKuery(field)}`, escapeKuery(filter)) - ) - ); -}; - -/** - * Creates a KueryNode filter for the Saved Object find API's filter field. This handles constructing a filter for - * a nested field. - * - * @param filters is a string or array of strings that defines the values to search for - * @param field is the location to search for - * @param nestedField is the field in the saved object that has a type of 'nested' - * @param operator whether to 'or'/'and' the created filters together - * @type the type of saved object being searched - * @returns a constructed KueryNode representing the filter or undefined if one could not be built - */ -export const buildNestedFilter = ({ - filters, - field, - nestedField, - operator, - type = CASE_SAVED_OBJECT, -}: NestedFilterField): KueryNode | undefined => { - if (filters === undefined) { - return; - } - - const filtersAsArray = Array.isArray(filters) ? filters : [filters]; - - if (filtersAsArray.length === 0) { - return; - } - - return nodeBuilder[operator]( - filtersAsArray.map((filter) => - fromKueryExpression( - `${escapeKuery(type)}.attributes.${escapeKuery(nestedField)}:{ ${escapeKuery( - field - )}: ${escapeKuery(filter)} }` - ) - ) + filtersAsArray.map((filter) => nodeBuilder.is(`${type}.attributes.${field}`, filter)) ); }; @@ -365,7 +320,7 @@ export const buildAssigneesFilter = ({ ); const assigneesFilter = assigneesWithoutNone.map((filter) => - nodeBuilder.is(`${CASE_SAVED_OBJECT}.attributes.assignees.uid`, escapeKuery(filter)) + nodeBuilder.is(`${CASE_SAVED_OBJECT}.attributes.assignees.uid`, filter) ); if (!hasNoneAssignee) { diff --git a/x-pack/plugins/cloud_integrations/cloud_chat/public/components/chat/chat.tsx b/x-pack/plugins/cloud_integrations/cloud_chat/public/components/chat/chat.tsx index f58c5d0834ae2..1a11542699ed3 100644 --- a/x-pack/plugins/cloud_integrations/cloud_chat/public/components/chat/chat.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_chat/public/components/chat/chat.tsx @@ -37,10 +37,10 @@ export const Chat = ({ onHide = () => {}, onReady, onResize }: Props) => { } const { isReady, isResized, style } = config; - const { bottom, height, right } = style; + const { right } = style; const buttonCSS = css` - bottom: calc(${bottom} + ${height}); + bottom: ${euiThemeVars.euiSizeXS}; position: fixed; right: calc(${right} + ${euiThemeVars.euiSizeXS}); visibility: ${isReady && isResized ? 'visible' : 'hidden'}; diff --git a/x-pack/plugins/cloud_security_posture/common/types.ts b/x-pack/plugins/cloud_security_posture/common/types.ts index 69a6ed48f3b2f..c0e6286b594c0 100644 --- a/x-pack/plugins/cloud_security_posture/common/types.ts +++ b/x-pack/plugins/cloud_security_posture/common/types.ts @@ -131,6 +131,15 @@ export interface GetCspRuleTemplateResponse { // CNVM DASHBOARD +export interface VulnScoreTrend { + '@timestamp': string; + policy_template: 'vuln_mgmt'; + critical: number; + high: number; + medium: number; + low: number; +} + export interface CnvmStatistics { criticalCount: number | undefined; highCount: number | undefined; @@ -141,6 +150,7 @@ export interface CnvmStatistics { export interface CnvmDashboardData { cnvmStatistics: CnvmStatistics; + vulnTrends: VulnScoreTrend[]; topVulnerableResources: VulnerableResourceStat[]; topPatchableVulnerabilities: PatchableVulnerabilityStat[]; topVulnerabilities: VulnerabilityStat[]; diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_filtered_data_view.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_filtered_data_view.ts index c2104478edb87..cabc449b1e3bd 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_filtered_data_view.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_filtered_data_view.ts @@ -34,10 +34,18 @@ export const useFilteredDataView = (indexPattern: string) => { throw new Error('Error fetching fields for the index pattern'); } + // Filter out fields that are not present in the index pattern passed as a parameter dataView.fields = dataView.fields.filter((field) => indexPatternFields.some((indexPatternField) => indexPatternField.name === field.name) ) as DataView['fields']; + // Insert fields that are present in the index pattern but not in the data view + indexPatternFields.forEach((indexPatternField) => { + if (!dataView.fields.some((field) => field.name === indexPatternField.name)) { + dataView.fields.push(indexPatternField as DataView['fields'][0]); + } + }); + return dataView; }; diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_vulnerabilities_stats_api.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_vulnerability_dashboard_api.ts similarity index 88% rename from x-pack/plugins/cloud_security_posture/public/common/api/use_vulnerabilities_stats_api.ts rename to x-pack/plugins/cloud_security_posture/public/common/api/use_vulnerability_dashboard_api.ts index 5d933921068c5..11113949d0972 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_vulnerabilities_stats_api.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_vulnerability_dashboard_api.ts @@ -10,9 +10,9 @@ import { CnvmDashboardData } from '../../../common/types'; import { useKibana } from '../hooks/use_kibana'; import { VULNERABILITIES_DASHBOARD_ROUTE_PATH } from '../../../common/constants'; -const cnvmKey = 'use-cnvm-statistics-api-key'; +const cnvmKey = 'use-vulnerability-dashboard-api-key'; -export const useCnvmStatisticsApi = ( +export const useVulnerabilityDashboardApi = ( options?: UseQueryOptions ) => { const { http } = useKibana().services; diff --git a/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx b/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx index c7772063b2f90..e0ec83af0d3ba 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/chart_panel.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import { EuiPanel, EuiText, @@ -22,6 +22,7 @@ interface ChartPanelProps { hasBorder?: boolean; isLoading?: boolean; isError?: boolean; + rightSideItems?: ReactNode[]; } const Loading = () => ( @@ -52,6 +53,7 @@ export const ChartPanel: React.FC = ({ isLoading, isError, children, + rightSideItems, }) => { const { euiTheme } = useEuiTheme(); const renderChart = () => { @@ -64,13 +66,18 @@ export const ChartPanel: React.FC = ({ - {title && ( - -

    {title}

    -
    - )} + + + {title && ( + +

    {title}

    +
    + )} +
    + {rightSideItems} +
    - {renderChart()} + {renderChart()}
    ); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index d098023b2dc57..d4610156afa8d 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -257,6 +257,7 @@ const useEnsureDefaultNamespace = ({ updatePolicy(policy); }, [newPolicy, input, updatePolicy]); }; + const usePolicyTemplateInitialName = ({ isEditPage, isLoading, @@ -286,11 +287,14 @@ const usePolicyTemplateInitialName = ({ if (newPolicy.name === currentIntegrationName) { return; } + updatePolicy({ ...newPolicy, name: currentIntegrationName, }); - }, [isLoading, integration, isEditPage, packagePolicyList, newPolicy, updatePolicy]); + // since this useEffect should only run on initial mount updatePolicy and newPolicy shouldn't re-trigger it + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isLoading, integration, isEditPage, packagePolicyList]); }; const getSelectedOption = ( diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 053abaa0f4b34..32bec0489c9fa 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -187,7 +187,7 @@ export const getMaxPackageName = ( packageName: string, packagePolicies?: Array<{ name: string }> ) => { - // Retrieve highest number appended to package policy name and increment it by one + // Retrieve the highest number appended to package policy name and increment it by one const pkgPoliciesNamePattern = new RegExp(`${packageName}-(\\d+)`); const maxPkgPolicyName = Math.max( diff --git a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts index 38985d1d99222..638076818d3f0 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts @@ -31,3 +31,5 @@ export const NO_VULNERABILITIES_STATUS_TEST_SUBJ = { }; export const VULNERABILITIES_CONTAINER_TEST_SUBJ = 'vulnerabilities_container'; + +export const VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ = 'vuknerabilities_cvss_score_badge'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx b/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx index 3f2e729446b12..b94efbd2de1a0 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/vulnerability_badges.tsx @@ -11,6 +11,7 @@ import { css } from '@emotion/react'; import { float } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { getCvsScoreColor, getSeverityStatusColor } from '../common/utils/get_vulnerability_colors'; import { VulnSeverity } from '../../common/types'; +import { VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ } from './test_subjects'; interface CVSScoreBadgeProps { score: float; @@ -32,9 +33,9 @@ export const CVSScoreBadge = ({ score, version }: CVSScoreBadgeProps) => { .euiBadge__text { display: flex; } - display: flex; width: 62px; `} + data-test-subj={VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ} > {versionDisplay && ( <> diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx index 978a4ed2d9710..1ea6a460a41fc 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings_by_resource/resource_findings/resource_findings_container.tsx @@ -5,17 +5,12 @@ * 2.0. */ import React, { useCallback } from 'react'; -import { - EuiSpacer, - EuiButtonEmpty, - type EuiDescriptionListProps, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; +import { EuiSpacer, EuiButtonEmpty, type EuiDescriptionListProps } from '@elastic/eui'; import { Link, useParams } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; import { generatePath } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; import { CspInlineDescriptionList } from '../../../../components/csp_inline_description_list'; import type { Evaluation } from '../../../../../common/types'; import { CspFinding } from '../../../../../common/schemas/csp_finding'; @@ -50,7 +45,14 @@ const getDefaultQuery = ({ const BackToResourcesButton = () => ( - + { }} loading={resourceFindings.isFetching} /> - - - - - - } + + + + - - - - - - + } + /> + {resourceFindings.data && ( ( ); -export const PageTitleText = ({ title }: { title: React.ReactNode }) =>

    {title}

    ; +export const PageTitleText = ({ title }: { title: React.ReactNode }) => ( + +

    {title}

    +
    +); export const getExpandColumn = ({ onClick, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx b/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx index b268914134d67..4d9283da03d74 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/findings/findings.tsx @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; -import { Redirect, Switch, useHistory, useLocation } from 'react-router-dom'; +import { Redirect, Switch, useHistory, useLocation, matchPath } from 'react-router-dom'; import { Route } from '@kbn/shared-ux-router'; import { Configurations } from '../configurations'; import { cloudPosturePages, findingsNavigation } from '../../common/navigation/constants'; @@ -33,63 +33,76 @@ export const Findings = () => { history.push({ pathname: findingsNavigation.findings_default.path }); }; + const isResourcesVulnerabilitiesPage = matchPath(location.pathname, { + path: findingsNavigation.resource_vulnerabilities.path, + })?.isExact; + + const isResourcesFindingsPage = matchPath(location.pathname, { + path: findingsNavigation.resource_findings.path, + })?.isExact; + + const showHeader = !isResourcesVulnerabilitiesPage && !isResourcesFindingsPage; + const isVulnerabilitiesTabSelected = (pathname: string) => { return ( pathname === findingsNavigation.vulnerabilities.path || - pathname === findingsNavigation.vulnerabilities_by_resource.path || - pathname === findingsNavigation.resource_vulnerabilities.path + pathname === findingsNavigation.vulnerabilities_by_resource.path ); }; return ( <> - -

    - -

    -
    - - - - - - - - - + +

    + +

    +
    + + + + + + + + + } + tooltipPosition="bottom" /> - } - tooltipPosition="bottom" + + + + + -
    -
    -
    - - - -
    + + + + )} ; type LatestFindingsResponse = IKibanaSearchResponse>; @@ -59,7 +60,7 @@ export const useLatestVulnerabilities = (options: VulnerabilitiesQuery) => { ); return { - page: hits.hits.map((hit) => hit._source!), + page: hits.hits.map((hit) => hit._source!) as VulnerabilityRecord[], total: number.is(hits.total) ? hits.total : 0, }; }, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_by_resource.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_by_resource.ts index 42b7cc76c55a9..706f980408d18 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_by_resource.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities_by_resource.ts @@ -118,13 +118,17 @@ export const getQuery = ({ }); const getFirstKey = ( buckets: AggregationsMultiBucketAggregateBase['buckets'] -): undefined | string => { - if (!!Array.isArray(buckets) && !!buckets.length) return buckets[0].key; +) => { + return !!Array.isArray(buckets) && !!buckets.length ? (buckets[0].key as string) : ''; }; const createVulnerabilitiesByResource = (resource: FindingsAggBucket) => ({ - 'resource.id': resource.key, - 'resource.name': getFirstKey(resource.name.buckets), - 'cloud.region': getFirstKey(resource.region.buckets), + resource: { + id: resource.key, + name: getFirstKey(resource.name.buckets), + }, + cloud: { + region: getFirstKey(resource.region.buckets), + }, vulnerabilities_count: resource.doc_count, severity_map: { critical: resource.critical.doc_count, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.ts index ff0bfce6c8cf3..fea25c64d0978 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.ts @@ -39,6 +39,10 @@ export const useStyles = () => { & .euiDataGridRowCell__expandActions > [data-test-subj='euiDataGridCellExpandButton'] { display: none; } + & .euiDataGridRowCell__contentByHeight + .euiDataGridRowCell__expandActions { + padding: 0; + } + & .euiDataGridRowCell__expandFlex { align-items: center; } diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/types.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/types.ts index def4c543b5fcd..7ff7861954a61 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/types.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/types.ts @@ -52,22 +52,22 @@ export interface VulnerabilityRecord { version: string; }; cloud: { - image: { + image?: { id: string; }; - provider: string; - instance: { + provider?: string; + instance?: { id: string; }; - machine: { + machine?: { type: string; }; region: string; - availability_zone: string; - service: { + availability_zone?: string; + service?: { name: string; }; - account: { + account?: { id: string; }; }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.tsx new file mode 100644 index 0000000000000..edafbd1f763f6 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/get_vulnerabilities_grid_cell_actions.tsx @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiDataGridColumn, EuiDataGridColumnCellAction, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { VulnerabilityRecord } from '../types'; +import { getFilters } from './get_filters'; +import { FILTER_IN, FILTER_OUT } from '../translations'; + +export const getVulnerabilitiesGridCellActions = >>({ + data, + columns, + columnGridFn, + pageSize, + setUrlQuery, + filters, + dataView, +}: { + data: T; + columns: Record; + columnGridFn: (cellActions: EuiDataGridColumnCellAction[]) => EuiDataGridColumn[]; + pageSize: number; + setUrlQuery: (query: any) => void; + filters: any; + dataView: any; +}) => { + const getColumnIdValue = (rowIndex: number, columnId: string) => { + const vulnerabilityRow = data[rowIndex]; + if (!vulnerabilityRow) return null; + + if (columnId === columns.vulnerability) { + return vulnerabilityRow.vulnerability?.id; + } + if (columnId === columns.cvss) { + return vulnerabilityRow.vulnerability?.score.base; + } + if (columnId === columns.resource) { + return vulnerabilityRow.resource?.name; + } + if (columnId === columns.severity) { + return vulnerabilityRow.vulnerability?.severity; + } + if (columnId === columns.package) { + return vulnerabilityRow.vulnerability?.package?.name; + } + if (columnId === columns.version) { + return vulnerabilityRow.vulnerability?.package?.version; + } + if (columnId === columns.fix_version) { + return vulnerabilityRow.vulnerability?.package?.fixed_version; + } + if (columnId === columns.resource_id) { + return vulnerabilityRow.resource?.id; + } + if (columnId === columns.resource_name) { + return vulnerabilityRow.resource?.name; + } + if (columnId === columns.region) { + return vulnerabilityRow.cloud?.region; + } + }; + + const cellActions: EuiDataGridColumnCellAction[] = [ + ({ Component, rowIndex, columnId }) => { + const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; + + const value = getColumnIdValue(rowIndexFromPage, columnId); + + if (!value) return null; + return ( + + { + setUrlQuery({ + pageIndex: 0, + filters: getFilters({ + filters, + dataView, + field: columnId, + value, + negate: false, + }), + }); + }} + > + {FILTER_IN} + + + ); + }, + ({ Component, rowIndex, columnId }) => { + const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; + + const value = getColumnIdValue(rowIndexFromPage, columnId); + + if (!value) return null; + return ( + + { + setUrlQuery({ + pageIndex: 0, + filters: getFilters({ + filters, + dataView, + field: columnId, + value, + negate: true, + }), + }); + }} + > + {FILTER_OUT} + + + ); + }, + ]; + + return columnGridFn(cellActions); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx index 4d688c1d02cf3..7733d3010e281 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities.tsx @@ -9,11 +9,9 @@ import { EuiButtonIcon, EuiDataGrid, EuiDataGridCellValueElementProps, - EuiDataGridColumnCellAction, EuiFlexItem, EuiProgress, EuiSpacer, - EuiToolTip, useEuiTheme, } from '@elastic/eui'; import { cx } from '@emotion/css'; @@ -42,8 +40,7 @@ import { vulnerabilitiesColumns, } from './vulnerabilities_table_columns'; import { defaultLoadingRenderer, defaultNoDataRenderer } from '../../components/cloud_posture_page'; -import { getFilters } from './utils/get_filters'; -import { FILTER_IN, FILTER_OUT, SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from './translations'; +import { SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from './translations'; import { severitySchemaConfig, severitySortScript, @@ -54,6 +51,8 @@ import { FindingsGroupBySelector } from '../configurations/layout/findings_group import { vulnerabilitiesPathnameHandler } from './utils/vulnerabilities_pathname_handler'; import { findingsNavigation } from '../../common/navigation/constants'; import { VulnerabilitiesByResource } from './vulnerabilities_by_resource/vulnerabilities_by_resource'; +import { ResourceVulnerabilities } from './vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities'; +import { getVulnerabilitiesGridCellActions } from './utils/get_vulnerabilities_grid_cell_actions'; const getDefaultQuery = ({ query, filters }: any): any => ({ query, @@ -84,6 +83,11 @@ export const Vulnerabilities = () => { return ( + } + /> { }); const columns = useMemo(() => { - const getColumnIdValue = (rowIndex: number, columnId: string) => { - const vulnerabilityRow = data?.page[rowIndex] as VulnerabilityRecord; - if (!vulnerabilityRow) return null; - - if (columnId === vulnerabilitiesColumns.vulnerability) { - return vulnerabilityRow.vulnerability.id; - } - if (columnId === vulnerabilitiesColumns.cvss) { - return vulnerabilityRow.vulnerability.score.base; - } - if (columnId === vulnerabilitiesColumns.resource) { - return vulnerabilityRow.resource?.name; - } - if (columnId === vulnerabilitiesColumns.severity) { - return vulnerabilityRow.vulnerability.severity; - } - if (columnId === vulnerabilitiesColumns.package) { - return vulnerabilityRow.vulnerability?.package?.name; - } - if (columnId === vulnerabilitiesColumns.version) { - return vulnerabilityRow.vulnerability?.package?.version; - } - if (columnId === vulnerabilitiesColumns.fix_version) { - return vulnerabilityRow.vulnerability.package?.fixed_version; - } - }; - - const cellActions: EuiDataGridColumnCellAction[] = [ - ({ Component, rowIndex, columnId }) => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const value = getColumnIdValue(rowIndexFromPage, columnId); - - if (!value) return null; - return ( - - { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field: columnId, - value, - negate: false, - }), - }); - }} - > - {FILTER_IN} - - - ); - }, - ({ Component, rowIndex, columnId }) => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const value = getColumnIdValue(rowIndexFromPage, columnId); - - if (!value) return null; - return ( - - { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field: columnId, - value, - negate: true, - }), - }); - }} - > - {FILTER_OUT} - - - ); - }, - ]; - - return getVulnerabilitiesColumnsGrid(cellActions); + if (!data?.page) { + return []; + } + return getVulnerabilitiesGridCellActions({ + columnGridFn: getVulnerabilitiesColumnsGrid, + columns: vulnerabilitiesColumns, + dataView, + pageSize, + data: data.page, + setUrlQuery, + filters: urlQuery.filters, + }); }, [data?.page, dataView, pageSize, setUrlQuery, urlQuery.filters]); const flyoutVulnerabilityIndex = urlQuery?.vulnerabilityIndex; @@ -520,7 +417,7 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { }} /> {isLastLimitedPage && } - {showVulnerabilityFlyout && ( + {showVulnerabilityFlyout && selectedVulnerability && ( ({ total_vulnerabilities: 8, page: [ { - 'resource.id': 'resource-id-1', - 'resource.name': 'resource-test-1', - 'cloud.region': 'us-test-1', + resource: { id: 'resource-id-1', name: 'resource-test-1' }, + cloud: { region: 'us-test-1' }, vulnerabilities_count: 4, severity_map: { critical: 1, @@ -22,9 +21,8 @@ export const getVulnerabilitiesByResourceData = () => ({ }, }, { - 'resource.id': 'resource-id-2', - 'resource.name': 'resource-test-2', - 'cloud.region': 'us-test-1', + resource: { id: 'resource-id-2', name: 'resource-test-2' }, + cloud: { region: 'us-test-1' }, vulnerabilities_count: 4, severity_map: { critical: 1, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/__mocks__/resource_vulnerabilities.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/__mocks__/resource_vulnerabilities.mock.ts new file mode 100644 index 0000000000000..8328192062cc0 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/__mocks__/resource_vulnerabilities.mock.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const getResourceVulnerabilitiesMockData = () => ({ + page: [ + { + agent: { + name: 'ip-172-31-15-210', + id: '2d262db5-b637-4e46-a2a0-db409825ff46', + ephemeral_id: '2af1be77-0bdf-4313-b375-592848fe60d7', + type: 'cloudbeat', + version: '8.8.0', + }, + package: { + path: 'usr/lib/snapd/snapd', + fixed_version: '3.0.0-20220521103104-8f96da9f5d5e', + name: 'gopkg.in/yaml.v3', + type: 'gobinary', + version: 'v3.0.0-20210107192922-496545a6307b', + }, + resource: { + name: 'elastic-agent-instance-a6c683d0-0977-11ee-bb0b-0af2059ffbbf', + id: '0d103e99f17f355ba', + }, + elastic_agent: { + id: '2d262db5-b637-4e46-a2a0-db409825ff46', + version: '8.8.0', + snapshot: false, + }, + vulnerability: { + severity: 'HIGH', + package: { + fixed_version: '3.0.0-20220521103104-8f96da9f5d5e', + name: 'gopkg.in/yaml.v3', + version: 'v3.0.0-20210107192922-496545a6307b', + }, + description: + 'An issue in the Unmarshal function in Go-Yaml v3 causes the program to crash when attempting to deserialize invalid input.', + title: 'crash when attempting to deserialize invalid input', + classification: 'CVSS', + data_source: { + ID: 'go-vulndb', + URL: 'https://github.com/golang/vulndb', + Name: 'The Go Vulnerability Database', + }, + cwe: ['CWE-502'], + reference: 'https://avd.aquasec.com/nvd/cve-2022-28948', + score: { + version: '3.1', + base: 7.5, + }, + report_id: 1686633719, + scanner: { + vendor: 'Trivy', + version: 'v0.35.0', + }, + id: 'CVE-2022-28948', + enumeration: 'CVE', + published_date: '2022-05-19T20:15:00Z', + class: 'lang-pkgs', + cvss: { + redhat: { + V3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H', + V3Score: 7.5, + }, + nvd: { + V3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H', + V2Vector: 'AV:N/AC:L/Au:N/C:N/I:N/A:P', + V3Score: 7.5, + V2Score: 5, + }, + ghsa: { + V3Vector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H', + V3Score: 7.5, + }, + }, + }, + cloud: { + provider: 'aws', + region: 'us-east-1', + account: { + name: 'elastic-security-cloud-security-dev', + id: '704479110758', + }, + }, + '@timestamp': '2023-06-13T06:15:16.182Z', + cloudbeat: { + commit_sha: '8497f3a4b4744c645233c5a13b45400367411c2f', + commit_time: '2023-05-09T16:07:58Z', + version: '8.8.0', + }, + ecs: { + version: '8.6.0', + }, + data_stream: { + namespace: 'default', + type: 'logs', + dataset: 'cloud_security_posture.vulnerabilities', + }, + host: { + name: 'ip-172-31-15-210', + }, + event: { + agent_id_status: 'auth_metadata_missing', + sequence: 1686633719, + ingested: '2023-06-15T18:37:56Z', + created: '2023-06-13T06:15:16.18250081Z', + kind: 'state', + id: '5cad2983-4a74-455d-ab39-6c584acd3994', + type: ['info'], + category: ['vulnerability'], + dataset: 'cloud_security_posture.vulnerabilities', + outcome: 'success', + }, + }, + ], + total: 1, +}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.test.tsx new file mode 100644 index 0000000000000..9de1a61bebe38 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.test.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { useParams } from 'react-router-dom'; +import { ResourceVulnerabilities } from './resource_vulnerabilities'; +import { TestProvider } from '../../../../test/test_provider'; +import { useLatestVulnerabilities } from '../../hooks/use_latest_vulnerabilities'; +import { getResourceVulnerabilitiesMockData } from './__mocks__/resource_vulnerabilities.mock'; +import { VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ } from '../../../../components/test_subjects'; + +jest.mock('../../hooks/use_latest_vulnerabilities', () => ({ + useLatestVulnerabilities: jest.fn(), +})); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: jest.fn().mockReturnValue({ + integration: undefined, + }), +})); + +beforeEach(() => { + jest.clearAllMocks(); +}); + +describe('ResourceVulnerabilities', () => { + const dataView: any = {}; + + const renderVulnerabilityByResource = () => { + return render( + + + + ); + }; + + it('renders the loading state', () => { + (useLatestVulnerabilities as jest.Mock).mockReturnValue({ + data: undefined, + isLoading: true, + isFetching: true, + }); + renderVulnerabilityByResource(); + expect(screen.getByText(/loading/i)).toBeInTheDocument(); + }); + it('renders the no data state', () => { + (useLatestVulnerabilities as jest.Mock).mockReturnValue({ + data: undefined, + isLoading: false, + isFetching: false, + }); + + renderVulnerabilityByResource(); + expect(screen.getByText(/no data/i)).toBeInTheDocument(); + }); + + it('applies the correct filter on fetch', () => { + const resourceId = 'test'; + (useParams as jest.Mock).mockReturnValue({ + resourceId, + }); + renderVulnerabilityByResource(); + expect(useLatestVulnerabilities).toHaveBeenCalledWith( + expect.objectContaining({ + query: { + bool: { + filter: [ + { + term: { + 'resource.id': resourceId, + }, + }, + ], + must: [], + must_not: [], + should: [], + }, + }, + }) + ); + }); + + it('renders the empty state component', () => { + (useLatestVulnerabilities as jest.Mock).mockReturnValue({ + data: { total: 0, total_vulnerabilities: 0, page: [] }, + isLoading: false, + isFetching: false, + }); + + renderVulnerabilityByResource(); + expect(screen.getByText(/no results/i)).toBeInTheDocument(); + }); + + it('renders the Table', () => { + (useLatestVulnerabilities as jest.Mock).mockReturnValue({ + data: getResourceVulnerabilitiesMockData(), + isLoading: false, + isFetching: false, + }); + + renderVulnerabilityByResource(); + + // Header + expect(screen.getByText(/0d103e99f17f355ba/i)).toBeInTheDocument(); + expect(screen.getByText(/us-east-1/i)).toBeInTheDocument(); + expect( + screen.getByText(/elastic-agent-instance-a6c683d0-0977-11ee-bb0b-0af2059ffbbf/i) + ).toBeInTheDocument(); + + // Table + expect(screen.getByText(/CVE-2022-28948/i)).toBeInTheDocument(); + expect(screen.getByTestId(VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ)).toHaveTextContent(/7.5/i); + expect(screen.getByTestId(VULNERABILITIES_CVSS_SCORE_BADGE_SUBJ)).toHaveTextContent(/v3/i); + expect(screen.getByText(/high/i)).toBeInTheDocument(); + expect(screen.getByText(/gopkg.in\/yaml.v3/i)).toBeInTheDocument(); + expect(screen.getByText(/v3.0.0-20210107192922-496545a6307b/i)).toBeInTheDocument(); + expect(screen.getByText(/3.0.0-20220521103104-8f96da9f5d5e/i)).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.tsx new file mode 100644 index 0000000000000..f40196d4f4a14 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/resource_vulnerabilities/resource_vulnerabilities.tsx @@ -0,0 +1,443 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiButtonEmpty, + EuiButtonIcon, + EuiDataGrid, + EuiDataGridCellValueElementProps, + EuiProgress, + EuiSpacer, + useEuiTheme, +} from '@elastic/eui'; +import { cx } from '@emotion/css'; +import { DataView } from '@kbn/data-views-plugin/common'; +import React, { useCallback, useMemo, useState, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { Link, useParams, generatePath } from 'react-router-dom'; +import { css } from '@emotion/react'; +import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../../../common/constants'; +import { useCloudPostureTable } from '../../../../common/hooks/use_cloud_posture_table'; +import { useLatestVulnerabilities } from '../../hooks/use_latest_vulnerabilities'; +import { VulnerabilityRecord } from '../../types'; +import { ErrorCallout } from '../../../configurations/layout/error_callout'; +import { FindingsSearchBar } from '../../../configurations/layout/findings_search_bar'; +import { CVSScoreBadge, SeverityStatusBadge } from '../../../../components/vulnerability_badges'; +import { EmptyState } from '../../../../components/empty_state'; +import { VulnerabilityFindingFlyout } from '../../vulnerabilities_finding_flyout/vulnerability_finding_flyout'; +import { useLimitProperties } from '../../../../common/utils/get_limit_properties'; +import { + LimitedResultsBar, + PageTitle, + PageTitleText, +} from '../../../configurations/layout/findings_layout'; +import { + getVulnerabilitiesColumnsGrid, + vulnerabilitiesColumns, +} from '../../vulnerabilities_table_columns'; +import { + defaultLoadingRenderer, + defaultNoDataRenderer, +} from '../../../../components/cloud_posture_page'; +import { SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from '../../translations'; +import { + severitySchemaConfig, + severitySortScript, + getCaseInsensitiveSortScript, +} from '../../utils/custom_sort_script'; +import { useStyles } from '../../hooks/use_styles'; +import { findingsNavigation } from '../../../../common/navigation/constants'; +import { CspInlineDescriptionList } from '../../../../components/csp_inline_description_list'; +import { getVulnerabilitiesGridCellActions } from '../../utils/get_vulnerabilities_grid_cell_actions'; + +const getDefaultQuery = ({ query, filters }: any) => ({ + query, + filters, + sort: [ + { id: vulnerabilitiesColumns.severity, direction: 'desc' }, + { id: vulnerabilitiesColumns.cvss, direction: 'desc' }, + ], + pageIndex: 0, +}); + +export const ResourceVulnerabilities = ({ dataView }: { dataView: DataView }) => { + const params = useParams<{ resourceId: string }>(); + const resourceId = decodeURIComponent(params.resourceId); + + const { + pageIndex, + query, + sort, + queryError, + pageSize, + onChangeItemsPerPage, + onChangePage, + onSort, + urlQuery, + setUrlQuery, + onResetFilters, + } = useCloudPostureTable({ + dataView, + defaultQuery: getDefaultQuery, + paginationLocalStorageKey: LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY, + }); + const { euiTheme } = useEuiTheme(); + const styles = useStyles(); + + const [showHighlight, setHighlight] = useState(false); + + const onSortHandler = useCallback( + (newSort: any) => { + onSort(newSort); + if (newSort.length !== sort.length) { + setHighlight(true); + setTimeout(() => { + setHighlight(false); + }, 2000); + } + }, + [onSort, sort] + ); + + const multiFieldsSort = useMemo(() => { + return sort.map(({ id, direction }: { id: string; direction: string }) => { + if (id === vulnerabilitiesColumns.severity) { + return severitySortScript(direction); + } + if (id === vulnerabilitiesColumns.package) { + return getCaseInsensitiveSortScript(id, direction); + } + + return { + [id]: direction, + }; + }); + }, [sort]); + + const { data, isLoading, isFetching } = useLatestVulnerabilities({ + query: { + ...query, + bool: { + ...query!.bool, + filter: [...(query?.bool?.filter || []), { term: { 'resource.id': resourceId } }], + }, + }, + sort: multiFieldsSort, + enabled: !queryError, + pageIndex, + pageSize, + }); + + const invalidIndex = -1; + + const selectedVulnerability = useMemo(() => { + return data?.page[urlQuery.vulnerabilityIndex]; + }, [data?.page, urlQuery.vulnerabilityIndex]); + + const onCloseFlyout = () => { + setUrlQuery({ + vulnerabilityIndex: invalidIndex, + }); + }; + + const onOpenFlyout = useCallback( + (vulnerabilityRow: VulnerabilityRecord) => { + const vulnerabilityIndex = data?.page.findIndex( + (vulnerabilityRecord: VulnerabilityRecord) => + vulnerabilityRecord.vulnerability?.id === vulnerabilityRow.vulnerability?.id && + vulnerabilityRecord.resource?.id === vulnerabilityRow.resource?.id && + vulnerabilityRecord.vulnerability.package.name === + vulnerabilityRow.vulnerability.package.name && + vulnerabilityRecord.vulnerability.package.version === + vulnerabilityRow.vulnerability.package.version + ); + setUrlQuery({ + vulnerabilityIndex, + }); + }, + [setUrlQuery, data?.page] + ); + + const { isLastLimitedPage, limitedTotalItemCount } = useLimitProperties({ + total: data?.total, + pageIndex, + pageSize, + }); + + const columns = useMemo(() => { + if (!data?.page) { + return []; + } + return getVulnerabilitiesGridCellActions({ + columnGridFn: getVulnerabilitiesColumnsGrid, + columns: vulnerabilitiesColumns, + dataView, + pageSize, + data: data.page, + setUrlQuery, + filters: urlQuery.filters, + }).filter((column) => column.id !== vulnerabilitiesColumns.resource); + }, [data?.page, dataView, pageSize, setUrlQuery, urlQuery.filters]); + + const flyoutVulnerabilityIndex = urlQuery?.vulnerabilityIndex; + + const selectedVulnerabilityIndex = flyoutVulnerabilityIndex + pageIndex * pageSize; + + const renderCellValue = useMemo(() => { + const Cell: React.FC = ({ + columnId, + rowIndex, + setCellProps, + }): React.ReactElement | null => { + const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; + + const vulnerabilityRow = data?.page[rowIndexFromPage] as VulnerabilityRecord; + + useEffect(() => { + if (selectedVulnerabilityIndex === rowIndex) { + setCellProps({ + style: { + backgroundColor: euiTheme.colors.highlight, + }, + }); + } else { + setCellProps({ + style: { + backgroundColor: 'inherit', + }, + }); + } + }, [rowIndex, setCellProps]); + + if (isFetching) return null; + if (!vulnerabilityRow) return null; + if (!vulnerabilityRow.vulnerability?.id) return null; + + if (columnId === vulnerabilitiesColumns.actions) { + return ( + { + onOpenFlyout(vulnerabilityRow); + }} + /> + ); + } + if (columnId === vulnerabilitiesColumns.vulnerability) { + return <>{vulnerabilityRow.vulnerability?.id}; + } + if (columnId === vulnerabilitiesColumns.cvss) { + if ( + !vulnerabilityRow.vulnerability.score?.base || + !vulnerabilityRow.vulnerability.score?.version + ) { + return null; + } + return ( + + ); + } + if (columnId === vulnerabilitiesColumns.resource) { + return <>{vulnerabilityRow.resource?.name}; + } + if (columnId === vulnerabilitiesColumns.severity) { + if (!vulnerabilityRow.vulnerability.severity) { + return null; + } + return ; + } + + if (columnId === vulnerabilitiesColumns.package) { + return <>{vulnerabilityRow.vulnerability?.package?.name}; + } + if (columnId === vulnerabilitiesColumns.version) { + return <>{vulnerabilityRow.vulnerability?.package?.version}; + } + if (columnId === vulnerabilitiesColumns.fix_version) { + return <>{vulnerabilityRow.vulnerability?.package?.fixed_version}; + } + + return null; + }; + + return Cell; + }, [ + data?.page, + euiTheme.colors.highlight, + onOpenFlyout, + pageSize, + selectedVulnerabilityIndex, + isFetching, + ]); + + const onPaginateFlyout = useCallback( + (nextVulnerabilityIndex: number) => { + // the index of the vulnerability in the current page + const newVulnerabilityIndex = nextVulnerabilityIndex % pageSize; + + // if the vulnerability is not in the current page, we need to change the page + const flyoutPageIndex = Math.floor(nextVulnerabilityIndex / pageSize); + + setUrlQuery({ + pageIndex: flyoutPageIndex, + vulnerabilityIndex: newVulnerabilityIndex, + }); + }, + [pageSize, setUrlQuery] + ); + + const error = queryError || null; + + if (error) { + return ; + } + if (isLoading) { + return defaultLoadingRenderer(); + } + + if (!data?.page) { + return defaultNoDataRenderer(); + } + + const showVulnerabilityFlyout = flyoutVulnerabilityIndex > invalidIndex; + + return ( + <> + { + setUrlQuery({ ...newQuery, pageIndex: 0 }); + }} + loading={isLoading} + placeholder={SEARCH_BAR_PLACEHOLDER} + /> + + + + + + + + + + + + + + {!isLoading && data?.page.length === 0 ? ( + + ) : ( + <> + + id), + setVisibleColumns: () => {}, + }} + height={undefined} + width={undefined} + schemaDetectors={[severitySchemaConfig]} + rowCount={limitedTotalItemCount} + rowHeightsOptions={{ + defaultHeight: 40, + }} + toolbarVisibility={{ + showColumnSelector: false, + showDisplaySelector: false, + showKeyboardShortcuts: false, + showFullScreenSelector: false, + additionalControls: { + left: { + prepend: ( + <> + + {i18n.translate('xpack.csp.vulnerabilities.totalVulnerabilities', { + defaultMessage: + '{total, plural, one {# Vulnerability} other {# Vulnerabilities}}', + values: { total: data?.total }, + })} + + + ), + }, + }, + }} + gridStyle={{ + border: 'horizontal', + cellPadding: 'l', + stripes: false, + rowHover: 'none', + header: 'underline', + }} + renderCellValue={renderCellValue} + inMemory={{ level: 'enhancements' }} + sorting={{ columns: sort, onSort: onSortHandler }} + pagination={{ + pageIndex, + pageSize, + pageSizeOptions: [10, 25, 100], + onChangeItemsPerPage, + onChangePage, + }} + /> + {isLastLimitedPage && } + {showVulnerabilityFlyout && selectedVulnerability && ( + + )} + + )} + + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.tsx index 5e2ac7e199e5a..9e4e47707e142 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_by_resource/vulnerabilities_by_resource.tsx @@ -9,16 +9,16 @@ import { EuiButtonEmpty, EuiDataGrid, EuiDataGridCellValueElementProps, - EuiDataGridColumnCellAction, EuiFlexItem, EuiProgress, EuiSpacer, - EuiToolTip, } from '@elastic/eui'; import { DataView } from '@kbn/data-views-plugin/common'; import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; +import { Link, generatePath } from 'react-router-dom'; import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../../common/constants'; +import { findingsNavigation } from '../../../common/navigation/constants'; import { useCloudPostureTable } from '../../../common/hooks/use_cloud_posture_table'; import { ErrorCallout } from '../../configurations/layout/error_callout'; import { FindingsSearchBar } from '../../configurations/layout/findings_search_bar'; @@ -32,8 +32,7 @@ import { defaultLoadingRenderer, defaultNoDataRenderer, } from '../../../components/cloud_posture_page'; -import { getFilters } from '../utils/get_filters'; -import { FILTER_IN, FILTER_OUT, SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from '../translations'; +import { SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from '../translations'; import { useStyles } from '../hooks/use_styles'; import { FindingsGroupBySelector } from '../../configurations/layout/findings_group_by_selector'; import { vulnerabilitiesPathnameHandler } from '../utils/vulnerabilities_pathname_handler'; @@ -41,6 +40,7 @@ import { useLatestVulnerabilitiesByResource } from '../hooks/use_latest_vulnerab import { EmptyState } from '../../../components/empty_state'; import { SeverityMap } from './severity_map'; import { VULNERABILITY_RESOURCE_COUNT } from './test_subjects'; +import { getVulnerabilitiesGridCellActions } from '../utils/get_vulnerabilities_grid_cell_actions'; const getDefaultQuery = ({ query, filters }: any): any => ({ query, @@ -84,114 +84,19 @@ export const VulnerabilitiesByResource = ({ dataView }: { dataView: DataView }) }); const columns = useMemo(() => { - const getColumnIdValue = (rowIndex: number, columnId: string) => { - const vulnerabilityRow = data?.page[rowIndex]; - if (!vulnerabilityRow) return null; - - if (columnId === vulnerabilitiesByResourceColumns.resource_id) { - return vulnerabilityRow['resource.id']; - } - if (columnId === vulnerabilitiesByResourceColumns.resource_name) { - return vulnerabilityRow['resource.name']; - } - if (columnId === vulnerabilitiesByResourceColumns.region) { - return vulnerabilityRow['cloud.region']; - } - }; - - const cellActions: EuiDataGridColumnCellAction[] = [ - ({ Component, rowIndex, columnId }) => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const value = getColumnIdValue(rowIndexFromPage, columnId); - - if (!value) return null; - return ( - - { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field: columnId, - value, - negate: false, - }), - }); - }} - > - {FILTER_IN} - - - ); - }, - ({ Component, rowIndex, columnId }) => { - const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; - - const value = getColumnIdValue(rowIndexFromPage, columnId); - - if (!value) return null; - return ( - - { - setUrlQuery({ - pageIndex: 0, - filters: getFilters({ - filters: urlQuery.filters, - dataView, - field: columnId, - value, - negate: true, - }), - }); - }} - > - {FILTER_OUT} - - - ); - }, - ]; - - return getVulnerabilitiesByResourceColumnsGrid(cellActions); - }, [data?.page, dataView, pageSize, setUrlQuery, urlQuery.filters]); + if (!data?.page) { + return []; + } + return getVulnerabilitiesGridCellActions({ + columnGridFn: getVulnerabilitiesByResourceColumnsGrid, + columns: vulnerabilitiesByResourceColumns, + dataView, + pageSize, + data: data.page, + setUrlQuery, + filters: urlQuery.filters, + }); + }, [data, dataView, pageSize, setUrlQuery, urlQuery.filters]); const renderCellValue = useMemo(() => { const Cell: React.FC = ({ @@ -203,16 +108,26 @@ export const VulnerabilitiesByResource = ({ dataView }: { dataView: DataView }) const resourceVulnerabilityRow = data?.page[rowIndexFromPage]; if (isFetching) return null; - if (!resourceVulnerabilityRow?.['resource.id']) return null; + if (!resourceVulnerabilityRow?.resource?.id) return null; if (columnId === vulnerabilitiesByResourceColumns.resource_id) { - return <>{resourceVulnerabilityRow['resource.id']}; + return ( + + {resourceVulnerabilityRow?.resource?.id} + + ); } if (columnId === vulnerabilitiesByResourceColumns.resource_name) { - return <>{resourceVulnerabilityRow['resource.name']}; + return <>{resourceVulnerabilityRow?.resource?.name}; } if (columnId === vulnerabilitiesByResourceColumns.region) { - return <>{resourceVulnerabilityRow['cloud.region']}; + return <>{resourceVulnerabilityRow?.cloud?.region}; } if (columnId === vulnerabilitiesByResourceColumns.vulnerabilities_count) { return ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx index 0b08af66d6ee9..efe451ba97e54 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.tsx @@ -189,7 +189,7 @@ export const VulnerabilityFindingFlyout = ({ -

    -

    +
    diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/_mocks_/vulnerability_dashboard.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/_mocks_/vulnerability_dashboard.mock.ts new file mode 100644 index 0000000000000..05b73d74e6cec --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/_mocks_/vulnerability_dashboard.mock.ts @@ -0,0 +1,278 @@ +/* + * Copyright 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 { CnvmDashboardData } from '../../../../common/types'; + +export const mockCnvmDashboardData: CnvmDashboardData = { + cnvmStatistics: { + criticalCount: 84, + highCount: 4595, + mediumCount: 12125, + resourcesScanned: 81, + cloudRegions: 1, + }, + vulnTrends: [ + { + high: 4634, + policy_template: 'vuln_mgmt', + medium: 12522, + '@timestamp': '2023-06-15T23:49:46.563935Z', + critical: 84, + low: 4147, + }, + { + high: 4634, + policy_template: 'vuln_mgmt', + medium: 12522, + '@timestamp': '2023-06-16T23:50:14.640737Z', + critical: 84, + low: 4147, + }, + { + high: 4634, + policy_template: 'vuln_mgmt', + medium: 12522, + '@timestamp': '2023-06-17T23:53:51.851500Z', + critical: 84, + low: 4147, + }, + { + high: 4634, + policy_template: 'vuln_mgmt', + medium: 12522, + '@timestamp': '2023-06-18T23:53:50.831704Z', + critical: 84, + low: 4147, + }, + { + high: 4634, + policy_template: 'vuln_mgmt', + medium: 12522, + '@timestamp': '2023-06-19T08:28:22.830830Z', + critical: 84, + low: 4147, + }, + ], + topVulnerableResources: [ + { + resource: { id: '01dfb5ad43724b411', name: 'dima-sanity-FQj' }, + vulnerabilityCount: 2030, + cloudRegion: 'eu-west-1', + }, + { + resource: { id: '09aa0a3d51dae9820', name: 'dima-sanity-FQj' }, + vulnerabilityCount: 2030, + cloudRegion: 'eu-west-1', + }, + { + resource: { id: '042985d76403bab90', name: 'kfir3-june12-8-8-0-41B' }, + vulnerabilityCount: 1551, + cloudRegion: 'eu-west-1', + }, + { + resource: { id: '0ba9cce1f0984b413', name: 'daily-env-8.7-vanilla' }, + vulnerabilityCount: 894, + cloudRegion: 'eu-west-1', + }, + { + resource: { id: '0a2dc4a316cdefd0a', name: 'TrackLiveEnvironment' }, + vulnerabilityCount: 679, + cloudRegion: 'eu-west-1', + }, + { + resource: { + id: '0bcb81dda72d6d86a', + name: 'elastic-agent-instance-36c7f8d0-fd41-11ed-b093-02daf9c5eb3d', + }, + vulnerabilityCount: 383, + cloudRegion: 'eu-west-1', + }, + { + resource: { + id: '0413fc81a8f190eda', + name: 'elastic-agent-instance-19770570-e7b9-11ed-a680-02315045ab2d', + }, + vulnerabilityCount: 340, + cloudRegion: 'eu-west-1', + }, + { + resource: { + id: '006ea5239813449ee', + name: 'elastic-agent-instance-b32cdc60-091c-11ee-818e-06cae4cbdef5', + }, + vulnerabilityCount: 334, + cloudRegion: 'eu-west-1', + }, + { + resource: { + id: '0f2dec779a9b6df40', + name: 'elastic-agent-instance-9fb90e20-fb1a-11ed-ac6c-02d320ffd109', + }, + vulnerabilityCount: 321, + cloudRegion: 'eu-west-1', + }, + { + resource: { id: '089a865e3fe1fe29b', name: 'cloudbeat-tf-5jA-2' }, + vulnerabilityCount: 314, + cloudRegion: 'eu-west-1', + }, + ], + topPatchableVulnerabilities: [ + { + cve: 'CVE-2022-41723', + cvss: { score: 7.5, version: '3.1' }, + packageFixVersion: '0.7.0', + vulnerabilityCount: 384, + }, + { + cve: 'CVE-2022-41717', + cvss: { score: 5.300000190734863, version: '3.1' }, + packageFixVersion: '0.4.0', + vulnerabilityCount: 335, + }, + { + cve: 'CVE-2022-27664', + cvss: { score: 7.5, version: '3.1' }, + packageFixVersion: '0.0.0-20220906165146-f3363e06e74c', + vulnerabilityCount: 237, + }, + { + cve: 'CVE-2021-37600', + cvss: { score: 5.5, version: '3.1' }, + packageFixVersion: '2.30.2-2.amzn2.0.11', + vulnerabilityCount: 168, + }, + { + cve: 'CVE-2023-2253', + cvss: { score: 7.5, version: '3.1' }, + packageFixVersion: '2.8.2-beta.1', + vulnerabilityCount: 157, + }, + { + cve: 'CVE-2023-2609', + cvss: { score: 7.800000190734863, version: '3.1' }, + packageFixVersion: '2:9.0.1592-1.amzn2.0.1', + vulnerabilityCount: 154, + }, + { + cve: 'CVE-2023-2610', + cvss: { score: 7.800000190734863, version: '3.1' }, + packageFixVersion: '2:9.0.1592-1.amzn2.0.1', + vulnerabilityCount: 154, + }, + { + cve: 'CVE-2023-28840', + cvss: { score: 7.5, version: '3.1' }, + packageFixVersion: '23.0.3, 20.10.24', + vulnerabilityCount: 152, + }, + { + cve: 'CVE-2023-28841', + cvss: { score: 6.800000190734863, version: '3.1' }, + packageFixVersion: '23.0.3, 20.10.24', + vulnerabilityCount: 152, + }, + { + cve: 'CVE-2023-28842', + cvss: { score: 6.800000190734863, version: '3.1' }, + packageFixVersion: '23.0.3, 20.10.24', + vulnerabilityCount: 152, + }, + ], + topVulnerabilities: [ + { + cve: 'CVE-2022-41723', + packageFixVersion: '0.7.0', + packageName: 'golang.org/x/net', + packageVersion: 'v0.0.0-20220809184613-07c6da5e1ced', + severity: 'HIGH', + vulnerabilityCount: 384, + cvss: { score: 7.5, version: '3.1' }, + }, + { + cve: 'CVE-2022-41717', + packageFixVersion: '0.4.0', + packageName: 'golang.org/x/net', + packageVersion: 'v0.0.0-20220809184613-07c6da5e1ced', + severity: 'MEDIUM', + vulnerabilityCount: 335, + cvss: { score: 5.300000190734863, version: '3.1' }, + }, + { + cve: 'CVE-2020-8911', + packageFixVersion: '', + packageName: 'github.com/aws/aws-sdk-go', + packageVersion: 'v1.38.60', + severity: 'MEDIUM', + vulnerabilityCount: 334, + cvss: { score: 5.599999904632568, version: '3.1' }, + }, + { + cve: 'CVE-2020-8912', + packageFixVersion: '', + packageName: 'github.com/aws/aws-sdk-go', + packageVersion: 'v1.38.60', + severity: 'LOW', + vulnerabilityCount: 334, + cvss: { score: 2.5, version: '3.1' }, + }, + { + cve: 'CVE-2022-27664', + packageFixVersion: '0.0.0-20220906165146-f3363e06e74c', + packageName: 'golang.org/x/net', + packageVersion: 'v0.0.0-20220809184613-07c6da5e1ced', + severity: 'HIGH', + vulnerabilityCount: 237, + cvss: { score: 7.5, version: '3.1' }, + }, + { + cve: 'CVE-2023-2609', + packageFixVersion: '2:9.0.1592-1.amzn2.0.1', + packageName: 'vim-data', + packageVersion: '2:8.2.3995-1ubuntu2.7', + severity: 'HIGH', + vulnerabilityCount: 199, + cvss: { score: 7.800000190734863, version: '3.1' }, + }, + { + cve: 'CVE-2023-2610', + packageFixVersion: '2:9.0.1592-1.amzn2.0.1', + packageName: 'vim-data', + packageVersion: '2:8.2.3995-1ubuntu2.7', + severity: 'HIGH', + vulnerabilityCount: 199, + cvss: { score: 7.800000190734863, version: '3.1' }, + }, + { + cve: 'CVE-2022-3219', + packageFixVersion: '', + packageName: 'dirmngr', + packageVersion: '2.2.27-3ubuntu2.1', + severity: 'LOW', + vulnerabilityCount: 176, + cvss: { score: 3.299999952316284, version: '3.1' }, + }, + { + cve: 'CVE-2021-37600', + packageFixVersion: '2.30.2-2.amzn2.0.11', + packageName: 'libblkid', + packageVersion: '2.30.2-2.amzn2.0.10', + severity: 'LOW', + vulnerabilityCount: 168, + cvss: { score: 5.5, version: '3.1' }, + }, + { + cve: 'CVE-2023-2253', + packageFixVersion: '2.8.2-beta.1', + packageName: 'github.com/docker/distribution', + packageVersion: 'v2.8.1+incompatible', + severity: 'HIGH', + vulnerabilityCount: 157, + cvss: { score: 7.5, version: '3.1' }, + }, + ], +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx index 6e2c51e0b727b..de41bfdccd9c1 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.test.tsx @@ -29,6 +29,8 @@ import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; import { useLicenseManagementLocatorApi } from '../../common/api/use_license_management_locator_api'; import { VulnerabilityDashboard } from './vulnerability_dashboard'; import { VULNERABILITY_DASHBOARD_CONTAINER } from '../compliance_dashboard/test_subjects'; +import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability_dashboard_api'; +import { mockCnvmDashboardData } from './_mocks_/vulnerability_dashboard.mock'; jest.mock('../../common/api/use_latest_findings_data_view'); jest.mock('../../common/api/use_setup_status_api'); @@ -36,6 +38,7 @@ jest.mock('../../common/api/use_license_management_locator_api'); jest.mock('../../common/hooks/use_subscription_status'); jest.mock('../../common/navigation/use_navigate_to_cis_integration_policies'); jest.mock('../../common/navigation/use_csp_integration_link'); +jest.mock('../../common/api/use_vulnerability_dashboard_api'); const chance = new Chance(); @@ -190,6 +193,12 @@ describe('', () => { }) ); (useCspIntegrationLink as jest.Mock).mockImplementation(() => chance.url()); + (useVulnerabilityDashboardApi as jest.Mock).mockImplementation(() => + createReactQueryResponse({ + status: 'success', + data: mockCnvmDashboardData, + }) + ); renderVulnerabilityDashboardPage(); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.tsx index 36d2d5fe99c6e..eadecbfab9cc4 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.tsx @@ -7,6 +7,8 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiPageHeader, EuiSpacer } from '@elastic/eui'; +import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability_dashboard_api'; +import { VulnerabilityTrendGraph } from './vulnerability_trend_graph'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; import { NoVulnerabilitiesStates } from '../../components/no_vulnerabilities_states'; import { @@ -20,6 +22,7 @@ import { VulnerabilityTablePanelSection } from './vulnerability_table_panel_sect export const VulnerabilityDashboard = () => { const getSetupStatus = useCspSetupStatusApi(); + const getVulnerabilityDashboard = useVulnerabilityDashboardApi(); return ( @@ -38,12 +41,16 @@ export const VulnerabilityDashboard = () => { {getSetupStatus?.data?.vuln_mgmt?.status !== 'indexed' ? ( ) : ( -
    - - - - -
    + +
    + + + + + + +
    +
    )}
    ); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx index b05fd1d22597d..d7b93bd861b0d 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_statistics.tsx @@ -8,7 +8,7 @@ import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiHealth } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { VULNERABILITIES_SEVERITY } from '../../../common/constants'; -import { useCnvmStatisticsApi } from '../../common/api/use_vulnerabilities_stats_api'; +import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability_dashboard_api'; import { useNavigateVulnerabilities } from '../../common/hooks/use_navigate_findings'; import { CompactFormattedNumber } from '../../components/compact_formatted_number'; import { getSeverityStatusColor } from '../../common/utils/get_vulnerability_colors'; @@ -16,13 +16,17 @@ import { CspCounterCard } from '../../components/csp_counter_card'; export const VulnerabilityStatistics = () => { const navToVulnerabilities = useNavigateVulnerabilities(); - const getCnvmStats = useCnvmStatisticsApi(); + const getVulnerabilityDashboard = useVulnerabilityDashboardApi(); const stats = useMemo( () => [ { id: 'cloud-regions-stat', - title: , + title: ( + + ), description: i18n.translate('xpack.csp.cnvmDashboard.statistics.cloudRegionTitle', { defaultMessage: 'Cloud Regions', }), @@ -30,7 +34,9 @@ export const VulnerabilityStatistics = () => { { id: 'assets-scanned-stat', title: ( - + ), description: i18n.translate('xpack.csp.cnvmDashboard.statistics.resourcesScannedTitle', { defaultMessage: 'Resources Scanned', @@ -38,9 +44,16 @@ export const VulnerabilityStatistics = () => { }, { id: 'critical-count-stat', - title: , + title: ( + + ), description: ( - + {i18n.translate('xpack.csp.cnvmDashboard.statistics.criticalTitle', { defaultMessage: 'Critical', })} @@ -52,9 +65,13 @@ export const VulnerabilityStatistics = () => { }, { id: 'high-count-stat', - title: , + title: ( + + ), description: ( - + {i18n.translate('xpack.csp.cnvmDashboard.statistics.highTitle', { defaultMessage: 'High', })} @@ -66,9 +83,16 @@ export const VulnerabilityStatistics = () => { }, { id: 'medium-count-stat', - title: , + title: ( + + ), description: ( - + {i18n.translate('xpack.csp.cnvmDashboard.statistics.mediumTitle', { defaultMessage: 'Medium', })} @@ -79,7 +103,7 @@ export const VulnerabilityStatistics = () => { }, }, ], - [getCnvmStats.data, navToVulnerabilities] + [getVulnerabilityDashboard.data, navToVulnerabilities] ); return ( diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.config.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.config.ts index 1144f86471b4b..b0a4436bc6b8c 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.config.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.config.ts @@ -15,17 +15,17 @@ export enum DASHBOARD_TABLE_TYPES { export const vulnerabilityDashboardTableContent = { [DASHBOARD_TABLE_TYPES.TOP_VULNERABLE_RESOURCES]: { - title: i18n.translate('xpack.csp.cvnmDasbhboardTable.panel.topVulnerableResources.title', { + title: i18n.translate('xpack.csp.cnvmDashboardTable.panel.topVulnerableResources.title', { defaultMessage: 'Top 10 vulnerable resources', }), }, [DASHBOARD_TABLE_TYPES.TOP_PATCH_VULNERABILITIES]: { - title: i18n.translate('xpack.csp.cvnmDasbhboardTable.panel.topPatchVulnerabilities.title', { + title: i18n.translate('xpack.csp.cnvmDashboardTable.panel.topPatchVulnerabilities.title', { defaultMessage: 'Top 10 patchable vulnerabilities', }), }, [DASHBOARD_TABLE_TYPES.TOP_VULNERABILITIES]: { - title: i18n.translate('xpack.csp.cvnmDasbhboardTable.panel.topVulnerabilities.title', { + title: i18n.translate('xpack.csp.cnvmDashboardTable.panel.topVulnerabilities.title', { defaultMessage: 'Top 10 vulnerabilities', }), }, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.tsx index cba8b36f1ed15..aac58442a9a34 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel.tsx @@ -7,9 +7,7 @@ import React from 'react'; import { - EuiTitle, EuiButtonEmpty, - EuiPanel, EuiBasicTable, EuiSpacer, EuiToolTip, @@ -22,6 +20,7 @@ import { DASHBOARD_TABLE_TYPES, vulnerabilityDashboardTableContent, } from './vulnerability_table_panel.config'; +import { ChartPanel } from '../../components/chart_panel'; export interface VulnerabilityDashboardTableProps { tableType: DASHBOARD_TABLE_TYPES; @@ -43,11 +42,7 @@ export const VulnerabilityTablePanel = ({ }); return ( - - -

    {title}

    -
    - + ({ - {i18n.translate('xpack.csp.vulnerabilityTable.panel..buttonText', { + {i18n.translate('xpack.csp.vulnerabilityTable.panel.buttonText', { defaultMessage: 'View all vulnerabilities', })} -
    + ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx index a81f01875746a..84ab162b243a4 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_table_panel_section.tsx @@ -22,7 +22,6 @@ import { VulnerableResourceStat, VulnSeverity, } from '../../../common/types'; -import { useCnvmStatisticsApi } from '../../common/api/use_vulnerabilities_stats_api'; import { DASHBOARD_TABLE_TYPES } from './vulnerability_table_panel.config'; import { VulnerabilityTablePanel } from './vulnerability_table_panel'; import { @@ -31,9 +30,10 @@ import { useNavigateVulnerabilitiesByResource, } from '../../common/hooks/use_navigate_findings'; import { CVSScoreBadge, SeverityStatusBadge } from '../../components/vulnerability_badges'; +import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability_dashboard_api'; export const VulnerabilityTablePanelSection = () => { - const getCnvmStats = useCnvmStatisticsApi(); + const getVulnerabilityDashboard = useVulnerabilityDashboardApi(); const { euiTheme } = useEuiTheme(); const navToVulnerabilities = useNavigateVulnerabilities(); const navToVulnerabilitiesByResource = useNavigateVulnerabilitiesByResource(); @@ -59,7 +59,7 @@ export const VulnerabilityTablePanelSection = () => { field: 'resource', truncateText: true, name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerableResources.column.resource', + 'xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.resource', { defaultMessage: 'Resource', } @@ -76,7 +76,7 @@ export const VulnerabilityTablePanelSection = () => { { field: 'cloudRegion', name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerableResources.column.region', + 'xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.region', { defaultMessage: 'Region', } @@ -98,7 +98,7 @@ export const VulnerabilityTablePanelSection = () => { {i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerableResources.column.vulnerabilities', + 'xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilities', { defaultMessage: 'Vulnerabilities', } @@ -118,7 +118,7 @@ export const VulnerabilityTablePanelSection = () => { { field: 'cve', name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerableResources.column.cve', + 'xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.cve', { defaultMessage: 'CVE', } @@ -135,7 +135,7 @@ export const VulnerabilityTablePanelSection = () => { { field: 'cvss', name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerableResources.column.version', + 'xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.version', { defaultMessage: 'CVSS', } @@ -150,7 +150,7 @@ export const VulnerabilityTablePanelSection = () => { field: 'packageFixVersion', truncateText: true, name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topPatchableVulnerabilities.column.fixedVersion', + 'xpack.csp.cnvmDashboardTable.section.topPatchableVulnerabilities.column.fixedVersion', { defaultMessage: 'Fix Version', } @@ -173,7 +173,7 @@ export const VulnerabilityTablePanelSection = () => { {i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerableResources.column.vulnerabilityCount', + 'xpack.csp.cnvmDashboardTable.section.topVulnerableResources.column.vulnerabilityCount', { defaultMessage: 'Vulnerabilities', } @@ -190,7 +190,7 @@ export const VulnerabilityTablePanelSection = () => { () => [ { field: 'cve', - name: i18n.translate('xpack.csp.cvnmDasbhboardTable.section.topVulnerability.column.cve', { + name: i18n.translate('xpack.csp.cnvmDashboardTable.section.topVulnerability.column.cve', { defaultMessage: 'CVE', }), render: (cve: string) => ( @@ -205,7 +205,7 @@ export const VulnerabilityTablePanelSection = () => { { field: 'cvss', name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerability.column.version', + 'xpack.csp.cnvmDashboardTable.section.topVulnerability.column.version', { defaultMessage: 'CVSS', } @@ -219,7 +219,7 @@ export const VulnerabilityTablePanelSection = () => { { field: 'severity', name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerability.column.severity', + 'xpack.csp.cnvmDashboardTable.section.topVulnerability.column.severity', { defaultMessage: 'Severity', } @@ -234,7 +234,7 @@ export const VulnerabilityTablePanelSection = () => { field: 'packageName', truncateText: true, name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerability.column.packageName', + 'xpack.csp.cnvmDashboardTable.section.topVulnerability.column.packageName', { defaultMessage: 'Package Name', } @@ -253,7 +253,7 @@ export const VulnerabilityTablePanelSection = () => { field: 'packageVersion', truncateText: true, name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerability.column.packageVersion', + 'xpack.csp.cnvmDashboardTable.section.topVulnerability.column.packageVersion', { defaultMessage: 'Package Version', } @@ -272,7 +272,7 @@ export const VulnerabilityTablePanelSection = () => { field: 'packageFixVersion', truncateText: true, name: i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerability.column.fixedVersion', + 'xpack.csp.cnvmDashboardTable.section.topVulnerability.column.fixedVersion', { defaultMessage: 'Fix Version', } @@ -295,7 +295,7 @@ export const VulnerabilityTablePanelSection = () => { {i18n.translate( - 'xpack.csp.cvnmDasbhboardTable.section.topVulnerability.column.vulnerabilities', + 'xpack.csp.cnvmDashboardTable.section.topVulnerability.column.vulnerabilities', { defaultMessage: 'Vulnerabilities', } @@ -311,39 +311,36 @@ export const VulnerabilityTablePanelSection = () => { return ( <> - {getCnvmStats.data?.topVulnerableResources && - getCnvmStats.data?.topVulnerableResources?.length > 0 && ( - - - items={getCnvmStats.data?.topVulnerableResources} - columns={topVulnerableResourceColumns} - tableType={DASHBOARD_TABLE_TYPES.TOP_VULNERABLE_RESOURCES} - onViewVulnerabilitiesClick={onViewVulnerabilitiesByResourceClick} - /> - - )} + {!!getVulnerabilityDashboard.data?.topVulnerableResources?.length && ( + + + items={getVulnerabilityDashboard.data?.topVulnerableResources} + columns={topVulnerableResourceColumns} + tableType={DASHBOARD_TABLE_TYPES.TOP_VULNERABLE_RESOURCES} + onViewVulnerabilitiesClick={onViewVulnerabilitiesByResourceClick} + /> + + )} - {getCnvmStats.data?.topPatchableVulnerabilities && - getCnvmStats.data?.topPatchableVulnerabilities?.length > 0 && ( - - items={getCnvmStats.data?.topPatchableVulnerabilities} - columns={topPatchableVulnerabilitiesColumns} - tableType={DASHBOARD_TABLE_TYPES.TOP_PATCH_VULNERABILITIES} - onViewVulnerabilitiesClick={onViewVulnerabilitiesClick} - /> - )} + {!!getVulnerabilityDashboard.data?.topPatchableVulnerabilities?.length && ( + + items={getVulnerabilityDashboard.data?.topPatchableVulnerabilities} + columns={topPatchableVulnerabilitiesColumns} + tableType={DASHBOARD_TABLE_TYPES.TOP_PATCH_VULNERABILITIES} + onViewVulnerabilitiesClick={onViewVulnerabilitiesClick} + /> + )} - {getCnvmStats.data?.topVulnerabilities && - getCnvmStats.data?.topVulnerabilities?.length > 0 && ( - - items={getCnvmStats.data?.topVulnerabilities} - columns={topVulnerabilitiesColumns} - tableType={DASHBOARD_TABLE_TYPES.TOP_VULNERABILITIES} - onViewVulnerabilitiesClick={onViewVulnerabilitiesClick} - /> - )} + {!!getVulnerabilityDashboard.data?.topVulnerabilities?.length && ( + + items={getVulnerabilityDashboard.data?.topVulnerabilities} + columns={topVulnerabilitiesColumns} + tableType={DASHBOARD_TABLE_TYPES.TOP_VULNERABILITIES} + onViewVulnerabilitiesClick={onViewVulnerabilitiesClick} + /> + )} ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_trend_graph.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_trend_graph.tsx new file mode 100644 index 0000000000000..68538ea9210c7 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_trend_graph.tsx @@ -0,0 +1,134 @@ +/* + * Copyright 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 { + Chart, + Settings, + Axis, + BarSeries, + timeFormatter, + niceTimeFormatByDay, + PartialTheme, +} from '@elastic/charts'; +import { EuiButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useNavigateVulnerabilities } from '../../common/hooks/use_navigate_findings'; +import { VulnSeverity } from '../../../common/types'; +import { useVulnerabilityDashboardApi } from '../../common/api/use_vulnerability_dashboard_api'; +import { getSeverityStatusColor } from '../../common/utils/get_vulnerability_colors'; +import { ChartPanel } from '../../components/chart_panel'; +import { VULNERABILITIES_SEVERITY } from '../../../common/constants'; + +const stackAccessors: VulnSeverity[] = [ + VULNERABILITIES_SEVERITY.CRITICAL, + VULNERABILITIES_SEVERITY.HIGH, + VULNERABILITIES_SEVERITY.MEDIUM, + VULNERABILITIES_SEVERITY.LOW, +]; + +const chartStyle = { width: '100%', height: 300 }; + +const theme: PartialTheme = { + scales: { + barsPadding: 0.05, // Maintains low margins between bars when chart is full + }, + legend: { + spacingBuffer: 45, + }, +}; + +const ViewAllButton = () => { + const navToVulnerabilities = useNavigateVulnerabilities(); + + return ( + navToVulnerabilities()} size="s"> + + + ); +}; + +export const VulnerabilityTrendGraph = () => { + const getVulnerabilityDashboard = useVulnerabilityDashboardApi(); + const trendData = getVulnerabilityDashboard.data?.vulnTrends || []; + + const bars: Array<{ + yAccessors: string[]; + color: string; + id: VulnSeverity; + }> = useMemo( + () => [ + { + id: VULNERABILITIES_SEVERITY.CRITICAL, + yAccessors: ['critical'], + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.CRITICAL), + }, + { + id: VULNERABILITIES_SEVERITY.HIGH, + yAccessors: ['high'], + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.HIGH), + }, + { + id: VULNERABILITIES_SEVERITY.MEDIUM, + yAccessors: ['medium'], + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.MEDIUM), + }, + { + id: VULNERABILITIES_SEVERITY.LOW, + yAccessors: ['low'], + color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.LOW), + }, + ], + [] + ); + + return ( + ]} + > +
    + + + + number.toLocaleString()} /> + {bars.map((bar) => ( + + ))} + +
    +
    + ); +}; diff --git a/x-pack/plugins/cloud_security_posture/server/create_indices/benchmark_score_mapping.ts b/x-pack/plugins/cloud_security_posture/server/create_indices/benchmark_score_mapping.ts index b1f3e64521a31..2f743e2ed8d64 100644 --- a/x-pack/plugins/cloud_security_posture/server/create_indices/benchmark_score_mapping.ts +++ b/x-pack/plugins/cloud_security_posture/server/create_indices/benchmark_score_mapping.ts @@ -32,5 +32,20 @@ export const benchmarkScoreMapping: MappingTypeMapping = { 'rule.benchmark.name': { type: 'keyword', }, + policy_template: { + type: 'keyword', + }, + critical: { + type: 'long', + }, + high: { + type: 'long', + }, + medium: { + type: 'long', + }, + low: { + type: 'long', + }, }, }; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/installation_stats_collector.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/installation_stats_collector.ts new file mode 100644 index 0000000000000..6c50bda0d4339 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/installation_stats_collector.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { CoreStart, Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { + AgentPolicy, + PackagePolicy, + PACKAGE_POLICY_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, +} from '@kbn/fleet-plugin/common'; +import { agentPolicyService } from '@kbn/fleet-plugin/server/services'; +import type { CloudSecurityInstallationStats } from './types'; +import type { CspServerPluginStart, CspServerPluginStartDeps } from '../../../types'; +import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../../../../common/constants'; + +export const getInstallationStats = async ( + esClient: ElasticsearchClient, + soClient: SavedObjectsClientContract, + coreServices: Promise<[CoreStart, CspServerPluginStartDeps, CspServerPluginStart]>, + logger: Logger +): Promise => { + const [, cspServerPluginStartDeps] = await coreServices; + + const cspContext = { + logger, + esClient, + soClient, + agentPolicyService: cspServerPluginStartDeps.fleet.agentPolicyService, + packagePolicyService: cspServerPluginStartDeps.fleet.packagePolicyService, + isPluginInitialized, + }; + + const getInstalledPackagePolicies = async ( + packagePolicies: PackagePolicy[], + agentPolicies: AgentPolicy[] + ) => { + const installationStats = await packagePolicies.map( + (packagePolicy: PackagePolicy): CloudSecurityInstallationStats => { + const agentCounts = + agentPolicies?.find((agentPolicy) => agentPolicy?.id === packagePolicy.policy_id) + ?.agents ?? 0; + + return { + package_policy_id: packagePolicy.id, + feature: packagePolicy.vars?.posture?.value as string, + deployment_mode: packagePolicy.vars?.deployment?.value as string, + package_version: packagePolicy.package?.version as string, + created_at: packagePolicy.created_at, + created_by: packagePolicy.created_by, + agent_policy_id: packagePolicy.policy_id, + agent_count: agentCounts, + }; + } + ); + return installationStats; + }; + + const packagePolicies = await cspContext.packagePolicyService.list(soClient, { + perPage: SO_SEARCH_LIMIT, + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name:"${CLOUD_SECURITY_POSTURE_PACKAGE_NAME}"`, + }); + + const agentPolicies = await agentPolicyService.list(soClient, { + perPage: SO_SEARCH_LIMIT, + kuery: '', + esClient, + withAgentCount: true, + }); + if (!packagePolicies) return []; + + const installationStats: CloudSecurityInstallationStats[] = await getInstalledPackagePolicies( + packagePolicies.items, + agentPolicies?.items || [] + ); + + return installationStats; +}; + +const isPluginInitialized = (): boolean => { + return true; +}; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts index dcbab6b2f0607..1b9b4f0370f6b 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/register.ts @@ -14,6 +14,7 @@ import { cspmUsageSchema } from './schema'; import { CspmUsage } from './types'; import { getAccountsStats } from './accounts_stats_collector'; import { getRulesStats } from './rules_stats_collector'; +import { getInstallationStats } from './installation_stats_collector'; export function registerCspmUsageCollector( logger: Logger, @@ -33,23 +34,31 @@ export function registerCspmUsageCollector( return true; }, fetch: async (collectorFetchContext: CollectorFetchContext) => { - const [indicesStats, accountsStats, resourcesStats, rulesStats] = await Promise.all([ - getIndicesStats( - collectorFetchContext.esClient, - collectorFetchContext.soClient, - coreServices, - logger - ), - getAccountsStats(collectorFetchContext.esClient, logger), - getResourcesStats(collectorFetchContext.esClient, logger), - getRulesStats(collectorFetchContext.esClient, logger), - ]); + const [indicesStats, accountsStats, resourcesStats, rulesStats, installationStats] = + await Promise.all([ + getIndicesStats( + collectorFetchContext.esClient, + collectorFetchContext.soClient, + coreServices, + logger + ), + getAccountsStats(collectorFetchContext.esClient, logger), + getResourcesStats(collectorFetchContext.esClient, logger), + getRulesStats(collectorFetchContext.esClient, logger), + getInstallationStats( + collectorFetchContext.esClient, + collectorFetchContext.soClient, + coreServices, + logger + ), + ]); return { indices: indicesStats, accounts_stats: accountsStats, resources_stats: resourcesStats, rules_stats: rulesStats, + installation_stats: installationStats, }; }, schema: cspmUsageSchema, diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts index 4fb7bfee22692..498c7bd846e74 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/schema.ts @@ -143,4 +143,17 @@ export const cspmUsageSchema: MakeSchemaFrom = { failed_findings_count: { type: 'long' }, }, }, + installation_stats: { + type: 'array', + items: { + package_policy_id: { type: 'keyword' }, + feature: { type: 'keyword' }, + package_version: { type: 'keyword' }, + agent_policy_id: { type: 'keyword' }, + deployment_mode: { type: 'keyword' }, + created_at: { type: 'date' }, + created_by: { type: 'keyword' }, + agent_count: { type: 'long' }, + }, + }, }; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts index fe24101dfa8d4..6e6c0a82575dc 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts @@ -12,6 +12,7 @@ export interface CspmUsage { resources_stats: CspmResourcesStats[]; accounts_stats: CspmAccountsStats[]; rules_stats: CspmRulesStats[]; + installation_stats: CloudSecurityInstallationStats[]; } export interface PackageSetupStatus { @@ -76,3 +77,14 @@ export interface CspmRulesStats { passed_findings_count: number; failed_findings_count: number; } + +export interface CloudSecurityInstallationStats { + package_policy_id: string; + feature: string; + package_version: string; + agent_policy_id: string; + deployment_mode: string; + created_at: string; + created_by: string; + agent_count: number; +} diff --git a/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/get_vulnerabilities_trend.ts b/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/get_vulnerabilities_trend.ts new file mode 100644 index 0000000000000..95f52676d09f8 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/get_vulnerabilities_trend.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient } from '@kbn/core/server'; +import { BENCHMARK_SCORE_INDEX_DEFAULT_NS } from '../../../common/constants'; +import { VulnScoreTrend } from '../../../common/types'; + +interface LastDocBucket { + key_as_string: string; + last_doc: { + hits: { + hits: Array<{ + _source: VulnScoreTrend; + }>; + }; + }; +} + +interface VulnScoreTrendResponse { + vuln_severity_per_day: { + buckets: LastDocBucket[]; + }; +} + +export const getVulnTrendsQuery = () => ({ + index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, + size: 0, + query: { + bool: { + must: [ + { + term: { + policy_template: 'vuln_mgmt', + }, + }, + { + range: { + '@timestamp': { + gte: 'now-30d', + lte: 'now', + format: 'strict_date_optional_time', + }, + }, + }, + ], + }, + }, + aggs: { + vuln_severity_per_day: { + date_histogram: { + field: '@timestamp', + calendar_interval: '1d', + order: { + _key: 'asc', + }, + }, + aggs: { + last_doc: { + top_hits: { + size: 1, + sort: [ + { + '@timestamp': { + order: 'desc', + }, + }, + ], + }, + }, + }, + }, + }, +}); + +export const getVulnerabilitiesTrends = async ( + esClient: ElasticsearchClient +): Promise => { + const vulnTrendsQueryResult = await esClient.search( + getVulnTrendsQuery() + ); + if (!vulnTrendsQueryResult.hits.hits) { + throw new Error('Missing trend results from score index'); + } + + const vulnScoreTrendDocs = vulnTrendsQueryResult.aggregations?.vuln_severity_per_day.buckets?.map( + (bucket) => bucket.last_doc.hits.hits[0]._source + ); + + return vulnScoreTrendDocs || []; +}; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts b/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts index ccaa8e6e724ba..be45fefeccd3d 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts @@ -6,6 +6,7 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { getVulnerabilitiesTrends } from './get_vulnerabilities_trend'; import type { CnvmDashboardData } from '../../../common/types'; import { VULNERABILITIES_DASHBOARD_ROUTE_PATH } from '../../../common/constants'; import { getSafeVulnerabilitiesQueryFilter } from '../../../common/utils/get_safe_vulnerabilities_query_filter'; @@ -14,6 +15,7 @@ import { getVulnerabilitiesStatistics } from './get_vulnerabilities_statistics'; import { getTopVulnerableResources } from './get_top_vulnerable_resources'; import { getTopPatchableVulnerabilities } from './get_top_patchable_vulnerabilities'; import { getTopVulnerabilities } from './get_top_vulnerabilities'; + export interface KeyDocCount { key: TKey; doc_count: number; @@ -38,11 +40,13 @@ export const defineGetVulnerabilitiesDashboardRoute = (router: CspRouter): void const [ cnvmStatistics, + vulnTrends, topVulnerableResources, topPatchableVulnerabilities, topVulnerabilities, ] = await Promise.all([ getVulnerabilitiesStatistics(esClient, query), + getVulnerabilitiesTrends(esClient), getTopVulnerableResources(esClient, query), getTopPatchableVulnerabilities(esClient, query), getTopVulnerabilities(esClient, query), @@ -50,6 +54,7 @@ export const defineGetVulnerabilitiesDashboardRoute = (router: CspRouter): void const body: CnvmDashboardData = { cnvmStatistics, + vulnTrends, topVulnerableResources, topPatchableVulnerabilities, topVulnerabilities, diff --git a/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts b/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts index 6f21112efcb90..65b4b0d7572c5 100644 --- a/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts +++ b/x-pack/plugins/cloud_security_posture/server/tasks/findings_stats_task.ts @@ -16,10 +16,18 @@ import { ElasticsearchClient } from '@kbn/core/server'; import type { Logger } from '@kbn/core/server'; import { getSafePostureTypeRuntimeMapping } from '../../common/runtime_mappings/get_safe_posture_type_runtime_mapping'; import { getIdentifierRuntimeMapping } from '../../common/runtime_mappings/get_identifier_runtime_mapping'; -import { FindingsStatsTaskResult, TaskHealthStatus, ScoreByPolicyTemplateBucket } from './types'; +import { + FindingsStatsTaskResult, + TaskHealthStatus, + ScoreByPolicyTemplateBucket, + VulnSeverityAggs, +} from './types'; import { BENCHMARK_SCORE_INDEX_DEFAULT_NS, LATEST_FINDINGS_INDEX_DEFAULT_NS, + LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, + VULNERABILITIES_SEVERITY, + VULN_MGMT_POLICY_TEMPLATE, } from '../../common/constants'; import { scheduleTaskSafe, removeTaskSafe } from '../lib/task_manager_util'; import { CspServerPluginStartServices } from '../types'; @@ -170,6 +178,80 @@ const getScoreQuery = (): SearchRequest => ({ }, }); +const getVulnScoreQuery = (): SearchRequest => ({ + index: LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, + size: 0, + query: { + match_all: {}, + }, + aggs: { + critical: { + filter: { term: { 'vulnerability.severity': VULNERABILITIES_SEVERITY.CRITICAL } }, + }, + high: { + filter: { term: { 'vulnerability.severity': VULNERABILITIES_SEVERITY.HIGH } }, + }, + medium: { + filter: { term: { 'vulnerability.severity': VULNERABILITIES_SEVERITY.MEDIUM } }, + }, + low: { + filter: { term: { 'vulnerability.severity': VULNERABILITIES_SEVERITY.LOW } }, + }, + }, +}); + +const getFindingsScoresDocIndexingPromises = ( + esClient: ElasticsearchClient, + scoresByPolicyTemplatesBuckets: ScoreByPolicyTemplateBucket['score_by_policy_template']['buckets'] +) => + scoresByPolicyTemplatesBuckets.map((policyTemplateTrend) => { + // creating score per cluster id objects + const clustersStats = Object.fromEntries( + policyTemplateTrend.score_by_cluster_id.buckets.map((clusterStats) => { + const clusterId = clusterStats.key; + + return [ + clusterId, + { + total_findings: clusterStats.total_findings.value, + passed_findings: clusterStats.passed_findings.doc_count, + failed_findings: clusterStats.failed_findings.doc_count, + }, + ]; + }) + ); + + // each document contains the policy template and its scores + return esClient.index({ + index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, + document: { + policy_template: policyTemplateTrend.key, + passed_findings: policyTemplateTrend.passed_findings.doc_count, + failed_findings: policyTemplateTrend.failed_findings.doc_count, + total_findings: policyTemplateTrend.total_findings.value, + score_by_cluster_id: clustersStats, + }, + }); + }); + +const getVulnScoresDocIndexingPromises = ( + esClient: ElasticsearchClient, + vulnScoreAggs?: VulnSeverityAggs +) => { + if (!vulnScoreAggs) return; + + return esClient.index({ + index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, + document: { + policy_template: VULN_MGMT_POLICY_TEMPLATE, + critical: vulnScoreAggs.critical.doc_count, + high: vulnScoreAggs.high.doc_count, + medium: vulnScoreAggs.medium.doc_count, + low: vulnScoreAggs.low.doc_count, + }, + }); +}; + export const aggregateLatestFindings = async ( esClient: ElasticsearchClient, stateRuns: number, @@ -180,8 +262,11 @@ export const aggregateLatestFindings = async ( const scoreIndexQueryResult = await esClient.search( getScoreQuery() ); + const vulnScoreIndexQueryResult = await esClient.search( + getVulnScoreQuery() + ); - if (!scoreIndexQueryResult.aggregations) { + if (!scoreIndexQueryResult.aggregations && !vulnScoreIndexQueryResult.aggregations) { logger.warn(`No data found in latest findings index`); return 'warning'; } @@ -195,43 +280,25 @@ export const aggregateLatestFindings = async ( // getting score per policy template buckets const scoresByPolicyTemplatesBuckets = - scoreIndexQueryResult.aggregations.score_by_policy_template.buckets; + scoreIndexQueryResult.aggregations?.score_by_policy_template.buckets || []; // iterating over the buckets and return promises which will index a modified document into the scores index - const docIndexingPromises = scoresByPolicyTemplatesBuckets.map((policyTemplateTrend) => { - // creating score per cluster id objects - const clustersStats = Object.fromEntries( - policyTemplateTrend.score_by_cluster_id.buckets.map((clusterStats) => { - const clusterId = clusterStats.key; - - return [ - clusterId, - { - total_findings: clusterStats.total_findings.value, - passed_findings: clusterStats.passed_findings.doc_count, - failed_findings: clusterStats.failed_findings.doc_count, - }, - ]; - }) - ); - - // each document contains the policy template and its scores - return esClient.index({ - index: BENCHMARK_SCORE_INDEX_DEFAULT_NS, - document: { - policy_template: policyTemplateTrend.key, - passed_findings: policyTemplateTrend.passed_findings.doc_count, - failed_findings: policyTemplateTrend.failed_findings.doc_count, - total_findings: policyTemplateTrend.total_findings.value, - score_by_cluster_id: clustersStats, - }, - }); - }); + const findingsScoresDocIndexingPromises = getFindingsScoresDocIndexingPromises( + esClient, + scoresByPolicyTemplatesBuckets + ); + + const vulnScoresDocIndexingPromises = getVulnScoresDocIndexingPromises( + esClient, + vulnScoreIndexQueryResult.aggregations + ); const startIndexTime = performance.now(); // executing indexing commands - await Promise.all(docIndexingPromises); + await Promise.all( + [...findingsScoresDocIndexingPromises, vulnScoresDocIndexingPromises].filter(Boolean) + ); const totalIndexTime = Number(performance.now() - startIndexTime).toFixed(2); logger.debug( diff --git a/x-pack/plugins/cloud_security_posture/server/tasks/types.ts b/x-pack/plugins/cloud_security_posture/server/tasks/types.ts index 0e2ab6f655d4b..abf5a3b2ac4b7 100644 --- a/x-pack/plugins/cloud_security_posture/server/tasks/types.ts +++ b/x-pack/plugins/cloud_security_posture/server/tasks/types.ts @@ -25,6 +25,21 @@ export interface ScoreByPolicyTemplateBucket { }; } +export interface VulnSeverityAggs { + critical: { + doc_count: number; + }; + high: { + doc_count: number; + }; + medium: { + doc_count: number; + }; + low: { + doc_count: number; + }; +} + export type TaskHealthStatus = 'ok' | 'warning' | 'error'; export interface FindingsStatsTaskResult { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_form.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_form.tsx index 40dd7c428c862..9d7f9841f16f3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_form.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/connector/connector_configuration_form.tsx @@ -50,17 +50,18 @@ export const ConnectorConfigurationForm = () => { items={localConfigView.unCategorizedItems} hasDocumentLevelSecurityEnabled={productFeatures.hasDocumentLevelSecurityEnabled} /> - {localConfigView.categories.map((category) => ( - <> + {localConfigView.categories.map((category, index) => ( +

    {category.label}

    + - +
    ))} diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/explain_log_rate_spike.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/explain_log_rate_spike.tsx index 059abd1a550d6..2aa61bb6dff6e 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/explain_log_rate_spike.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/components/alert_details_app_section/components/explain_log_rate_spike.tsx @@ -13,14 +13,17 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { DataView } from '@kbn/data-views-plugin/common'; -import { ExplainLogRateSpikesContent } from '@kbn/aiops-plugin/public'; - +import { + ExplainLogRateSpikesContent, + type ExplainLogRateSpikesAnalysisResults, +} from '@kbn/aiops-plugin/public'; import { Rule } from '@kbn/alerting-plugin/common'; import { CoPilotPrompt, TopAlert, useCoPilot } from '@kbn/observability-plugin/public'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { i18n } from '@kbn/i18n'; import { CoPilotPromptId } from '@kbn/observability-plugin/common'; import { ALERT_END } from '@kbn/rule-data-utils'; +import { Color, colorTransformer } from '../../../../../../common/color_palette'; import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana'; import { Comparator, @@ -38,6 +41,11 @@ export interface AlertDetailsExplainLogRateSpikesSectionProps { alert: TopAlert>; } +interface FieldValuePair { + field: string; + value: string | number; +} + export const ExplainLogRateSpikes: FC = ({ rule, alert, @@ -46,6 +54,9 @@ export const ExplainLogRateSpikes: FC(); const [esSearchQuery, setEsSearchQuery] = useState(); + const [logSpikeParams, setLogSpikeParams] = useState< + { significantFieldValues: FieldValuePair[] } | undefined + >(); useEffect(() => { const getDataView = async () => { @@ -100,10 +111,6 @@ export const ExplainLogRateSpikes: FC { + const fieldValuePairs = analysisResults?.significantTerms?.map((term) => ({ + field: term.fieldName, + value: term.fieldValue, + })); + setLogSpikeParams( + fieldValuePairs ? { significantFieldValues: fieldValuePairs?.slice(0, 2) } : undefined + ); + }; + + const coPilotService = useCoPilot(); + const hasLogSpikeParams = logSpikeParams && logSpikeParams.significantFieldValues?.length > 0; + if (!dataView || !esSearchQuery) return null; return ( @@ -132,6 +154,8 @@ export const ExplainLogRateSpikes: FC - {coPilotService?.isEnabled() && explainLogSpikeParams ? ( + {coPilotService?.isEnabled() && hasLogSpikeParams ? ( 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 d5779ef4ac81a..620ea06a8edea 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 @@ -71,7 +71,7 @@ import { cloneLayer, getNotifiableFeatures, } from './utils'; -import { isDraggedDataViewField } from '../../utils'; +import { getUniqueLabelGenerator, isDraggedDataViewField } from '../../utils'; import { hasField, normalizeOperationDataType } from './pure_utils'; import { LayerPanel } from './layerpanel'; import { @@ -499,28 +499,15 @@ export function getFormBasedDatasource({ uniqueLabels(state: FormBasedPrivateState) { const layers = state.layers; const columnLabelMap = {} as Record; - const counts = {} as Record; - const makeUnique = (label: string) => { - let uniqueLabel = label; + const uniqueLabelGenerator = getUniqueLabelGenerator(); - while (counts[uniqueLabel] >= 0) { - const num = ++counts[uniqueLabel]; - uniqueLabel = i18n.translate('xpack.lens.indexPattern.uniqueLabel', { - defaultMessage: '{label} [{num}]', - values: { label, num }, - }); - } - - counts[uniqueLabel] = 0; - return uniqueLabel; - }; Object.values(layers).forEach((layer) => { if (!layer.columns) { return; } Object.entries(layer.columns).forEach(([columnId, column]) => { - columnLabelMap[columnId] = makeUnique(column.label); + columnLabelMap[columnId] = uniqueLabelGenerator(column.label); }); }); diff --git a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx index 90ce505b06700..ae0a4d9cf71f9 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx +++ b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx @@ -43,6 +43,7 @@ import type { import { FieldSelect } from './field_select'; import type { Datasource, IndexPatternMap } from '../../types'; import { LayerPanel } from './layerpanel'; +import { getUniqueLabelGenerator } from '../../utils'; function getLayerReferenceName(layerId: string) { return `textBasedLanguages-datasource-layer-${layerId}`; @@ -509,28 +510,14 @@ export function getTextBasedDatasource({ uniqueLabels(state: TextBasedPrivateState) { const layers = state.layers; const columnLabelMap = {} as Record; - const counts = {} as Record; + const uniqueLabelGenerator = getUniqueLabelGenerator(); - const makeUnique = (label: string) => { - let uniqueLabel = label; - - while (counts[uniqueLabel] >= 0) { - const num = ++counts[uniqueLabel]; - uniqueLabel = i18n.translate('xpack.lens.indexPattern.uniqueLabel', { - defaultMessage: '{label} [{num}]', - values: { label, num }, - }); - } - - counts[uniqueLabel] = 0; - return uniqueLabel; - }; Object.values(layers).forEach((layer) => { if (!layer.columns) { return; } Object.values(layer.columns).forEach((column) => { - columnLabelMap[column.columnId] = makeUnique(column.fieldName); + columnLabelMap[column.columnId] = uniqueLabelGenerator(column.fieldName); }); }); diff --git a/x-pack/plugins/lens/public/utils.test.ts b/x-pack/plugins/lens/public/utils.test.ts index d52f6ccc0d2b8..52e509557b2fc 100644 --- a/x-pack/plugins/lens/public/utils.test.ts +++ b/x-pack/plugins/lens/public/utils.test.ts @@ -7,7 +7,7 @@ import { createDatatableUtilitiesMock } from '@kbn/data-plugin/common/mocks'; import { Datatable } from '@kbn/expressions-plugin/public'; -import { inferTimeField, renewIDs } from './utils'; +import { getUniqueLabelGenerator, inferTimeField, renewIDs } from './utils'; const datatableUtilities = createDatatableUtilitiesMock(); @@ -157,4 +157,19 @@ describe('utils', () => { `); }); }); + describe('getUniqueLabelGenerator', () => { + it('should handle empty labels', () => { + expect(getUniqueLabelGenerator()(' ')).toBe('[Untitled]'); + }); + + it('should add a counter for multiple hits of the same label', () => { + const labelGenerator = getUniqueLabelGenerator(); + expect(['myLabel', 'myLabel'].map(labelGenerator)).toEqual(['myLabel', 'myLabel [1]']); + }); + + it('should add a counter for multiple empty labels', () => { + const labelGenerator = getUniqueLabelGenerator(); + expect([' ', ' '].map(labelGenerator)).toEqual(['[Untitled]', '[Untitled] [1]']); + }); + }); }); diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 3838f3b23d44c..518b6c43ea08d 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -19,6 +19,7 @@ import { ClickTriggerEvent, MultiClickTriggerEvent, } from '@kbn/charts-plugin/public'; +import { emptyTitleText } from '@kbn/visualization-ui-components/public'; import { RequestAdapter } from '@kbn/inspector-plugin/common'; import { ISearchStart } from '@kbn/data-plugin/public'; import type { DraggingIdentifier } from '@kbn/dom-drag-drop'; @@ -363,6 +364,28 @@ export const getSearchWarningMessages = ( return [...warningsMap.values()].flat(); }; +function getSafeLabel(label: string) { + return label.trim().length ? label : emptyTitleText; +} + +export function getUniqueLabelGenerator() { + const counts = {} as Record; + return function makeUnique(label: string) { + let uniqueLabel = getSafeLabel(label); + + while (counts[uniqueLabel] >= 0) { + const num = ++counts[uniqueLabel]; + uniqueLabel = i18n.translate('xpack.lens.uniqueLabel', { + defaultMessage: '{label} [{num}]', + values: { label: getSafeLabel(label), num }, + }); + } + + counts[uniqueLabel] = 0; + return uniqueLabel; + }; +} + export function nonNullable(v: T): v is NonNullable { return v != null; } diff --git a/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.tsx b/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.tsx index 3bf619cc76129..ec89021686c6d 100644 --- a/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.tsx +++ b/x-pack/plugins/lens/public/visualizations/xy/annotations/helpers.tsx @@ -18,7 +18,7 @@ import { } from '@kbn/event-annotation-plugin/common'; import { IconChartBarAnnotations } from '@kbn/chart-icons'; import { LayerTypes } from '@kbn/expression-xy-plugin/public'; -import { isDraggedDataViewField } from '../../../utils'; +import { getUniqueLabelGenerator, isDraggedDataViewField } from '../../../utils'; import type { FramePublicAPI, Visualization } from '../../../types'; import { isHorizontalChart } from '../state_helpers'; import type { XYState, XYDataLayerConfig, XYAnnotationLayerConfig, XYLayerConfig } from '../types'; @@ -454,29 +454,15 @@ export const getAnnotationsConfiguration = ({ export const getUniqueLabels = (layers: XYLayerConfig[]) => { const annotationLayers = getAnnotationsLayers(layers); const columnLabelMap = {} as Record; - const counts = {} as Record; - const makeUnique = (label: string) => { - let uniqueLabel = label; - - while (counts[uniqueLabel] >= 0) { - const num = ++counts[uniqueLabel]; - uniqueLabel = i18n.translate('xpack.lens.uniqueLabel', { - defaultMessage: '{label} [{num}]', - values: { label, num }, - }); - } - - counts[uniqueLabel] = 0; - return uniqueLabel; - }; + const uniqueLabelGenerator = getUniqueLabelGenerator(); annotationLayers.forEach((layer) => { if (!layer.annotations) { return; } layer.annotations.forEach((l) => { - columnLabelMap[l.id] = makeUnique(l.label); + columnLabelMap[l.id] = uniqueLabelGenerator(l.label); }); }); return columnLabelMap; diff --git a/x-pack/plugins/observability/common/co_pilot.ts b/x-pack/plugins/observability/common/co_pilot.ts index c96767c2f88d2..758b0c7774eb0 100644 --- a/x-pack/plugins/observability/common/co_pilot.ts +++ b/x-pack/plugins/observability/common/co_pilot.ts @@ -72,14 +72,12 @@ const logEntryRt = t.type({ ), }); -const significantFieldValuesRt = t.type({ - fields: t.array( - t.type({ - field: t.string, - value: t.string, - }) - ), -}); +const significantFieldValuesRt = t.array( + t.type({ + field: t.string, + value: t.union([t.string, t.number]), + }) +); export const coPilotPrompts = { [CoPilotPromptId.ProfilingOptimizeFunction]: prompt({ @@ -311,11 +309,9 @@ export const coPilotPrompts = { }), messages: ({ significantFieldValues }) => { const customMessageForPrompt = - significantFieldValues.fields.length === 1 - ? `There has been an alert on spike of logs. The spike mainly consists of logs with field ${significantFieldValues.fields[0]?.field} with value "${significantFieldValues.fields[0]?.value}".` - : significantFieldValues.fields.length > 1 - ? `There has been an alert on spike of logs. The spike mainly consists of logs with field ${significantFieldValues.fields[0]?.field} with value "${significantFieldValues.fields[0]?.value}" and field ${significantFieldValues.fields[1]?.field} with value "${significantFieldValues.fields[1]?.value}".` - : ''; + significantFieldValues.length === 1 + ? `There has been an alert on spike of logs. The spike mainly consists of logs with field ${significantFieldValues[0]?.field} with value "${significantFieldValues[0]?.value}".` + : `There has been an alert on spike of logs. The spike mainly consists of logs with field ${significantFieldValues[0]?.field} with value "${significantFieldValues[0]?.value}" and field ${significantFieldValues[1]?.field} with value "${significantFieldValues[1]?.value}".`; return [ LOGS_SYSTEM_MESSAGE, { diff --git a/x-pack/plugins/observability/kibana.jsonc b/x-pack/plugins/observability/kibana.jsonc index c60511b3ec6a5..a69ffbd0234f6 100644 --- a/x-pack/plugins/observability/kibana.jsonc +++ b/x-pack/plugins/observability/kibana.jsonc @@ -29,8 +29,8 @@ "unifiedSearch", "visualizations" ], - "optionalPlugins": ["discover", "home", "licensing", "usageCollection"], - "requiredBundles": ["data", "kibanaReact", "kibanaUtils", "unifiedSearch"], + "optionalPlugins": ["discover", "home", "licensing", "usageCollection", "cloud"], + "requiredBundles": ["data", "kibanaReact", "kibanaUtils", "unifiedSearch", "cloudChat"], "extraPublicDirs": ["common"] } } diff --git a/x-pack/plugins/observability/public/application/index.tsx b/x-pack/plugins/observability/public/application/index.tsx index b04dfca154d6b..ea0294f1eca77 100644 --- a/x-pack/plugins/observability/public/application/index.tsx +++ b/x-pack/plugins/observability/public/application/index.tsx @@ -85,43 +85,50 @@ export const renderApp = ({ const ApplicationUsageTrackingProvider = usageCollection?.components.ApplicationUsageTrackingProvider ?? React.Fragment; + const CloudProvider = plugins.cloud?.CloudContextProvider ?? React.Fragment; + ReactDOM.render( - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + , diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx index b1a8d9137d9bf..211fc4bc47d7d 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { waitFor } from '@testing-library/react'; import { timefilterServiceMock } from '@kbn/data-plugin/public/query/timefilter/timefilter_service.mock'; -import { ObservabilityAlertSearchBarProps } from './types'; +import { ObservabilityAlertSearchBarProps, Services } from './types'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; import { observabilityAlertFeatureIds } from '../../config/alert_feature_ids'; import { render } from '../../utils/test_helper'; @@ -17,7 +17,10 @@ const getAlertsSearchBarMock = jest.fn(); const ALERT_SEARCH_BAR_DATA_TEST_SUBJ = 'alerts-search-bar'; describe('ObservabilityAlertSearchBar', () => { - const renderComponent = (props: Partial = {}) => { + const renderComponent = ( + props: Partial = {}, + services: Partial = {} + ) => { const observabilityAlertSearchBarProps: ObservabilityAlertSearchBarProps = { appName: 'testAppName', kuery: '', @@ -35,6 +38,7 @@ describe('ObservabilityAlertSearchBar', () => {
    ), useToasts: jest.fn(), + ...services, }, ...props, }; @@ -152,4 +156,26 @@ describe('ObservabilityAlertSearchBar', () => { }, }); }); + + it('should show error in a toast', async () => { + const error = new Error('something is wrong in esQueryChange'); + const mockedOnEsQueryChange = jest.fn().mockImplementation(() => { + throw error; + }); + const mockedAddError = jest.fn(); + const mockedUseToast = jest.fn().mockImplementation(() => ({ + addError: mockedAddError, + })); + + renderComponent( + { + onEsQueryChange: mockedOnEsQueryChange, + }, + { + useToasts: mockedUseToast, + } + ); + + expect(mockedAddError).toHaveBeenCalledWith(error, { title: 'Invalid query string' }); + }); }); diff --git a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx index 3922b8eeff5cf..bf4d190837850 100644 --- a/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability/public/components/alert_search_bar/alert_search_bar.tsx @@ -22,6 +22,9 @@ const getAlertStatusQuery = (status: string): Query[] => { ? [{ query: ALERT_STATUS_QUERY[status], language: 'kuery' }] : []; }; +const toastTitle = i18n.translate('xpack.observability.alerts.searchBar.invalidQueryTitle', { + defaultMessage: 'Invalid query string', +}); export function ObservabilityAlertSearchBar({ appName, @@ -41,18 +44,25 @@ export function ObservabilityAlertSearchBar({ const onAlertStatusChange = useCallback( (alertStatus: AlertStatus) => { - onEsQueryChange( - buildEsQuery( - { - to: rangeTo, - from: rangeFrom, - }, - kuery, - [...getAlertStatusQuery(alertStatus), ...defaultSearchQueries] - ) - ); + try { + onEsQueryChange( + buildEsQuery( + { + to: rangeTo, + from: rangeFrom, + }, + kuery, + [...getAlertStatusQuery(alertStatus), ...defaultSearchQueries] + ) + ); + } catch (error) { + toasts.addError(error, { + title: toastTitle, + }); + onKueryChange(DEFAULT_QUERY_STRING); + } }, - [kuery, defaultSearchQueries, rangeFrom, rangeTo, onEsQueryChange] + [onEsQueryChange, rangeTo, rangeFrom, kuery, defaultSearchQueries, toasts, onKueryChange] ); useEffect(() => { @@ -83,9 +93,7 @@ export function ObservabilityAlertSearchBar({ onEsQueryChange(esQuery); } catch (error) { toasts.addError(error, { - title: i18n.translate('xpack.observability.alerts.searchBar.invalidQueryTitle', { - defaultMessage: 'Invalid query string', - }), + title: toastTitle, }); onKueryChange(DEFAULT_QUERY_STRING); } diff --git a/x-pack/plugins/observability/public/pages/alert_details/components/page_title.tsx b/x-pack/plugins/observability/public/pages/alert_details/components/page_title.tsx index a2e47ac4ccf16..263df29bc04cb 100644 --- a/x-pack/plugins/observability/public/pages/alert_details/components/page_title.tsx +++ b/x-pack/plugins/observability/public/pages/alert_details/components/page_title.tsx @@ -29,6 +29,7 @@ import moment from 'moment'; import { css } from '@emotion/react'; import { asDuration } from '../../../../common/utils/formatters'; import { TopAlert } from '../../../typings/alerts'; +import { ExperimentalBadge } from '../../../components/experimental_badge'; export interface PageTitleProps { alert: TopAlert | null; @@ -49,9 +50,17 @@ export function PageTitle({ alert }: PageTitleProps) { if (!alert) return ; + const showExperimentalBadge = + alert.fields[ALERT_RULE_CATEGORY] === 'Log threshold' || + alert.fields[ALERT_RULE_CATEGORY] === 'Metric threshold' || + alert.fields[ALERT_RULE_CATEGORY] === 'Inventory'; + return (
    - {pageTitleContent(alert.fields[ALERT_RULE_CATEGORY])} + + {pageTitleContent(alert.fields[ALERT_RULE_CATEGORY])} + {showExperimentalBadge && } + diff --git a/x-pack/plugins/observability/public/pages/overview/overview.tsx b/x-pack/plugins/observability/public/pages/overview/overview.tsx index 5212897a5c53c..a938cdc98023e 100644 --- a/x-pack/plugins/observability/public/pages/overview/overview.tsx +++ b/x-pack/plugins/observability/public/pages/overview/overview.tsx @@ -11,6 +11,7 @@ import { BoolQuery } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { useBreadcrumbs, useFetcher } from '@kbn/observability-shared-plugin/public'; +import { Chat } from '@kbn/cloud-chat-plugin/public'; import { useKibana } from '../../utils/kibana_react'; import { LoadingObservability } from '../../components/loading_observability'; @@ -240,6 +241,8 @@ export function OverviewPage() { {isDataAssistantFlyoutVisible ? ( setIsDataAssistantFlyoutVisible(false)} /> ) : null} + + ); } diff --git a/x-pack/plugins/observability/public/plugin.ts b/x-pack/plugins/observability/public/plugin.ts index f0b515f554973..fd6300eff8caa 100644 --- a/x-pack/plugins/observability/public/plugin.ts +++ b/x-pack/plugins/observability/public/plugin.ts @@ -26,6 +26,7 @@ import type { DiscoverStart } from '@kbn/discover-plugin/public'; import type { EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { HomePublicPluginSetup, HomePublicPluginStart } from '@kbn/home-plugin/public'; import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import type { CloudStart } from '@kbn/cloud-plugin/public'; import type { ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, @@ -117,6 +118,7 @@ export interface ObservabilityPublicPluginsStart { usageCollection: UsageCollectionSetup; unifiedSearch: UnifiedSearchPublicPluginStart; home?: HomePublicPluginStart; + cloud?: CloudStart; } export type ObservabilityPublicStart = ReturnType; diff --git a/x-pack/plugins/observability/server/index.ts b/x-pack/plugins/observability/server/index.ts index 6a5d905bb6f60..1bdacac1aee58 100644 --- a/x-pack/plugins/observability/server/index.ts +++ b/x-pack/plugins/observability/server/index.ts @@ -19,6 +19,7 @@ import { WrappedElasticsearchClientError, } from '../common/utils/unwrap_es_response'; import { observabilityCoPilotConfig } from './services/openai/config'; + export { rangeQuery, kqlQuery, termQuery, termsQuery } from './utils/queries'; export { getInspectResponse } from '../common/utils/get_inspect_response'; @@ -35,7 +36,8 @@ const configSchema = schema.object({ enabled: schema.boolean({ defaultValue: false }), }), logs: schema.object({ - enabled: schema.boolean({ defaultValue: false }), + // Enable it by default: https://github.com/elastic/kibana/issues/159945 + enabled: schema.boolean({ defaultValue: true }), }), uptime: schema.object({ enabled: schema.boolean({ defaultValue: false }), diff --git a/x-pack/plugins/observability/tsconfig.json b/x-pack/plugins/observability/tsconfig.json index 4adbf40cd1d94..77f668338ba35 100644 --- a/x-pack/plugins/observability/tsconfig.json +++ b/x-pack/plugins/observability/tsconfig.json @@ -75,7 +75,9 @@ "@kbn/ui-actions-plugin", "@kbn/field-types", "@kbn/safer-lodash-set", - "@kbn/core-http-server" + "@kbn/core-http-server", + "@kbn/cloud-chat-plugin", + "@kbn/cloud-plugin" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/profiling/README.md b/x-pack/plugins/profiling/README.md index 4b2108cc6779e..869bba9fb1a1b 100644 --- a/x-pack/plugins/profiling/README.md +++ b/x-pack/plugins/profiling/README.md @@ -1 +1,79 @@ -### TODO +# Universal Profiling (Beta) + +## Overview +Universal Profiling provides fleet-wide, whole-system, continuous profiling with zero instrumentation. Get a comprehensive understanding of what lines of code are consuming compute resources throughout your entire fleet by visualizing your data in Kibana using the flamegraph, stacktraces, and top functions views. + +### Universal profiling setup +Universal Profiling is enabled by default on [Elastic Cloud](https://www.elastic.co/cloud/), and you can find it under **Observability**. To see data in Universal Profiling, you need to initialize it. + +##### **Initialize Universal Profiling** +Initialize Universal Profiling by navigating to one of the views and clicking the **Set up** button. Clicking this will trigger some checks and install some packages so data can be processed. + +The following are some of the actions and checks that occur during initialization: +- Check that the APM integration is installed and configured. +- Create Universal Profiling indices. +- Install the Collector integration. +- Install the Symbolizer integration. + +### Collector integration +The Collector is the component that receives data from the profiling agents deployed on users machines. + +It runs a gRPC server over HTTPS and exposes an endpoint where the profiling agents can send data. + +To send data, agents are required to use a token-based authentication, referred as `secretToken` in the agent configurations. + +The token is generated by Kibana during the setup process and at the moment cannot be configured by users. + +The "Add Data" page will display instructions for several deployment methodologies. +The instructions contain both the endpoint and the token that allow profiling agent to connect to the Collector. + +### Symbolizer integration +The Symbolizer is the component processing debug symbols for the received profiles data, enriching with source-code metadata the profiling visualizations. + +It processes both publicly-available debug symbols and "private" debug symbols. + +For public symbols, users don't have to do anything: the symbolizer asynchronously intercepts unsymbolized frames and populates them automatically. + +For private symbols, an HTTPS endpoint is provided to users for uploading the debug symbols of the software they own. + +The authentication and authorization on this endpoint are provided as part of the request, in form of an Elasticsearch API key. + + +## Testing (unit, e2e) +### Unit Tests (Jest) + +``` +node scripts/jest --config x-pack/plugins/profiling/jest.config.js [--watchAll] +``` + +## E2E Tests (Cypress) +The E2E tests are located in [`x-pack/plugins/profiling/e2e`](./e2e). + +Universal Profiling uses [FTR](../../../packages/kbn-test/README.mdx) (functional test runner) and [Cypress](https://www.cypress.io/) to run the e2e tests. The tests are located at `kibana/x-pack/plugins/profiling/e2e/cypress/e2e`. + +### Start test server + +``` +node x-pack/plugins/profiling/scripts/test/e2e --server +``` + +### Open cypress dashboard + +``` +node x-pack/plugins/profiling/scripts/test/e2e --open +``` + +### Run tests in terminal + +``` +node x-pack/plugins/profiling/scripts/test/e2e --runner +``` + +### Run like CI + +``` +node x-pack/plugins/profiling/scripts/test/e2e +``` + +## Other resources +- [Official Profiling documentation](https://www.elastic.co/observability/universal-profiling) \ No newline at end of file diff --git a/x-pack/plugins/profiling/kibana.jsonc b/x-pack/plugins/profiling/kibana.jsonc index bf7f17fb5e5ec..354716906a0d1 100644 --- a/x-pack/plugins/profiling/kibana.jsonc +++ b/x-pack/plugins/profiling/kibana.jsonc @@ -7,22 +7,22 @@ "server": true, "browser": true, "configPath": ["xpack", "profiling"], + "optionalPlugins": ["spaces"], "requiredPlugins": [ - "navigation", + "charts", + "cloud", "data", - "kibanaUtils", - "share", + "dataViews", + "features", + "fleet", + "licensing", "observability", "observabilityShared", - "features", - "kibanaReact", "unifiedSearch", - "dataViews", - "charts", - "spaces", - "cloud", - "fleet", - "licensing" + ], + "requiredBundles": [ + "kibanaReact", + "kibanaUtils", ] } } diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/key_value_list.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/key_value_list.tsx index 4dc6909173e63..9ac9866bd9ae9 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/key_value_list.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/key_value_list.tsx @@ -24,7 +24,8 @@ export function KeyValueList({ rows, prependString = '' }: Props) { {row.label}: - {`${prependString}row.value`} + {prependString} + {row.value} diff --git a/x-pack/plugins/profiling/public/views/no_data_view/index.tsx b/x-pack/plugins/profiling/public/views/no_data_view/index.tsx index 0b2adac22a2a0..01d4f80d40795 100644 --- a/x-pack/plugins/profiling/public/views/no_data_view/index.tsx +++ b/x-pack/plugins/profiling/public/views/no_data_view/index.tsx @@ -41,9 +41,9 @@ export function NoDataView({ subTitle }: { subTitle: string }) { [setupDataCollectionInstructions] ); - const secretToken = data?.variables.collector.secretToken; - const collectionAgentHost = data?.variables.collector.host.replace('https://', ''); - const symbolUrl = data?.variables.symbolizer.host.replace('https://', ''); + const secretToken = data?.collector?.secretToken; + const collectionAgentHost = data?.collector?.host; + const symbolUrl = data?.symbolizer?.host; const hostAgentVersion = 'v3'; const tabs = [ diff --git a/x-pack/plugins/profiling/server/feature.ts b/x-pack/plugins/profiling/server/feature.ts index ec382952363df..13e064364b7b8 100644 --- a/x-pack/plugins/profiling/server/feature.ts +++ b/x-pack/plugins/profiling/server/feature.ts @@ -18,26 +18,25 @@ export const PROFILING_FEATURE = { order: 1200, category: DEFAULT_APP_CATEGORIES.observability, app: [PROFILING_SERVER_FEATURE_ID, 'ux', 'kibana'], - catalogue: [PROFILING_SERVER_FEATURE_ID], // see x-pack/plugins/features/common/feature_kibana_privileges.ts privileges: { all: { app: [PROFILING_SERVER_FEATURE_ID, 'ux', 'kibana'], - catalogue: [PROFILING_SERVER_FEATURE_ID], savedObject: { all: [], read: [], }, ui: ['show'], + api: [PROFILING_SERVER_FEATURE_ID], }, read: { app: [PROFILING_SERVER_FEATURE_ID, 'ux', 'kibana'], - catalogue: [PROFILING_SERVER_FEATURE_ID], savedObject: { all: [], read: [], }, ui: ['show'], + api: [PROFILING_SERVER_FEATURE_ID], }, }, }; diff --git a/x-pack/plugins/profiling/server/index.ts b/x-pack/plugins/profiling/server/index.ts index c4092e0fb598f..ea2b008c6a590 100644 --- a/x-pack/plugins/profiling/server/index.ts +++ b/x-pack/plugins/profiling/server/index.ts @@ -9,9 +9,14 @@ import { schema, TypeOf } from '@kbn/config-schema'; import type { PluginConfigDescriptor, PluginInitializerContext } from '@kbn/core/server'; import { ProfilingPlugin } from './plugin'; +/** + * These properties are used to create both the Collector and the Symbolizer integrations + * when Universal Profiling is initialized. + * As of now Universal Profiling is only availble on Elastic Cloud, so + * Elastic Cloud will be responsable of filling these properties up and pass it to Kibana. + */ const packageInputSchema = schema.object({ host: schema.maybe(schema.string()), - secret_token: schema.maybe(schema.string()), tls_enabled: schema.maybe(schema.boolean()), tls_supported_protocols: schema.maybe(schema.arrayOf(schema.string())), tls_certificate_path: schema.maybe(schema.string()), @@ -22,12 +27,17 @@ const configSchema = schema.object({ enabled: schema.boolean({ defaultValue: false }), symbolizer: schema.maybe(packageInputSchema), collector: schema.maybe(packageInputSchema), - elasticsearch: schema.maybe( - schema.object({ - hosts: schema.string(), - username: schema.string(), - password: schema.string(), - }) + elasticsearch: schema.conditional( + schema.contextRef('dist'), + schema.literal(true), + schema.never(), + schema.maybe( + schema.object({ + hosts: schema.string(), + username: schema.string(), + password: schema.string(), + }) + ) ), }); diff --git a/x-pack/plugins/profiling/server/lib/setup/fleet_policies.test.ts b/x-pack/plugins/profiling/server/lib/setup/fleet_policies.test.ts index a62cf6100d2de..66e30bbaa3d91 100644 --- a/x-pack/plugins/profiling/server/lib/setup/fleet_policies.test.ts +++ b/x-pack/plugins/profiling/server/lib/setup/fleet_policies.test.ts @@ -50,33 +50,6 @@ describe('getVarsFor', () => { }); }); - it('discards secret_token defined and generate a new one', () => { - const config: PackageInputType = { - host: 'example.com', - tls_enabled: true, - tls_supported_protocols: ['foo', 'bar'], - tls_certificate_path: '123', - tls_key_path: '456', - secret_token: 'bar!', - }; - - const { secret_token: secretToken, ...result } = getVarsFor({ - config, - includeSecretToken: true, - }); - expect(secretToken?.type).toBe('text'); - expect(secretToken?.value).not.toBe('bar!'); - expect(secretToken?.value.length).toBe(16); - expect(secretTokenRegex.test(secretToken?.value)).toBeTruthy(); - expect(result).toEqual({ - host: { type: 'text', value: 'example.com' }, - tls_enabled: { type: 'bool', value: true }, - tls_supported_protocols: { type: 'text', value: ['foo', 'bar'] }, - tls_certificate_path: { type: 'text', value: '123' }, - tls_key_path: { type: 'text', value: '456' }, - }); - }); - it('returns vars without secret_token', () => { const config: PackageInputType = { host: 'example.com', diff --git a/x-pack/plugins/profiling/server/lib/setup/fleet_policies.ts b/x-pack/plugins/profiling/server/lib/setup/fleet_policies.ts index 7240447a43861..3908817e95db6 100644 --- a/x-pack/plugins/profiling/server/lib/setup/fleet_policies.ts +++ b/x-pack/plugins/profiling/server/lib/setup/fleet_policies.ts @@ -161,6 +161,7 @@ export function generateSecretToken() { return result; } +type PackagePolicyVars = PackageInputType & { secret_token?: string }; export function getVarsFor({ config, includeSecretToken, @@ -168,13 +169,13 @@ export function getVarsFor({ config: PackageInputType; includeSecretToken: boolean; }) { - const configKeys = Object.keys(config) as Array; + const configKeys = Object.keys(config) as Array; if (includeSecretToken) { configKeys.push('secret_token'); } return configKeys.reduce< - Partial> + Partial> >((acc, currKey) => { const value = currKey === 'secret_token' ? generateSecretToken() : config[currKey]; const type = typeof value === 'boolean' ? 'bool' : 'text'; diff --git a/x-pack/plugins/profiling/server/lib/setup/get_setup_instructions.ts b/x-pack/plugins/profiling/server/lib/setup/get_setup_instructions.ts index f14424f61141f..df6da32a11b86 100644 --- a/x-pack/plugins/profiling/server/lib/setup/get_setup_instructions.ts +++ b/x-pack/plugins/profiling/server/lib/setup/get_setup_instructions.ts @@ -7,52 +7,44 @@ import { SavedObjectsClientContract } from '@kbn/core/server'; import { PackagePolicyClient } from '@kbn/fleet-plugin/server'; -import { getCollectorPolicy, getSymbolizerPolicy } from './fleet_policies'; +import { getCollectorPolicy } from './fleet_policies'; export interface SetupDataCollectionInstructions { - variables: { - collector: { - secretToken: string; - host: string; - }; - symbolizer: { - host: string; - }; + collector: { + secretToken?: string; + host?: string; + }; + symbolizer: { + host?: string; }; } export async function getSetupInstructions({ packagePolicyClient, soClient, + apmServerHost, }: { packagePolicyClient: PackagePolicyClient; soClient: SavedObjectsClientContract; + apmServerHost?: string; }): Promise { - const [collectorPolicy, symbolizerPolicy] = await Promise.all([ - getCollectorPolicy({ packagePolicyClient, soClient }), - getSymbolizerPolicy({ packagePolicyClient, soClient }), - ]); + const collectorPolicy = await getCollectorPolicy({ packagePolicyClient, soClient }); if (!collectorPolicy) { throw new Error('Could not find Collector policy'); } - if (!symbolizerPolicy) { - throw new Error('Could not find Symbolizer policy'); - } - const collectorVars = collectorPolicy.inputs[0].vars; - const symbolizerVars = symbolizerPolicy.inputs[0].vars; + const symbolizerHost = apmServerHost?.replace(/\.apm\./, '.symbols.'); + const collectorHost = apmServerHost?.replace(/\.apm\./, '.profiling.')?.replace('https://', ''); return { - variables: { - collector: { - secretToken: collectorVars!.secret_token.value!, - host: collectorVars!.host.value, - }, - symbolizer: { - host: symbolizerVars!.host.value, - }, + collector: { + secretToken: collectorVars?.secret_token?.value, + host: collectorHost, + }, + symbolizer: { + host: symbolizerHost, }, }; } diff --git a/x-pack/plugins/profiling/server/plugin.ts b/x-pack/plugins/profiling/server/plugin.ts index a0792c075b54b..b7e13c02c48b8 100644 --- a/x-pack/plugins/profiling/server/plugin.ts +++ b/x-pack/plugins/profiling/server/plugin.ts @@ -35,7 +35,6 @@ export class ProfilingPlugin } public setup(core: CoreSetup, deps: ProfilingPluginSetupDeps) { - this.logger.debug('profiling: Setup'); const router = core.http.createRouter(); deps.features.registerKibanaFeature(PROFILING_FEATURE); @@ -80,7 +79,6 @@ export class ProfilingPlugin } public start(core: CoreStart) { - this.logger.debug('profiling: Started'); return {}; } diff --git a/x-pack/plugins/profiling/server/routes/downsampling.ts b/x-pack/plugins/profiling/server/routes/downsampling.ts index fd297ac92f4b8..2c0fe5dc6aee0 100644 --- a/x-pack/plugins/profiling/server/routes/downsampling.ts +++ b/x-pack/plugins/profiling/server/routes/downsampling.ts @@ -87,9 +87,8 @@ export async function findDownsampledIndex({ }); sampleCountFromInitialExp = resp.hits.total.value; } catch (e) { - logger.info(e.message); + logger.error(e.message); } - logger.info('sampleCountFromPow6 ' + sampleCountFromInitialExp); return getSampledTraceEventsIndex(index, sampleSize, sampleCountFromInitialExp, initialExp); } diff --git a/x-pack/plugins/profiling/server/routes/flamechart.ts b/x-pack/plugins/profiling/server/routes/flamechart.ts index 3b33267892e0e..784dcb888271a 100644 --- a/x-pack/plugins/profiling/server/routes/flamechart.ts +++ b/x-pack/plugins/profiling/server/routes/flamechart.ts @@ -26,6 +26,7 @@ export function registerFlameChartSearchRoute({ router.get( { path: paths.Flamechart, + options: { tags: ['access:profiling'] }, validate: { query: schema.object({ timeFrom: schema.number(), @@ -48,7 +49,6 @@ export function registerFlameChartSearchRoute({ }); const totalSeconds = timeTo - timeFrom; - const t0 = Date.now(); const { stackTraceEvents, stackTraces, @@ -61,10 +61,8 @@ export function registerFlameChartSearchRoute({ filter, sampleSize: targetSampleSize, }); - logger.info(`querying stacktraces took ${Date.now() - t0} ms`); const flamegraph = await withProfilingSpan('create_flamegraph', async () => { - const t1 = Date.now(); const tree = createCalleeTree( stackTraceEvents, stackTraces, @@ -73,20 +71,20 @@ export function registerFlameChartSearchRoute({ totalFrames, samplingRate ); - logger.info(`creating callee tree took ${Date.now() - t1} ms`); - const t2 = Date.now(); const fg = createBaseFlameGraph(tree, samplingRate, totalSeconds); - logger.info(`creating flamegraph took ${Date.now() - t2} ms`); return fg; }); - logger.info('returning payload response to client'); - return response.ok({ body: flamegraph }); } catch (error) { - return handleRouteHandlerError({ error, logger, response }); + return handleRouteHandlerError({ + error, + logger, + response, + message: 'Error while fetching flamegraph', + }); } } ); diff --git a/x-pack/plugins/profiling/server/routes/functions.ts b/x-pack/plugins/profiling/server/routes/functions.ts index 52790c7a9b35b..d65bf33056930 100644 --- a/x-pack/plugins/profiling/server/routes/functions.ts +++ b/x-pack/plugins/profiling/server/routes/functions.ts @@ -34,6 +34,7 @@ export function registerTopNFunctionsSearchRoute({ router.get( { path: paths.TopNFunctions, + options: { tags: ['access:profiling'] }, validate: { query: querySchema, }, @@ -51,16 +52,13 @@ export function registerTopNFunctionsSearchRoute({ kuery, }); - const t0 = Date.now(); const { stackTraceEvents, stackTraces, executables, stackFrames, samplingRate } = await searchStackTraces({ client: profilingElasticsearchClient, filter, sampleSize: targetSampleSize, }); - logger.info(`querying stacktraces took ${Date.now() - t0} ms`); - const t1 = Date.now(); const topNFunctions = await withProfilingSpan('create_topn_functions', async () => { return createTopNFunctions( stackTraceEvents, @@ -72,15 +70,17 @@ export function registerTopNFunctionsSearchRoute({ samplingRate ); }); - logger.info(`creating topN functions took ${Date.now() - t1} ms`); - - logger.info('returning payload response to client'); return response.ok({ body: topNFunctions, }); } catch (error) { - return handleRouteHandlerError({ error, logger, response }); + return handleRouteHandlerError({ + error, + logger, + response, + message: 'Error while fetching TopN functions', + }); } } ); diff --git a/x-pack/plugins/profiling/server/routes/logger.ts b/x-pack/plugins/profiling/server/routes/logger.ts deleted file mode 100644 index 181479eccd8d9..0000000000000 --- a/x-pack/plugins/profiling/server/routes/logger.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { Logger } from '@kbn/core/server'; - -export async function logExecutionLatency( - logger: Logger, - activity: string, - func: () => Promise -): Promise { - const start = Date.now(); - return await func().then((res) => { - logger.info(activity + ' took ' + (Date.now() - start) + 'ms'); - return res; - }); -} diff --git a/x-pack/plugins/profiling/server/routes/setup.ts b/x-pack/plugins/profiling/server/routes/setup.ts index 9166d9a8c7bee..67e1d9dacdfc9 100644 --- a/x-pack/plugins/profiling/server/routes/setup.ts +++ b/x-pack/plugins/profiling/server/routes/setup.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import { RouteRegisterParameters } from '.'; import { getClient } from './compat'; import { installLatestApmPackage, isApmPackageInstalled } from '../lib/setup/apm_package'; @@ -45,6 +46,7 @@ export function registerSetupRoute({ router.get( { path: paths.HasSetupESResources, + options: { tags: ['access:profiling'] }, validate: false, }, async (context, request, response) => { @@ -56,18 +58,18 @@ export function registerSetupRoute({ request, useDefaultAuth: true, }); + const setupOptions: ProfilingSetupOptions = { client: clientWithDefaultAuth, logger, packagePolicyClient: dependencies.start.fleet.packagePolicyService, soClient: core.savedObjects.client, - spaceId: dependencies.setup.spaces.spacesService.getSpaceId(request), + spaceId: + dependencies.setup.spaces?.spacesService?.getSpaceId(request) ?? DEFAULT_SPACE_ID, isCloudEnabled: dependencies.setup.cloud.isCloudEnabled, config: dependencies.config, }; - logger.info('Checking if Elasticsearch and Fleet are setup for Universal Profiling'); - const state = createDefaultSetupState(); state.cloud.available = dependencies.setup.cloud.isCloudEnabled; @@ -102,7 +104,12 @@ export function registerSetupRoute({ }, }); } catch (error) { - return handleRouteHandlerError({ error, logger, response }); + return handleRouteHandlerError({ + error, + logger, + response, + message: 'Error while checking plugin setup', + }); } } ); @@ -110,7 +117,8 @@ export function registerSetupRoute({ router.post( { path: paths.HasSetupESResources, - validate: {}, + options: { tags: ['access:profiling'] }, + validate: false, }, async (context, request, response) => { try { @@ -126,13 +134,12 @@ export function registerSetupRoute({ logger, packagePolicyClient: dependencies.start.fleet.packagePolicyService, soClient: core.savedObjects.client, - spaceId: dependencies.setup.spaces.spacesService.getSpaceId(request), + spaceId: + dependencies.setup.spaces?.spacesService?.getSpaceId(request) ?? DEFAULT_SPACE_ID, isCloudEnabled: dependencies.setup.cloud.isCloudEnabled, config: dependencies.config, }; - logger.info('Setting up Elasticsearch and Fleet for Universal Profiling'); - const state = createDefaultSetupState(); state.cloud.available = dependencies.setup.cloud.isCloudEnabled; @@ -179,7 +186,12 @@ export function registerSetupRoute({ // and is not guaranteed to complete before Kibana sends a response. return response.accepted(); } catch (error) { - return handleRouteHandlerError({ error, logger, response }); + return handleRouteHandlerError({ + error, + logger, + response, + message: 'Error while setting up Universal Profiling', + }); } } ); @@ -187,18 +199,26 @@ export function registerSetupRoute({ router.get( { path: paths.SetupDataCollectionInstructions, + options: { tags: ['access:profiling'] }, validate: false, }, async (context, request, response) => { try { + const apmServerHost = dependencies.setup.cloud?.apm?.url; const setupInstructions = await getSetupInstructions({ packagePolicyClient: dependencies.start.fleet.packagePolicyService, soClient: (await context.core).savedObjects.client, + apmServerHost, }); return response.ok({ body: setupInstructions }); } catch (error) { - return handleRouteHandlerError({ error, logger, response }); + return handleRouteHandlerError({ + error, + logger, + response, + message: 'Error while fetching Universal Profiling instructions', + }); } } ); diff --git a/x-pack/plugins/profiling/server/routes/topn.ts b/x-pack/plugins/profiling/server/routes/topn.ts index 7f0b1d39c306f..ac4621cf0ed14 100644 --- a/x-pack/plugins/profiling/server/routes/topn.ts +++ b/x-pack/plugins/profiling/server/routes/topn.ts @@ -100,7 +100,6 @@ export async function topNElasticSearchQuery({ } let totalSampledStackTraces = aggregations.total_count.value ?? 0; - logger.info('total sampled stacktraces: ' + totalSampledStackTraces); totalSampledStackTraces = Math.floor(totalSampledStackTraces / eventsIndex.sampleRate); if (searchField !== ProfilingESField.StacktraceID) { @@ -139,8 +138,6 @@ export async function topNElasticSearchQuery({ return groupStackFrameMetadataByStackTrace(stackTraces, stackFrames, executables); }); - logger.info('returning payload response to client'); - return { TotalCount: totalSampledStackTraces, TopN: topN, @@ -164,6 +161,7 @@ export function queryTopNCommon({ router.get( { path: pathName, + options: { tags: ['access:profiling'] }, validate: { query: schema.object({ timeFrom: schema.number(), @@ -189,7 +187,12 @@ export function queryTopNCommon({ }), }); } catch (error) { - return handleRouteHandlerError({ error, logger, response }); + return handleRouteHandlerError({ + error, + logger, + response, + message: 'Error while fetching TopN functions', + }); } } ); diff --git a/x-pack/plugins/profiling/server/types.ts b/x-pack/plugins/profiling/server/types.ts index 6112c2e9790cf..2fe87e18a545b 100644 --- a/x-pack/plugins/profiling/server/types.ts +++ b/x-pack/plugins/profiling/server/types.ts @@ -15,17 +15,17 @@ import { FleetSetupContract, FleetStartContract } from '@kbn/fleet-plugin/server export interface ProfilingPluginSetupDeps { observability: ObservabilityPluginSetup; features: FeaturesPluginSetup; - spaces: SpacesPluginSetup; cloud: CloudSetup; fleet: FleetSetupContract; + spaces?: SpacesPluginSetup; } export interface ProfilingPluginStartDeps { observability: {}; features: {}; - spaces: SpacesPluginStart; cloud: CloudStart; fleet: FleetStartContract; + spaces?: SpacesPluginStart; } // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts b/x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts index 782beeeae15cb..6e50953877550 100644 --- a/x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts +++ b/x-pack/plugins/profiling/server/utils/handle_route_error_handler.ts @@ -14,10 +14,12 @@ export function handleRouteHandlerError({ error, logger, response, + message, }: { error: any; response: KibanaResponseFactory; logger: Logger; + message: string; }) { if ( error instanceof WrappedElasticsearchClientError && @@ -34,8 +36,6 @@ export function handleRouteHandlerError({ return response.customError({ statusCode: error.statusCode ?? 500, - body: { - message: error.message, - }, + body: { message }, }); } diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index ed9afb7fa9518..079ad8434f445 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -82,7 +82,7 @@ export const allowedExperimentalValues = Object.freeze({ securityFlyoutEnabled: false, /** - * Enables the Elastic Security Assistant + * Enables the Elastic AI Assistant */ assistantEnabled: false, diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/row_renderers.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/row_renderers.cy.ts index 9a0a07bb97f06..9ae5993f8b80c 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/row_renderers.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/investigations/timelines/row_renderers.cy.ts @@ -15,7 +15,13 @@ import { TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE_TOOLTIP, TIMELINE_ROW_RENDERERS_SURICATA_LINK_TOOLTIP, } from '../../../screens/timeline'; -import { cleanKibana, deleteTimelines } from '../../../tasks/common'; +import { + cleanKibana, + deleteTimelines, + waitForPageToBeLoaded, + waitForWelcomePanelToBeLoaded, +} from '../../../tasks/common'; +import { waitForAllHostsToBeLoaded } from '../../../tasks/hosts/all_hosts'; import { login, visit } from '../../../tasks/login'; import { openTimelineUsingToggle } from '../../../tasks/security_main'; @@ -31,7 +37,13 @@ describe('Row renderers', () => { beforeEach(() => { deleteTimelines(); login(); - visit(HOSTS_URL); + visit(HOSTS_URL, { + onLoad: () => { + waitForWelcomePanelToBeLoaded(); + waitForPageToBeLoaded(); + waitForAllHostsToBeLoaded(); + }, + }); openTimelineUsingToggle(); populateTimeline(); cy.get(TIMELINE_SHOW_ROW_RENDERERS_GEAR).should('exist'); @@ -48,17 +60,27 @@ describe('Row renderers', () => { cy.get(TIMELINE_ROW_RENDERERS_SEARCHBOX).type('flow'); // Intercepts should be before click handlers that activate them rather than afterwards or you have race conditions - cy.intercept('PATCH', '/api/timeline').as('updateTimeline'); + cy.intercept('PATCH', '/api/timeline', (req) => { + if (req.body.timeline.excludedRowRendererIds.includes('netflow')) { + req.alias = 'excludedNetflow'; + } else { + req.alias = 'includedNetflow'; + } + }); cy.get(TIMELINE_ROW_RENDERERS_MODAL_ITEMS_CHECKBOX).first().uncheck(); - cy.wait('@updateTimeline').then((interception) => { - expect(interception.request.body.timeline.excludedRowRendererIds).to.contain('netflow'); + cy.wait('@excludedNetflow').then((interception) => { + expect( + interception?.response?.body.data.persistTimeline.timeline.excludedRowRendererIds + ).to.contain('netflow'); }); cy.get(TIMELINE_ROW_RENDERERS_MODAL_ITEMS_CHECKBOX).first().check(); - cy.wait('@updateTimeline').then((interception) => { - expect(interception.request.body.timeline.excludedRowRendererIds).not.to.contain('netflow'); + cy.wait('@includedNetflow').then((interception) => { + expect( + interception?.response?.body.data.persistTimeline.timeline.excludedRowRendererIds + ).not.to.contain('netflow'); }); }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/saved_queries.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/saved_queries.ts index ddfcc543c8666..df19f9c6fffba 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/saved_queries.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/saved_queries.ts @@ -5,7 +5,9 @@ * 2.0. */ +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import type { SavedQuery } from '@kbn/data-plugin/public'; +import { SAVED_QUERY_BASE_URL } from '@kbn/data-plugin/common/constants'; import { rootRequest } from '../common'; export const createSavedQuery = ( @@ -15,7 +17,7 @@ export const createSavedQuery = ( ) => rootRequest({ method: 'POST', - url: '/api/saved_query/_create', + url: `${SAVED_QUERY_BASE_URL}/_create`, body: { title, description: '', @@ -34,7 +36,7 @@ export const createSavedQuery = ( }, ], }, - headers: { 'kbn-xsrf': 'cypress-creds' }, + headers: { 'kbn-xsrf': 'cypress-creds', [ELASTIC_HTTP_VERSION_HEADER]: '1' }, }); export const deleteSavedQueries = () => { diff --git a/x-pack/plugins/security_solution/cypress/tasks/common.ts b/x-pack/plugins/security_solution/cypress/tasks/common.ts index 0dcbe84296cb7..08518c2049f1c 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/common.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/common.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { DATA_VIEW_PATH, INITIAL_REST_VERSION } from '@kbn/data-views-plugin/server/constants'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { + KIBANA_LOADING_ICON, LOADING_INDICATOR, LOADING_INDICATOR_HIDDEN, - KIBANA_LOADING_ICON, } from '../screens/security_header'; const primaryButton = 0; diff --git a/x-pack/plugins/security_solution/kibana.jsonc b/x-pack/plugins/security_solution/kibana.jsonc index b279ea77e0bac..f24dffb58edc6 100644 --- a/x-pack/plugins/security_solution/kibana.jsonc +++ b/x-pack/plugins/security_solution/kibana.jsonc @@ -68,7 +68,8 @@ "usageCollection", "lists", "ml", - "unifiedSearch" + "unifiedSearch", + "cloudChat" ], "extraPublicDirs": [ "common" diff --git a/x-pack/plugins/security_solution/public/app/app.tsx b/x-pack/plugins/security_solution/public/app/app.tsx index a0e582b6b7ac2..ef4e05a5046e4 100644 --- a/x-pack/plugins/security_solution/public/app/app.tsx +++ b/x-pack/plugins/security_solution/public/app/app.tsx @@ -34,9 +34,11 @@ import type { StartServices } from '../types'; import { PageRouter } from './routes'; import { UserPrivilegesProvider } from '../common/components/user_privileges/user_privileges_context'; import { ReactQueryClientProvider } from '../common/containers/query_client/query_client_provider'; +import { DEFAULT_ALLOW, DEFAULT_ALLOW_REPLACEMENT } from '../assistant/content/anonymization'; import { PROMPT_CONTEXTS } from '../assistant/content/prompt_contexts'; import { BASE_SECURITY_QUICK_PROMPTS } from '../assistant/content/quick_prompts'; import { BASE_SECURITY_SYSTEM_PROMPTS } from '../assistant/content/prompts/system'; +import { useAnonymizationStore } from '../assistant/use_anonymization_store'; interface StartAppComponent { children: React.ReactNode; @@ -64,6 +66,9 @@ const StartAppComponent: FC = ({ } = useKibana().services; const { conversations, setConversations } = useConversationStore(); + const { defaultAllow, defaultAllowReplacement, setDefaultAllow, setDefaultAllowReplacement } = + useAnonymizationStore(); + const getInitialConversation = useCallback(() => { return conversations; }, [conversations]); @@ -81,6 +86,10 @@ const StartAppComponent: FC = ({ = ({ http={http} nameSpace={nameSpace} setConversations={setConversations} + setDefaultAllow={setDefaultAllow} + setDefaultAllowReplacement={setDefaultAllowReplacement} title={ASSISTANT_TITLE} > @@ -142,23 +153,29 @@ const SecurityAppComponent: React.FC = ({ setHeaderActionMenu, store, theme$, -}) => ( - - { + const CloudProvider = services.cloud?.CloudContextProvider ?? React.Fragment; + + return ( + - {children} - - -); + + + {children} + + + + ); +}; export const SecurityApp = memo(SecurityAppComponent); diff --git a/x-pack/plugins/security_solution/public/app/translations.ts b/x-pack/plugins/security_solution/public/app/translations.ts index 50c3fae8f8ad2..9180894fbde84 100644 --- a/x-pack/plugins/security_solution/public/app/translations.ts +++ b/x-pack/plugins/security_solution/public/app/translations.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; export const ASSISTANT_TITLE = i18n.translate('xpack.securitySolution.assistant.title', { - defaultMessage: 'Elastic Security Assistant', + defaultMessage: 'Elastic AI Assistant', }); export const OVERVIEW = i18n.translate('xpack.securitySolution.navigation.overview', { diff --git a/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx b/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx index 6a782f6d58d84..befd0680c9c80 100644 --- a/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/comment_actions/index.tsx @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiButtonIcon, EuiCopy, EuiToolTip } from '@elastic/eui'; + +import { EuiButtonIcon, EuiCopy, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { CommentType } from '@kbn/cases-plugin/common'; import type { Message } from '@kbn/elastic-assistant'; import React, { useCallback } from 'react'; @@ -61,45 +62,51 @@ const CommentActionsComponent: React.FC = ({ message }) => { { comment: message.content, type: CommentType.user, - owner: i18n.ELASTIC_SECURITY_ASSISTANT, + owner: i18n.ELASTIC_AI_ASSISTANT, }, ], }); }, [message.content, selectCaseModal]); return ( - <> - - - + + + + + + - - - + + + + + - - - {(copy) => ( - - )} - - - + + + + {(copy) => ( + + )} + + + + ); }; diff --git a/x-pack/plugins/security_solution/public/assistant/comment_actions/translations.ts b/x-pack/plugins/security_solution/public/assistant/comment_actions/translations.ts index 878fbab69d6af..1f85d7b2cb96f 100644 --- a/x-pack/plugins/security_solution/public/assistant/comment_actions/translations.ts +++ b/x-pack/plugins/security_solution/public/assistant/comment_actions/translations.ts @@ -35,10 +35,10 @@ export const ADD_TO_CASE_EXISTING_CASE = i18n.translate( } ); -export const ELASTIC_SECURITY_ASSISTANT = i18n.translate( - 'xpack.securitySolution.assistant.commentActions.elasticSecurityAssistantTitle', +export const ELASTIC_AI_ASSISTANT = i18n.translate( + 'xpack.securitySolution.assistant.commentActions.elasticAiAssistantTitle', { - defaultMessage: 'Elastic Security Assistant', + defaultMessage: 'Elastic AI Assistant', } ); diff --git a/x-pack/plugins/security_solution/public/assistant/content/anonymization/index.ts b/x-pack/plugins/security_solution/public/assistant/content/anonymization/index.ts new file mode 100644 index 0000000000000..84cd9ad09cacb --- /dev/null +++ b/x-pack/plugins/security_solution/public/assistant/content/anonymization/index.ts @@ -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. + */ + +/** By default, these fields are allowed to be sent to the assistant */ +export const DEFAULT_ALLOW = [ + '@timestamp', + 'cloud.availability_zone', + 'cloud.provider', + 'cloud.region', + 'destination.ip', + 'dns.question.name', + 'dns.question.type', + 'event.action', + 'event.category', + 'event.dataset', + 'event.module', + 'event.outcome', + 'event.type', + 'file.Ext.original.path', + 'file.hash.sha256', + 'file.name', + 'file.path', + 'host.name', + 'kibana.alert.rule.name', + 'network.protocol', + 'process.args', + 'process.exit_code', + 'process.hash.md5', + 'process.hash.sha1', + 'process.hash.sha256', + 'process.parent.name', + 'process.parent.pid', + 'process.name', + 'process.pid', + 'source.ip', + 'user.domain', + 'user.name', +]; + +/** By default, these fields will be anonymized */ +export const DEFAULT_ALLOW_REPLACEMENT = [ + 'cloud.availability_zone', + 'cloud.provider', + 'cloud.region', + 'destination.ip', + 'file.Ext.original.path', + 'file.name', + 'file.path', + 'host.ip', // not a default allow field, but anonymized by default + 'host.name', + 'source.ip', + 'user.domain', + 'user.name', +]; diff --git a/x-pack/plugins/security_solution/public/assistant/content/conversations/index.tsx b/x-pack/plugins/security_solution/public/assistant/content/conversations/index.tsx index 261906baa9150..b499092240377 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/conversations/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/content/conversations/index.tsx @@ -6,7 +6,7 @@ */ import { - ELASTIC_SECURITY_ASSISTANT_TITLE, + ELASTIC_AI_ASSISTANT_TITLE, WELCOME_CONVERSATION_TITLE, } from '@kbn/elastic-assistant/impl/assistant/use_conversation/translations'; import type { Conversation } from '@kbn/elastic-assistant'; @@ -21,7 +21,7 @@ import { ALERT_SUMMARY_CONVERSATION_ID, EVENT_SUMMARY_CONVERSATION_ID, } from '../../../common/components/event_details/translations'; -import { ELASTIC_SECURITY_ASSISTANT } from '../../comment_actions/translations'; +import { ELASTIC_AI_ASSISTANT } from '../../comment_actions/translations'; import { TIMELINE_CONVERSATION_TITLE } from './translations'; export const BASE_SECURITY_CONVERSATIONS: Record = { @@ -59,10 +59,10 @@ export const BASE_SECURITY_CONVERSATIONS: Record = { id: WELCOME_CONVERSATION_TITLE, isDefault: true, theme: { - title: ELASTIC_SECURITY_ASSISTANT_TITLE, + title: ELASTIC_AI_ASSISTANT_TITLE, titleIcon: 'logoSecurity', assistant: { - name: ELASTIC_SECURITY_ASSISTANT, + name: ELASTIC_AI_ASSISTANT, icon: 'logoSecurity', }, system: { diff --git a/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts b/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts index a24e63f6c9be5..e060e88a2c8c7 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts +++ b/x-pack/plugins/security_solution/public/assistant/content/prompts/system/translations.ts @@ -11,7 +11,7 @@ export const YOU_ARE_A_HELPFUL_EXPERT_ASSISTANT = i18n.translate( 'xpack.securitySolution.assistant.content.prompts.system.youAreAHelpfulExpertAssistant', { defaultMessage: - 'You are a helpful, expert assistant who only answers questions about Elastic Security.', + 'You are a helpful, expert assistant who answers questions about Elastic Security.', } ); diff --git a/x-pack/plugins/security_solution/public/assistant/get_comments/index.tsx b/x-pack/plugins/security_solution/public/assistant/get_comments/index.tsx index fd0de680ee84c..d2c051285c8cd 100644 --- a/x-pack/plugins/security_solution/public/assistant/get_comments/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/get_comments/index.tsx @@ -16,23 +16,41 @@ import * as i18n from './translations'; export const getComments = ({ currentConversation, lastCommentRef, + showAnonymizedValues, }: { currentConversation: Conversation; lastCommentRef: React.MutableRefObject; + showAnonymizedValues: boolean; }): EuiCommentProps[] => currentConversation.messages.map((message, index) => { const isUser = message.role === 'user'; + const replacements = currentConversation.replacements; + const messageContentWithReplacements = + replacements != null + ? Object.keys(replacements).reduce( + (acc, replacement) => acc.replaceAll(replacement, replacements[replacement]), + message.content + ) + : message.content; + const transformedMessage = { + ...message, + content: messageContentWithReplacements, + }; return { - actions: , + actions: , children: index !== currentConversation.messages.length - 1 ? ( - {message.content} + + {showAnonymizedValues ? message.content : transformedMessage.content} + ) : ( - {message.content} + + {showAnonymizedValues ? message.content : transformedMessage.content} + ), diff --git a/x-pack/plugins/security_solution/public/assistant/helpers.tsx b/x-pack/plugins/security_solution/public/assistant/helpers.tsx index 896bb5b13cd65..829d36c0f9be7 100644 --- a/x-pack/plugins/security_solution/public/assistant/helpers.tsx +++ b/x-pack/plugins/security_solution/public/assistant/helpers.tsx @@ -34,6 +34,11 @@ export const getAllFields = (data: TimelineEventsDetailsItem[]): QueryField[] => .filter(({ field }) => !field.startsWith('signal.')) .map(({ field, values }) => ({ field, values: values?.join(',') ?? '' })); +export const getRawData = (data: TimelineEventsDetailsItem[]): Record => + data + .filter(({ field }) => !field.startsWith('signal.')) + .reduce((acc, { field, values }) => ({ ...acc, [field]: values ?? [] }), {}); + export const getFieldsAsCsv = (queryFields: QueryField[]): string => queryFields.map(({ field, values }) => `${field},${values}`).join('\n'); diff --git a/x-pack/plugins/security_solution/public/assistant/use_anonymization_store/index.tsx b/x-pack/plugins/security_solution/public/assistant/use_anonymization_store/index.tsx new file mode 100644 index 0000000000000..62ffa72713223 --- /dev/null +++ b/x-pack/plugins/security_solution/public/assistant/use_anonymization_store/index.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 { useLocalStorage } from '../../common/components/local_storage'; +import { DEFAULT_ALLOW, DEFAULT_ALLOW_REPLACEMENT } from '../content/anonymization'; +import { LOCAL_STORAGE_KEY } from '../helpers'; + +export interface UseAnonymizationStore { + defaultAllow: string[]; + defaultAllowReplacement: string[]; + setDefaultAllow: React.Dispatch>; + setDefaultAllowReplacement: React.Dispatch>; +} + +const DEFAULT_ALLOW_KEY = `${LOCAL_STORAGE_KEY}.defaultAllow`; +const DEFAULT_ALLOW_REPLACEMENT_KEY = `${LOCAL_STORAGE_KEY}.defaultAllowReplacement`; + +export const useAnonymizationStore = (): UseAnonymizationStore => { + const [defaultAllow, setDefaultAllow] = useLocalStorage({ + defaultValue: DEFAULT_ALLOW, + key: DEFAULT_ALLOW_KEY, + isInvalidDefault: (valueFromStorage) => !Array.isArray(valueFromStorage), + }); + + const [defaultAllowReplacement, setDefaultAllowReplacement] = useLocalStorage({ + defaultValue: DEFAULT_ALLOW_REPLACEMENT, + key: DEFAULT_ALLOW_REPLACEMENT_KEY, + isInvalidDefault: (valueFromStorage) => !Array.isArray(valueFromStorage), + }); + + return { + defaultAllow, + defaultAllowReplacement, + setDefaultAllow, + setDefaultAllowReplacement, + }; +}; diff --git a/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx index c40fd2b6cebf3..d80a14872ccf6 100644 --- a/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/storybook_providers.tsx @@ -69,9 +69,15 @@ export const StorybookProviders: React.FC = ({ children }) => { {children} diff --git a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx index 89f5a6351411f..61f0a69266af5 100644 --- a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx @@ -77,9 +77,15 @@ export const TestProvidersComponent: React.FC = ({ @@ -124,9 +130,15 @@ const TestProvidersWithPrivilegesComponent: React.FC = ({ { expect(result).toEqual({ unit: 'ms', value: 0 }); }); + + test('returns timeObj with unit of d and value 5 when time is 5d ', () => { + const result = getTimeTypeValue('5d'); + + expect(result).toEqual({ unit: 'd', value: 5 }); + }); }); describe('filterEmptyThreats', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts index e283c8aae095b..fbf57f48fe150 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts @@ -62,7 +62,7 @@ export const getTimeTypeValue = (time: string): { unit: Unit; value: number } => if ( !isEmpty(filterTimeType) && filterTimeType != null && - ['s', 'm', 'h'].includes(filterTimeType[0]) + ['s', 'm', 'h', 'd'].includes(filterTimeType[0]) ) { timeObj.unit = filterTimeType[0] as Unit; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index c02aa7fdca34c..336e697cbdb8f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -67,6 +67,7 @@ import { AlertsHistogramPanel } from '../../../../detections/components/alerts_k import { useUserData } from '../../../../detections/components/user_info'; import { StepDefineRuleReadOnly } from '../../../../detections/components/rules/step_define_rule'; import { StepScheduleRuleReadOnly } from '../../../../detections/components/rules/step_schedule_rule'; +import { StepRuleActionsReadOnly } from '../../../../detections/components/rules/step_rule_actions'; import { buildAlertsFilter, buildAlertStatusFilter, @@ -290,7 +291,13 @@ const RuleDetailsPageComponent: React.FC = ({ const [pageTabs, setTabs] = useState>>(ruleDetailTabs); - const { aboutRuleData, modifiedAboutRuleDetailsData, defineRuleData, scheduleRuleData } = + const { + aboutRuleData, + modifiedAboutRuleDetailsData, + defineRuleData, + scheduleRuleData, + ruleActionsData, + } = rule != null ? getStepsData({ rule, detailsView: true }) : { @@ -298,6 +305,7 @@ const RuleDetailsPageComponent: React.FC = ({ modifiedAboutRuleDetailsData: null, defineRuleData: null, scheduleRuleData: null, + ruleActionsData: null, }; const [dataViewTitle, setDataViewTitle] = useState(); useEffect(() => { @@ -644,6 +652,11 @@ const RuleDetailsPageComponent: React.FC = ({ const defaultRuleStackByOption: AlertsStackByField = 'event.category'; + const hasNotificationActions = ruleActionsData != null && ruleActionsData.actions.length > 0; + const hasResponseActions = + ruleActionsData != null && (ruleActionsData.responseActions || []).length > 0; + const hasActions = hasNotificationActions || hasResponseActions; + return ( <> @@ -791,6 +804,16 @@ const RuleDetailsPageComponent: React.FC = ({ )} + {hasActions && ( + + + + + + )} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx index 4c126311b6d18..926289dd19892 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx @@ -12,11 +12,11 @@ import type { FieldSpec, DataViewSpec } from '@kbn/data-views-plugin/common'; import { useAppToasts } from '../../../common/hooks/use_app_toasts'; import type { Rule } from '../../rule_management/logic/types'; -import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; import { useKibana } from '../../../common/lib/kibana'; import { useFetchIndex } from '../../../common/containers/source'; import * as i18n from '../../../common/containers/source/translations'; +import { useRuleIndices } from '../../rule_management/logic/use_rule_indices'; export interface ReturnUseFetchExceptionFlyoutData { isLoading: boolean; @@ -72,20 +72,20 @@ export const useFetchIndexPatterns = (rules: Rule[] | null): ReturnUseFetchExcep () => (isMLRule && isSingleRule && rules != null ? rules[0].machine_learning_job_id ?? [] : []), [isMLRule, isSingleRule, rules] ); - const { loading: mlJobLoading, jobs } = useGetInstalledJob(memoMlJobIds); + const { mlJobLoading, ruleIndices: mlRuleIndices } = useRuleIndices(memoMlJobIds); // We only want to provide a non empty array if it's an ML rule and we were able to fetch // the index patterns, or if it's a rule not using data views. Otherwise, return an empty // empty array to avoid making the `useFetchIndex` call const memoRuleIndices = useMemo(() => { - if (isMLRule && jobs.length > 0) { - return jobs[0].results_index_name ? [`.ml-anomalies-${jobs[0].results_index_name}`] : []; + if (isMLRule && mlRuleIndices.length > 0) { + return mlRuleIndices; } else if (memoDataViewId != null) { return []; } else { return memoNonDataViewIndexPatterns; } - }, [jobs, isMLRule, memoDataViewId, memoNonDataViewIndexPatterns]); + }, [isMLRule, memoDataViewId, memoNonDataViewIndexPatterns, mlRuleIndices]); const [ isIndexPatternLoading, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/exceptionable_endpoint_fields.json b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/exceptionable_endpoint_fields.json index faa73b290f3cb..93a35fdcdc6cc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/exceptionable_endpoint_fields.json +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/utils/exceptionable_endpoint_fields.json @@ -30,6 +30,10 @@ "agent.id", "agent.type", "agent.version", + "Effective_process.entity_id", + "Effective_process.executable", + "Effective_process.name", + "Effective_process.pid", "elastic.agent.id", "event.action", "event.category", @@ -59,6 +63,12 @@ "file.path", "file.pe.company", "file.pe.description", + "file.pe.Ext.dotnet", + "file.pe.Ext.streams.hash.md5", + "file.pe.Ext.streams.hash.sha256", + "file.pe.Ext.streams.name", + "file.pe.Ext.sections.hash.md5", + "file.pe.Ext.sections.hash.sha256", "file.pe.file_version", "file.pe.original_file_name", "file.pe.product", @@ -79,6 +89,7 @@ "host.os.platform", "host.os.version", "host.type", + "process.args", "process.command_line", "process.code_signature.subject_name", "process.Ext.services", @@ -92,6 +103,7 @@ "process.hash.sha256", "process.hash.sha512", "process.name", + "process.parent.args", "process.parent.executable", "process.parent.hash.md5", "process.parent.hash.sha1", diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index aff10f8a817aa..796ac3513f67b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -10,6 +10,9 @@ import type { ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/common'; +import { BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common'; +import type { ActionType, AsApiContract } from '@kbn/actions-plugin/common'; +import type { ActionResult } from '@kbn/actions-plugin/server'; import type { BulkInstallPackagesResponse } from '@kbn/fleet-plugin/common'; import { epmRouteService } from '@kbn/fleet-plugin/common'; import type { InstallPackageResponse } from '@kbn/fleet-plugin/common/types'; @@ -236,6 +239,21 @@ export const fetchRulesSnoozeSettings = async ({ return result; }, {} as RulesSnoozeSettingsMap); }; + +export const fetchConnectors = ( + signal?: AbortSignal +): Promise>> => + KibanaServices.get().http.fetch(`${BASE_ACTION_API_PATH}/connectors`, { method: 'GET', signal }); + +export const fetchConnectorTypes = (signal?: AbortSignal): Promise => + KibanaServices.get().http.fetch(`${BASE_ACTION_API_PATH}/connector_types`, { + method: 'GET', + signal, + query: { + feature_id: 'siem', + }, + }); + export interface BulkActionSummary { failed: number; skipped: number; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/translations.ts new file mode 100644 index 0000000000000..96afe91611c69 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/translations.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const CONNECTORS_FETCH_ERROR = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.actions.connectorsFetchError', + { + defaultMessage: 'Failed to fetch connectors', + } +); + +export const CONNECTOR_TYPES_FETCH_ERROR = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.actions.connectorTypesFetchError', + { + defaultMessage: 'Failed to fetch connector types', + } +); + +export const ACTIONS_FETCH_ERROR_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.actions.actionsFetchErrorDescription', + { + defaultMessage: 'Viewing actions is not available', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_connectors.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_connectors.ts new file mode 100644 index 0000000000000..500a346fa1406 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_connectors.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; +import { BASE_ACTION_API_PATH } from '@kbn/actions-plugin/common'; +import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; +import { fetchConnectors, fetchConnectorTypes } from '../api'; +import * as i18n from './translations'; + +export const useFetchConnectors = () => { + const { addError } = useAppToasts(); + + return useQuery( + ['GET', BASE_ACTION_API_PATH, 'connectors'], + ({ signal }) => fetchConnectors(signal), + { + onError: (error) => { + addError(error, { + title: i18n.CONNECTORS_FETCH_ERROR, + toastMessage: i18n.ACTIONS_FETCH_ERROR_DESCRIPTION, + }); + }, + } + ); +}; + +export const useFetchConnectorTypes = () => { + const { addError } = useAppToasts(); + + return useQuery( + ['GET', BASE_ACTION_API_PATH, 'connector_types', 'siem'], + ({ signal }) => fetchConnectorTypes(signal), + { + onError: (error) => { + addError(error, { + title: i18n.CONNECTOR_TYPES_FETCH_ERROR, + toastMessage: i18n.ACTIONS_FETCH_ERROR_DESCRIPTION, + }); + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts index b04cda31daf5f..cdb6e805d18c8 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts @@ -9,8 +9,10 @@ import { renderHook } from '@testing-library/react-hooks'; import { useRuleIndices } from './use_rule_indices'; import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; +import { useSecurityJobs } from '../../../common/components/ml_popover/hooks/use_security_jobs'; jest.mock('../../../common/components/ml/hooks/use_get_jobs'); +jest.mock('../../../common/components/ml_popover/hooks/use_security_jobs'); describe('useRuleIndices', () => { beforeEach(() => { @@ -18,6 +20,10 @@ describe('useRuleIndices', () => { }); it('should return handle undefined parameters', async () => { + (useSecurityJobs as jest.Mock).mockImplementation(() => ({ + jobs: [{ id: 'job1' }, { id: 'job2' }], + loading: false, + })); (useGetInstalledJob as jest.Mock).mockImplementation((jobIds: string[]) => { expect(jobIds).toEqual([]); return { loading: false, jobs: [] }; @@ -30,6 +36,10 @@ describe('useRuleIndices', () => { }); it('should return default indices if ML job is not specified', async () => { + (useSecurityJobs as jest.Mock).mockImplementation(() => ({ + jobs: [{ id: 'job1' }, { id: 'job2' }], + loading: false, + })); (useGetInstalledJob as jest.Mock).mockImplementation((jobIds: string[]) => { expect(jobIds).toEqual([]); return { loading: false, jobs: [] }; @@ -44,6 +54,13 @@ describe('useRuleIndices', () => { it('should return default indices if ML job is not specified 1', async () => { const machineLearningJobId = ['ml-job-1', 'ml-job-2']; + (useSecurityJobs as jest.Mock).mockImplementation(() => ({ + jobs: [ + { id: 'ml-job-1', isInstalled: true }, + { id: 'ml-job-2', isInstalled: true }, + ], + loading: false, + })); (useGetInstalledJob as jest.Mock).mockImplementation((jobIds: string[]) => { expect(jobIds).toEqual(machineLearningJobId); return { @@ -55,7 +72,55 @@ describe('useRuleIndices', () => { const { result } = renderHook(() => useRuleIndices(machineLearningJobId, defaultIndices)); expect(result.current).toEqual({ mlJobLoading: false, - ruleIndices: ['.ml-anomalies-index1'], + ruleIndices: ['.ml-anomalies-index1', '.ml-anomalies-index2'], + }); + }); + + it('should return indices of installed jobs only', async () => { + const machineLearningJobId = ['ml-job-1', 'ml-job-2']; + (useSecurityJobs as jest.Mock).mockImplementation(() => ({ + jobs: [ + { id: 'ml-job-1', isInstalled: false }, + { id: 'ml-job-2', isInstalled: true }, + ], + loading: false, + })); + (useGetInstalledJob as jest.Mock).mockImplementation((jobIds: string[]) => { + expect(jobIds).toEqual(['ml-job-2']); + return { + loading: false, + jobs: [{ results_index_name: 'index2' }], + }; + }); + const defaultIndices = ['index1', 'index2']; + const { result } = renderHook(() => useRuleIndices(machineLearningJobId, defaultIndices)); + expect(result.current).toEqual({ + mlJobLoading: false, + ruleIndices: ['.ml-anomalies-index2'], + }); + }); + + it('should return default indices if ML jobs are not installed', async () => { + const machineLearningJobId = ['ml-job-1', 'ml-job-2']; + (useSecurityJobs as jest.Mock).mockImplementation(() => ({ + jobs: [ + { id: 'ml-job-1', isInstalled: false }, + { id: 'ml-job-2', isInstalled: false }, + ], + loading: false, + })); + (useGetInstalledJob as jest.Mock).mockImplementation((jobIds: string[]) => { + expect(jobIds).toEqual([]); + return { + loading: false, + jobs: [], + }; + }); + const defaultIndices = ['index1', 'index2']; + const { result } = renderHook(() => useRuleIndices(machineLearningJobId, defaultIndices)); + expect(result.current).toEqual({ + mlJobLoading: false, + ruleIndices: defaultIndices, }); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.ts index 4dbb28514255a..144750790800f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.ts @@ -6,19 +6,39 @@ */ import { useMemo } from 'react'; +import { useSecurityJobs } from '../../../common/components/ml_popover/hooks/use_security_jobs'; import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; export const useRuleIndices = (machineLearningJobId?: string[], defaultRuleIndices?: string[]) => { const memoMlJobIds = useMemo(() => machineLearningJobId ?? [], [machineLearningJobId]); - const { loading: mlJobLoading, jobs } = useGetInstalledJob(memoMlJobIds); + const { loading: mlSecurityJobLoading, jobs } = useSecurityJobs(); + const memoSelectedMlJobs = useMemo( + () => jobs.filter(({ id }) => memoMlJobIds.includes(id)), + [jobs, memoMlJobIds] + ); + + // Filter jobs that are installed. For those jobs we can get the index pattern from `job.results_index_name` field + const memoInstalledMlJobs = useMemo( + () => memoSelectedMlJobs.filter(({ isInstalled }) => isInstalled).map((j) => j.id), + [memoSelectedMlJobs] + ); + const { loading: mlInstalledJobLoading, jobs: installedJobs } = + useGetInstalledJob(memoInstalledMlJobs); + const memoMlIndices = useMemo(() => { + const installedJobsIndices = installedJobs.map((j) => `.ml-anomalies-${j.results_index_name}`); + return [...new Set(installedJobsIndices)]; + }, [installedJobs]); const memoRuleIndices = useMemo(() => { - if (jobs.length > 0) { - return jobs[0].results_index_name ? [`.ml-anomalies-${jobs[0].results_index_name}`] : []; + if (memoMlIndices.length > 0) { + return memoMlIndices; } else { return defaultRuleIndices ?? []; } - }, [jobs, defaultRuleIndices]); + }, [defaultRuleIndices, memoMlIndices]); - return { mlJobLoading, ruleIndices: memoRuleIndices }; + return { + mlJobLoading: mlSecurityJobLoading || mlInstalledJobLoading, + ruleIndices: memoRuleIndices, + }; }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_no_items_message.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_no_items_message.tsx new file mode 100644 index 0000000000000..222ab543a7cd9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_no_items_message.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 { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import { SecurityPageName } from '../../../../../../common'; +import { useGetSecuritySolutionLinkProps } from '../../../../../common/components/links'; +import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; + +const AddPrebuiltRulesTableNoItemsMessageComponent = () => { + const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); + const { onClick: onClickLink } = getSecuritySolutionLinkProps({ + deepLinkId: SecurityPageName.rules, + }); + + return ( + + + {i18n.NO_RULES_AVAILABLE_FOR_INSTALL}} + titleSize="s" + body={i18n.NO_RULES_AVAILABLE_FOR_INSTALL_BODY} + /> + + + + {i18n.GO_BACK_TO_RULES_TABLE_BUTTON} + + + + ); +}; + +export const AddPrebuiltRulesTableNoItemsMessage = React.memo( + AddPrebuiltRulesTableNoItemsMessageComponent +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.tsx index 159e76e822911..b131704bf8be7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.tsx @@ -6,7 +6,6 @@ */ import { - EuiEmptyPrompt, EuiInMemoryTable, EuiSkeletonLoading, EuiProgress, @@ -15,20 +14,13 @@ import { } from '@elastic/eui'; import React from 'react'; -import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; import { RULES_TABLE_INITIAL_PAGE_SIZE, RULES_TABLE_PAGE_SIZE_OPTIONS } from '../constants'; +import { AddPrebuiltRulesTableNoItemsMessage } from './add_prebuilt_rules_no_items_message'; import { useAddPrebuiltRulesTableContext } from './add_prebuilt_rules_table_context'; +import { AddPrebuiltRulesTableFilters } from './add_prebuilt_rules_table_filters'; import { useAddPrebuiltRulesTableColumns } from './use_add_prebuilt_rules_table_columns'; -const NO_ITEMS_MESSAGE = ( - {i18n.NO_RULES_AVAILABLE_FOR_INSTALL}} - titleSize="s" - body={i18n.NO_RULES_AVAILABLE_FOR_INSTALL_BODY} - /> -); - /** * Table Component for displaying new rules that are available to be installed */ @@ -38,7 +30,7 @@ export const AddPrebuiltRulesTable = React.memo(() => { const addRulesTableContext = useAddPrebuiltRulesTableContext(); const { - state: { rules, tags, isFetched, isLoading, isRefetching, selectedRules }, + state: { rules, filteredRules, isFetched, isLoading, isRefetching, selectedRules }, actions: { selectRules }, } = addRulesTableContext; const rulesColumns = useAddPrebuiltRulesTableColumns(); @@ -68,44 +60,28 @@ export const AddPrebuiltRulesTable = React.memo(() => { } loadedContent={ isTableEmpty ? ( - NO_ITEMS_MESSAGE + ) : ( - ({ - value: tag, - name: tag, - field: 'tags', - })), - }, - ], - }} - pagination={{ - initialPageSize: RULES_TABLE_INITIAL_PAGE_SIZE, - pageSizeOptions: RULES_TABLE_PAGE_SIZE_OPTIONS, - }} - isSelectable - selection={{ - selectable: () => true, - onSelectionChange: selectRules, - initialSelected: selectedRules, - }} - itemId="rule_id" - data-test-subj="add-prebuilt-rules-table" - columns={rulesColumns} - /> + <> + + true, + onSelectionChange: selectRules, + initialSelected: selectedRules, + }} + itemId="rule_id" + data-test-subj="add-prebuilt-rules-table" + columns={rulesColumns} + /> + ) } /> diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx index baa2da7eda5f0..6691eb7598070 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import type { Dispatch, SetStateAction } from 'react'; import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; import type { RuleInstallationInfoForReview } from '../../../../../../common/detection_engine/prebuilt_rules/api/review_rule_installation/response_schema'; import type { RuleSignatureId } from '../../../../../../common/detection_engine/rule_schema'; @@ -14,12 +15,22 @@ import { usePerformInstallSpecificRules, } from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_install'; import { usePrebuiltRulesInstallReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_install_review'; +import type { AddPrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_install'; +import { useFilterPrebuiltRulesToInstall } from './use_filter_prebuilt_rules_to_install'; export interface AddPrebuiltRulesTableState { /** * Rules available to be installed */ rules: RuleInstallationInfoForReview[]; + /** + * Rules to display in table after applying filters + */ + filteredRules: RuleInstallationInfoForReview[]; + /** + * Currently selected table filter + */ + filterOptions: AddPrebuiltRulesTableFilterOptions; /** * All unique tags for all rules */ @@ -55,6 +66,7 @@ export interface AddPrebuiltRulesTableActions { installOneRule: (ruleId: RuleSignatureId) => void; installAllRules: () => void; installSelectedRules: () => void; + setFilterOptions: Dispatch>; selectRules: (rules: RuleInstallationInfoForReview[]) => void; } @@ -75,6 +87,11 @@ export const AddPrebuiltRulesTableContextProvider = ({ const [loadingRules, setLoadingRules] = useState([]); const [selectedRules, setSelectedRules] = useState([]); + const [filterOptions, setFilterOptions] = useState({ + filter: '', + tags: [], + }); + const { data: { rules, stats: { tags } } = { rules: [], @@ -135,6 +152,7 @@ export const AddPrebuiltRulesTableContextProvider = ({ const actions = useMemo( () => ({ + setFilterOptions, installAllRules, installOneRule, installSelectedRules, @@ -144,10 +162,14 @@ export const AddPrebuiltRulesTableContextProvider = ({ [installAllRules, installOneRule, installSelectedRules, refetch] ); + const filteredRules = useFilterPrebuiltRulesToInstall({ filterOptions, rules }); + const providerValue = useMemo(() => { return { state: { rules, + filteredRules, + filterOptions, tags, isFetched, isLoading, @@ -160,6 +182,8 @@ export const AddPrebuiltRulesTableContextProvider = ({ }; }, [ rules, + filteredRules, + filterOptions, tags, isFetched, isLoading, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_filters.tsx new file mode 100644 index 0000000000000..913dbd5a0fbc1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_filters.tsx @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { isEqual } from 'lodash/fp'; +import React, { useCallback } from 'react'; +import styled from 'styled-components'; +import * as i18n from './translations'; +import { TagsFilterPopover } from '../rules_table_filters/tags_filter_popover'; +import { RuleSearchField } from '../rules_table_filters/rule_search_field'; +import { useAddPrebuiltRulesTableContext } from './add_prebuilt_rules_table_context'; + +const FilterWrapper = styled(EuiFlexGroup)` + margin-bottom: ${({ theme }) => theme.eui.euiSizeM}; +`; + +/** + * Collection of filters for filtering data within the Add Prebuilt Rules table. + * Contains search bar and tag selection + */ +const AddPrebuiltRulesTableFiltersComponent = () => { + const { + state: { filterOptions, tags }, + actions: { setFilterOptions }, + } = useAddPrebuiltRulesTableContext(); + + const { tags: selectedTags } = filterOptions; + + const handleOnSearch = useCallback( + (filterString) => { + setFilterOptions((filters) => ({ + ...filters, + filter: filterString.trim(), + })); + }, + [setFilterOptions] + ); + + const handleSelectedTags = useCallback( + (newTags: string[]) => { + if (!isEqual(newTags, selectedTags)) { + setFilterOptions((filters) => ({ + ...filters, + tags: newTags, + })); + } + }, + [selectedTags, setFilterOptions] + ); + + return ( + + + + + + + + + ); +}; + +AddPrebuiltRulesTableFiltersComponent.displayName = 'AddPrebuiltRulesTableFiltersComponent'; + +export const AddPrebuiltRulesTableFilters = React.memo(AddPrebuiltRulesTableFiltersComponent); + +AddPrebuiltRulesTableFilters.displayName = 'AddPrebuiltRulesTableFilters'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/translations.ts index 72cac13e5494d..5b63f4c4f60d0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/translations.ts @@ -23,3 +23,10 @@ export const INSTALL_SELECTED_RULES = (numberOfSelectedRules: number) => { } ); }; + +export const SEARCH_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.addRules.searchBarPlaceholder', + { + defaultMessage: 'Search by rule name', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_filter_prebuilt_rules_to_install.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_filter_prebuilt_rules_to_install.ts new file mode 100644 index 0000000000000..5c11633d31f92 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_filter_prebuilt_rules_to_install.ts @@ -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 { useMemo } from 'react'; +import type { RuleInstallationInfoForReview } from '../../../../../../common/detection_engine/prebuilt_rules/api/review_rule_installation/response_schema'; +import type { FilterOptions } from '../../../../rule_management/logic/types'; + +export type AddPrebuiltRulesTableFilterOptions = Pick; + +export const useFilterPrebuiltRulesToInstall = ({ + rules, + filterOptions, +}: { + rules: RuleInstallationInfoForReview[]; + filterOptions: AddPrebuiltRulesTableFilterOptions; +}) => { + const filteredRules = useMemo(() => { + const { filter, tags } = filterOptions; + return rules.filter((rule) => { + if (filter && !rule.name.toLowerCase().includes(filter.toLowerCase())) { + return false; + } + + if (tags && tags.length > 0) { + return tags.every((tag) => rule.tags.includes(tag)); + } + + return true; + }); + }, [filterOptions, rules]); + + return filteredRules; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx index f631985951add..75d132b761654 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx @@ -25,9 +25,14 @@ const SearchBarWrapper = styled(EuiFlexItem)` interface RuleSearchFieldProps { initialValue?: string; onSearch: (value: string) => void; + placeholder?: string; } -export function RuleSearchField({ initialValue, onSearch }: RuleSearchFieldProps): JSX.Element { +export function RuleSearchField({ + initialValue, + onSearch, + placeholder, +}: RuleSearchFieldProps): JSX.Element { const [searchText, setSearchText] = useState(initialValue); const handleChange = useCallback( (e: ChangeEvent) => setSearchText(e.target.value), @@ -45,7 +50,7 @@ export function RuleSearchField({ initialValue, onSearch }: RuleSearchFieldProps aria-label={i18n.SEARCH_RULES} fullWidth incremental={false} - placeholder={i18n.SEARCH_PLACEHOLDER} + placeholder={placeholder ?? i18n.SEARCH_PLACEHOLDER} value={searchText} onChange={handleChange} onSearch={onSearch} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts index f333d263bfa07..6eecbe133d620 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts @@ -23,3 +23,10 @@ export const UPDATE_SELECTED_RULES = (numberOfSelectedRules: number) => { } ); }; + +export const SEARCH_PLACEHOLDER = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.searchBarPlaceholder', + { + defaultMessage: 'Search by rule name', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx index 7a8b79037a06f..e6afcb08c16bb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table.tsx @@ -7,6 +7,8 @@ import { EuiEmptyPrompt, + EuiFlexGroup, + EuiFlexItem, EuiInMemoryTable, EuiProgress, EuiSkeletonLoading, @@ -19,6 +21,7 @@ import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logi import { RULES_TABLE_INITIAL_PAGE_SIZE, RULES_TABLE_PAGE_SIZE_OPTIONS } from '../constants'; import { UpgradePrebuiltRulesTableButtons } from './upgrade_prebuilt_rules_table_buttons'; import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_table_context'; +import { UpgradePrebuiltRulesTableFilters } from './upgrade_prebuilt_rules_table_filters'; import { useUpgradePrebuiltRulesTableColumns } from './use_upgrade_prebuilt_rules_table_columns'; const NO_ITEMS_MESSAGE = ( @@ -38,7 +41,7 @@ export const UpgradePrebuiltRulesTable = React.memo(() => { const upgradeRulesTableContext = useUpgradePrebuiltRulesTableContext(); const { - state: { rules, tags, isFetched, isLoading, isRefetching, selectedRules }, + state: { rules, filteredRules, isFetched, isLoading, isRefetching, selectedRules }, actions: { selectRules }, } = upgradeRulesTableContext; const rulesColumns = useUpgradePrebuiltRulesTableColumns(); @@ -70,43 +73,34 @@ export const UpgradePrebuiltRulesTable = React.memo(() => { isTableEmpty ? ( NO_ITEMS_MESSAGE ) : ( - ], - filters: [ - { - type: 'field_value_selection', - field: 'rule.tags', - name: 'Tags', - multiSelect: true, - options: tags.map((tag) => ({ - value: tag, - name: tag, - field: 'rule.tags', - })), - }, - ], - }} - pagination={{ - initialPageSize: RULES_TABLE_INITIAL_PAGE_SIZE, - pageSizeOptions: RULES_TABLE_PAGE_SIZE_OPTIONS, - }} - isSelectable - selection={{ - selectable: () => true, - onSelectionChange: selectRules, - initialSelected: selectedRules, - }} - itemId="rule_id" - data-test-subj="rules-upgrades-table" - columns={rulesColumns} - /> + <> + + + + + + + + + + true, + onSelectionChange: selectRules, + initialSelected: selectedRules, + }} + itemId="rule_id" + data-test-subj="rules-upgrades-table" + columns={rulesColumns} + /> + ) } /> diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx index c33185cabf128..89799a7e52dbc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx @@ -6,6 +6,7 @@ */ // import { isEqual } from 'lodash'; +import type { Dispatch, SetStateAction } from 'react'; import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; import type { RuleUpgradeInfoForReview } from '../../../../../../common/detection_engine/prebuilt_rules/api/review_rule_upgrade/response_schema'; import type { RuleSignatureId } from '../../../../../../common/detection_engine/rule_schema'; @@ -15,12 +16,22 @@ import { usePerformUpgradeSpecificRules, } from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_upgrade'; import { usePrebuiltRulesUpgradeReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_upgrade_review'; +import type { UpgradePrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_upgrade'; +import { useFilterPrebuiltRulesToUpgrade } from './use_filter_prebuilt_rules_to_upgrade'; export interface UpgradePrebuiltRulesTableState { /** * Rules available to be updated */ rules: RuleUpgradeInfoForReview[]; + /** + * Rules to display in table after applying filters + */ + filteredRules: RuleUpgradeInfoForReview[]; + /** + * Currently selected table filter + */ + filterOptions: UpgradePrebuiltRulesTableFilterOptions; /** * All unique tags for all rules */ @@ -57,6 +68,7 @@ export interface UpgradePrebuiltRulesTableActions { upgradeOneRule: (ruleId: string) => void; upgradeSelectedRules: () => void; upgradeAllRules: () => void; + setFilterOptions: Dispatch>; selectRules: (rules: RuleUpgradeInfoForReview[]) => void; } @@ -79,6 +91,11 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ const [loadingRules, setLoadingRules] = useState([]); const [selectedRules, setSelectedRules] = useState([]); + const [filterOptions, setFilterOptions] = useState({ + filter: '', + tags: [], + }); + const { data: { rules, stats: { tags } } = { rules: [], @@ -150,15 +167,20 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ upgradeOneRule, upgradeSelectedRules, upgradeAllRules, + setFilterOptions, selectRules: setSelectedRules, }), [refetch, upgradeAllRules, upgradeOneRule, upgradeSelectedRules] ); + const filteredRules = useFilterPrebuiltRulesToUpgrade({ filterOptions, rules }); + const providerValue = useMemo(() => { return { state: { rules, + filteredRules, + filterOptions, tags, isFetched, isLoading, @@ -171,6 +193,8 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ }; }, [ rules, + filteredRules, + filterOptions, tags, isFetched, isLoading, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_filters.tsx new file mode 100644 index 0000000000000..fc8fecab1e07c --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_filters.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { isEqual } from 'lodash/fp'; +import React, { useCallback } from 'react'; +import styled from 'styled-components'; +import * as i18n from './translations'; +import { TagsFilterPopover } from '../rules_table_filters/tags_filter_popover'; +import { RuleSearchField } from '../rules_table_filters/rule_search_field'; +import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_table_context'; + +const FilterWrapper = styled(EuiFlexGroup)` + margin-bottom: ${({ theme }) => theme.eui.euiSizeM}; +`; + +/** + * Collection of filters for filtering data within the Upgrade Prebuilt Rules table. + * Contains search bar and tag selection + */ +const UpgradePrebuiltRulesTableFiltersComponent = () => { + const { + state: { filterOptions, tags }, + actions: { setFilterOptions }, + } = useUpgradePrebuiltRulesTableContext(); + + const { tags: selectedTags } = filterOptions; + + const handleOnSearch = useCallback( + (filterString) => { + setFilterOptions((filters) => ({ + ...filters, + filter: filterString.trim(), + })); + }, + [setFilterOptions] + ); + + const handleSelectedTags = useCallback( + (newTags: string[]) => { + if (!isEqual(newTags, selectedTags)) { + setFilterOptions((filters) => ({ + ...filters, + tags: newTags, + })); + } + }, + [selectedTags, setFilterOptions] + ); + + return ( + + + + + + + + + ); +}; + +UpgradePrebuiltRulesTableFiltersComponent.displayName = 'UpgradePrebuiltRulesTableFiltersComponent'; + +export const UpgradePrebuiltRulesTableFilters = React.memo( + UpgradePrebuiltRulesTableFiltersComponent +); + +UpgradePrebuiltRulesTableFilters.displayName = 'UpgradePrebuiltRulesTableFilters'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts new file mode 100644 index 0000000000000..69b9a543eb448 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts @@ -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 { useMemo } from 'react'; +import type { RuleUpgradeInfoForReview } from '../../../../../../common/detection_engine/prebuilt_rules/api/review_rule_upgrade/response_schema'; +import type { FilterOptions } from '../../../../rule_management/logic/types'; + +export type UpgradePrebuiltRulesTableFilterOptions = Pick; + +export const useFilterPrebuiltRulesToUpgrade = ({ + rules, + filterOptions, +}: { + rules: RuleUpgradeInfoForReview[]; + filterOptions: UpgradePrebuiltRulesTableFilterOptions; +}) => { + const filteredRules = useMemo(() => { + const { filter, tags } = filterOptions; + return rules.filter(({ rule }) => { + if (filter && !rule.name.toLowerCase().includes(filter.toLowerCase())) { + return false; + } + + if (tags && tags.length > 0) { + return tags.every((tag) => rule.tags.includes(tag)); + } + + return true; + }); + }, [filterOptions, rules]); + + return filteredRules; +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button.tsx index 78efbab06024c..76e3a6e355667 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/pre_packaged_rules/load_prepackaged_rules_button.tsx @@ -14,8 +14,6 @@ import { useGetSecuritySolutionLinkProps } from '../../../../common/components/l import { SecurityPageName } from '../../../../../common'; import { usePrebuiltRulesStatus } from '../../../../detection_engine/rule_management/logic/prebuilt_rules/use_prebuilt_rules_status'; -// TODO: Still need to load timeline templates - interface LoadPrePackagedRulesButtonProps { 'data-test-subj'?: string; fill?: boolean; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx index 97e7e2e34a0f8..fc35444b61f28 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx @@ -13,6 +13,7 @@ import { stubIndexPattern } from '@kbn/data-plugin/common/stubs'; import { StepAboutRule, StepAboutRuleReadOnly } from '.'; import { useFetchIndex } from '../../../../common/containers/source'; import { useGetInstalledJob } from '../../../../common/components/ml/hooks/use_get_jobs'; +import { useSecurityJobs } from '../../../../common/components/ml_popover/hooks/use_security_jobs'; import { mockAboutStepRule } from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import { StepRuleDescription } from '../description_step'; import { stepAboutDefaultValue } from './default_value'; @@ -31,6 +32,7 @@ import type { FormHook } from '../../../../shared_imports'; jest.mock('../../../../common/lib/kibana'); jest.mock('../../../../common/containers/source'); jest.mock('../../../../common/components/ml/hooks/use_get_jobs'); +jest.mock('../../../../common/components/ml_popover/hooks/use_security_jobs'); jest.mock('@elastic/eui', () => { const original = jest.requireActual('@elastic/eui'); return { @@ -45,7 +47,7 @@ jest.mock('@elastic/eui', () => { export const stepDefineStepMLRule: DefineStepRule = { ruleType: 'machine_learning', - index: [], + index: ['default-index-*'], queryBar: { query: { query: '', language: '' }, filters: [], saved_id: null }, machineLearningJobId: ['auth_high_count_logon_events_for_a_source_ip'], anomalyThreshold: 50, @@ -71,6 +73,7 @@ export const stepDefineStepMLRule: DefineStepRule = { describe('StepAboutRuleComponent', () => { let useGetInstalledJobMock: jest.Mock; + let useSecurityJobsMock: jest.Mock; const TestComp = ({ setFormRef, defineStepDefaultOverride, @@ -108,6 +111,7 @@ describe('StepAboutRuleComponent', () => { useGetInstalledJobMock = (useGetInstalledJob as jest.Mock).mockImplementation(() => ({ jobs: [], })); + useSecurityJobsMock = (useSecurityJobs as jest.Mock).mockImplementation(() => ({ jobs: [] })); }); it('it renders StepRuleDescription if isReadOnlyView is true and "name" property exists', () => { @@ -374,8 +378,14 @@ describe('StepAboutRuleComponent', () => { }); }); - it('should use index based on ML jobs when editing ML rule', async () => { + it('should use index based on ML jobs when creating/editing ML rule', async () => { (useFetchIndex as jest.Mock).mockClear(); + useSecurityJobsMock.mockImplementation(() => { + return { + jobs: [{ id: 'auth_high_count_logon_events_for_a_source_ip', isInstalled: true }], + loading: false, + }; + }); useGetInstalledJobMock.mockImplementation((jobIds: string[]) => { expect(jobIds).toEqual(['auth_high_count_logon_events_for_a_source_ip']); return { jobs: [{ results_index_name: 'shared' }] }; @@ -388,4 +398,24 @@ describe('StepAboutRuleComponent', () => { const indexNames = ['.ml-anomalies-shared']; expect(useFetchIndex).lastCalledWith(indexNames); }); + + it('should use default rule index if selected ML jobs are not installed when creating/editing ML rule', async () => { + (useFetchIndex as jest.Mock).mockClear(); + useSecurityJobsMock.mockImplementation(() => { + return { + jobs: [{ id: 'auth_high_count_logon_events_for_a_source_ip', isInstalled: false }], + loading: false, + }; + }); + useGetInstalledJobMock.mockImplementation((jobIds: string[]) => { + expect(jobIds).toEqual([]); + return { jobs: [] }; + }); + + mount( {}} defineStepDefaultOverride={stepDefineStepMLRule} />, { + wrappingComponent: TestProviders, + }); + + expect(useFetchIndex).lastCalledWith(stepDefineStepMLRule.index); + }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.test.tsx index cffd025d70ec8..afa4327fe6b27 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import { TestProviders } from '../../../../common/mock'; @@ -19,6 +20,7 @@ import { import { useRuleForms } from '../../../../detection_engine/rule_creation_ui/pages/form'; import type { FormHook } from '../../../../shared_imports'; import type { ActionsStepRule } from '../../../pages/detection_engine/rules/types'; +import { FrequencyDescription } from './notification_action'; jest.mock('../../../../common/lib/kibana', () => ({ useKibana: jest.fn().mockReturnValue({ @@ -83,3 +85,113 @@ describe('StepRuleActions', () => { expect(wrapper.find('Form[data-test-subj="stepRuleActions"]')).toHaveLength(1); }); }); + +describe('getFrequencyDescription', () => { + it('should return empty string if frequency is not specified', () => { + const { container } = render(, { + wrapper: TestProviders, + }); + + expect(container).toBeEmptyDOMElement(); + }); + + it('should correctly handle "For each alert. Per rule run."', async () => { + const frequency = { notifyWhen: 'onActiveAlert', summary: false, throttle: null } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('For each alert. Per rule run.')).toBeInTheDocument(); + }); + + it('should correctly handle "Summary of alerts. Per rule run."', async () => { + const frequency = { notifyWhen: 'onActiveAlert', summary: true, throttle: null } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Summary of alerts. Per rule run.')).toBeInTheDocument(); + }); + + it('should return empty string if type is "onThrottleInterval" but throttle is not specified', () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: null } as const; + + const { container } = render(, { + wrapper: TestProviders, + }); + + expect(container).toBeEmptyDOMElement(); + }); + + it('should correctly handle "Once a second"', async () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: '1s' } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Once a second')).toBeInTheDocument(); + }); + + it('should correctly handle "Once in every # seconds"', async () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: '2s' } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Once in every 2 seconds')).toBeInTheDocument(); + }); + + it('should correctly handle "Once a minute"', async () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: '1m' } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Once a minute')).toBeInTheDocument(); + }); + + it('should correctly handle "Once in every # minutes"', async () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: '2m' } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Once in every 2 minutes')).toBeInTheDocument(); + }); + + it('should correctly handle "Once an hour"', async () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: '1h' } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Once an hour')).toBeInTheDocument(); + }); + + it('should correctly handle "Once in every # hours"', async () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: '2h' } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Once in every 2 hours')).toBeInTheDocument(); + }); + + it('should correctly handle unknown time units', async () => { + const frequency = { notifyWhen: 'onThrottleInterval', summary: true, throttle: '1z' } as const; + + const { findByText } = render(, { + wrapper: TestProviders, + }); + + expect(await findByText('Periodically')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx index 52056b355c82a..b6acd99c5abb4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/index.tsx @@ -10,7 +10,10 @@ import type { FC } from 'react'; import React, { memo, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { ActionVariables } from '@kbn/triggers-actions-ui-plugin/public'; +import type { + ActionTypeRegistryContract, + ActionVariables, +} from '@kbn/triggers-actions-ui-plugin/public'; import { UseArray } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import type { RuleObjectId } from '../../../../../common/detection_engine/rule_schema'; @@ -18,15 +21,19 @@ import { isQueryRule } from '../../../../../common/detection_engine/utils'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { ResponseActionsForm } from '../../../../detection_engine/rule_response_actions/response_actions_form'; import type { RuleStepProps, ActionsStepRule } from '../../../pages/detection_engine/rules/types'; -import { StepRuleDescription } from '../description_step'; import { Form, UseField } from '../../../../shared_imports'; import type { FormHook } from '../../../../shared_imports'; import { StepContentWrapper } from '../step_content_wrapper'; import { RuleActionsField } from '../rule_actions_field'; import { useKibana } from '../../../../common/lib/kibana'; -import { getSchema } from './get_schema'; -import * as I18n from './translations'; +import { + useFetchConnectors, + useFetchConnectorTypes, +} from '../../../../detection_engine/rule_management/api/hooks/use_fetch_connectors'; +import * as i18n from './translations'; import { RuleSnoozeSection } from './rule_snooze_section'; +import { NotificationAction } from './notification_action'; +import { ResponseAction } from './response_action'; interface StepRuleActionsProps extends RuleStepProps { ruleId?: RuleObjectId; // Rule SO's id (not ruleId) @@ -118,7 +125,7 @@ const StepRuleActionsComponent: FC = ({ ) : ( <> - {I18n.NO_ACTIONS_READ_PERMISSIONS} + {i18n.NO_ACTIONS_READ_PERMISSIONS} ); }, [ @@ -139,22 +146,79 @@ const StepRuleActionsComponent: FC = ({ ); }; + export const StepRuleActions = memo(StepRuleActionsComponent); const StepRuleActionsReadOnlyComponent: FC = ({ addPadding, - defaultValues: data, + defaultValues: ruleActionsData, }) => { const { - services: { - triggersActionsUi: { actionTypeRegistry }, - }, + services: { triggersActionsUi }, } = useKibana(); - const schema = useMemo(() => getSchema({ actionTypeRegistry }), [actionTypeRegistry]); + + const actionTypeRegistry = triggersActionsUi.actionTypeRegistry as ActionTypeRegistryContract; + + const { data: connectors } = useFetchConnectors(); + const { data: connectorTypes } = useFetchConnectorTypes(); + + const notificationActions = ruleActionsData.actions; + const responseActions = ruleActionsData.responseActions || []; + + const ruleHasActions = notificationActions.length > 0 || responseActions.length > 0; + + if (!ruleHasActions || !connectors || !connectorTypes) { + return null; + } + + const hasBothNotificationAndResponseActions = + notificationActions.length > 0 && responseActions.length > 0; + return ( - + {notificationActions.length > 0 && ( + <> + {i18n.NOTIFICATION_ACTIONS} + + + )} + + {notificationActions.map((action, index) => { + const isLastItem = index === notificationActions.length - 1; + return ( + <> + + {!isLastItem && } + + ); + })} + + {hasBothNotificationAndResponseActions && } + + {responseActions.length > 0 && ( + <> + {i18n.RESPONSE_ACTIONS} + + + )} + + {responseActions.map((action, index) => { + const isLastItem = index === responseActions.length - 1; + return ( + <> + + {!isLastItem && } + + ); + })} ); }; + export const StepRuleActionsReadOnly = memo(StepRuleActionsReadOnlyComponent); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/notification_action.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/notification_action.tsx new file mode 100644 index 0000000000000..6a02a6da88291 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/notification_action.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiToolTip, EuiText, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import type { ActionType, AsApiContract } from '@kbn/actions-plugin/common'; +import type { ActionResult } from '@kbn/actions-plugin/server'; +import type { RuleActionFrequency, RuleAction } from '@kbn/alerting-plugin/common'; +import type { ActionTypeRegistryContract } from '@kbn/triggers-actions-ui-plugin/public'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { getTimeTypeValue } from '../../../../detection_engine/rule_creation_ui/pages/rule_creation/helpers'; +import * as i18n from './translations'; + +const DescriptionLine = ({ children }: { children: React.ReactNode }) => ( + + + {children} + + +); + +export const FrequencyDescription: React.FC<{ frequency?: RuleActionFrequency }> = ({ + frequency, +}) => { + if (!frequency) { + return null; + } + + if (!frequency.summary) { + return {i18n.FOR_EACH_ALERT_PER_RULE_RUN}; + } + + if (frequency.notifyWhen === 'onActiveAlert') { + return {i18n.SUMMARY_OF_ALERTS_PER_RULE_RUN}; + } + + if (!frequency.throttle) { + return null; + } + + const { unit, value } = getTimeTypeValue(frequency.throttle); + + const messagesByUnit: { [unit: string]: JSX.Element } = { + s: ( + + ), + m: ( + + ), + h: ( + + ), + d: ( + + ), + }; + + return {messagesByUnit[unit] || i18n.PERIODICALLY}; +}; + +interface NotificationActionProps { + action: RuleAction; + connectorTypes: ActionType[]; + connectors: Array>; + actionTypeRegistry: ActionTypeRegistryContract; +} + +export function NotificationAction({ + action, + connectorTypes, + connectors, + actionTypeRegistry, +}: NotificationActionProps) { + const connectorType = connectorTypes.find(({ id }) => id === action.actionTypeId); + const connectorTypeName = connectorType?.name ?? ''; + + const connector = connectors.find(({ id }) => id === action.id); + const connectorName = connector?.name ?? ''; + + const iconType = actionTypeRegistry.get(action.actionTypeId)?.iconClass ?? 'apps'; + + return ( + + + + + + + + + {connectorName} + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/response_action.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/response_action.tsx new file mode 100644 index 0000000000000..6607ce29e9bc9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/response_action.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 React from 'react'; +import { EuiToolTip, EuiText, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; +import type { RuleAction } from '@kbn/alerting-plugin/common'; +import { getActionDetails } from '../../../../detection_engine/rule_response_actions/constants'; + +interface ResponseActionProps { + action: Omit; +} + +export function ResponseAction({ action }: ResponseActionProps) { + const { name, logo } = getActionDetails(action.actionTypeId); + + return ( + + + + + + + + + {name} + + + + ); +} diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx index 968cc27826e79..a1830186837c2 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_rule_actions/translations.tsx @@ -52,3 +52,37 @@ function RuleSnoozeDescription(): JSX.Element { } export const RULE_SNOOZE_DESCRIPTION = ; + +export const ACTIONS = i18n.translate( + 'xpack.securitySolution.detectionEngine.actionsSectionLabel', + { defaultMessage: 'Actions' } +); + +export const NOTIFICATION_ACTIONS = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.notificationActions', + { + defaultMessage: 'Notification actions', + } +); + +export const RESPONSE_ACTIONS = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.responseActions', + { + defaultMessage: 'Response actions', + } +); + +export const FOR_EACH_ALERT_PER_RULE_RUN = i18n.translate( + 'xpack.securitySolution.detectionEngine.actionNotifyWhen.forEachOption', + { defaultMessage: 'For each alert. Per rule run.' } +); + +export const SUMMARY_OF_ALERTS_PER_RULE_RUN = i18n.translate( + 'xpack.securitySolution.detectionEngine.actionNotifyWhen.summaryOption', + { defaultMessage: 'Summary of alerts. Per rule run.' } +); + +export const PERIODICALLY = i18n.translate( + 'xpack.securitySolution.detectionEngine.actionNotifyWhen.periodically', + { defaultMessage: 'Periodically' } +); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index 42820374c22c3..8ab078b34f296 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -1211,3 +1211,10 @@ export const UPDATE_RULE_BUTTON = i18n.translate( defaultMessage: 'Update rule', } ); + +export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( + 'xpack.securitySolution.addRules.goBackToRulesTableButton', + { + defaultMessage: 'Go back to installed Elastic rules', + } +); 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 8fffa3430680c..a544cd5ecc599 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 @@ -42,9 +42,15 @@ const renderHeader = (contextValue: RightPanelContext) => diff --git a/x-pack/plugins/security_solution/public/overview/pages/landing.tsx b/x-pack/plugins/security_solution/public/overview/pages/landing.tsx index c12eae3e0a7b5..71dd89fe0ba7f 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/landing.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/landing.tsx @@ -7,6 +7,7 @@ import React, { memo } from 'react'; import useObservable from 'react-use/lib/useObservable'; +import { Chat } from '@kbn/cloud-chat-plugin/public'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { SecurityPageName } from '../../../common/constants'; import { LandingPageComponent } from '../../common/components/landing_page'; @@ -24,6 +25,7 @@ export const LandingPage = memo(() => { )} + ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx index a1f6d45834f34..900a2aa9f870b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx @@ -12,7 +12,7 @@ import React, { useCallback, useMemo } from 'react'; import deepEqual from 'fast-deep-equal'; import type { EntityType } from '@kbn/timelines-plugin/common'; -import { getPromptContextFromEventDetailsItem } from '../../../../assistant/helpers'; +import { getRawData } from '../../../../assistant/helpers'; import type { BrowserFields } from '../../../../common/containers/source'; import { ExpandableEvent, ExpandableEventTitle } from './expandable_event'; import { useTimelineEventsDetails } from '../../../containers/details'; @@ -102,10 +102,7 @@ const EventDetailsPanelComponent: React.FC = ({ const view = useMemo(() => (isFlyoutView ? SUMMARY_VIEW : TIMELINE_VIEW), [isFlyoutView]); - const getPromptContext = useCallback( - async () => getPromptContextFromEventDetailsItem(detailsData ?? []), - [detailsData] - ); + const getPromptContext = useCallback(async () => getRawData(detailsData ?? []), [detailsData]); const { promptContextId } = useAssistant( isAlert ? 'alert' : 'event', diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 46ba02332e5c3..a4d2e2873a072 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -160,6 +160,7 @@ "@kbn/url-state", "@kbn/ml-anomaly-utils", "@kbn/field-formats-plugin", - "@kbn/dev-proc-runner" + "@kbn/dev-proc-runner", + "@kbn/cloud-chat-plugin" ] } diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts index dcd6b18974da4..5cbf2efbe62f7 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/monitor_configs.ts @@ -140,3 +140,7 @@ export const ResponseCheckJSONCodec = t.interface({ expression: t.string, }); export type ResponseCheckJSON = t.TypeOf; + +export const RequestBodyCheckCodec = t.interface({ value: t.string, type: CodeEditorModeCodec }); + +export type RequestBodyCheck = t.TypeOf; 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 44d6c13c85da8..cd9e96081778b 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 @@ -11,7 +11,6 @@ import { secretKeys } from '../../constants/monitor_management'; import { ConfigKey } from './config_key'; import { MonitorServiceLocationCodec, ServiceLocationErrors } from './locations'; import { - CodeEditorModeCodec, DataStream, DataStreamCodec, FormMonitorTypeCodec, @@ -22,6 +21,7 @@ import { SourceTypeCodec, TLSVersionCodec, VerificationModeCodec, + RequestBodyCheckCodec, } from './monitor_configs'; import { MetadataCodec } from './monitor_meta_data'; import { PrivateLocationCodec } from './synthetics_private_locations'; @@ -195,7 +195,7 @@ export const HTTPSensitiveAdvancedFieldsCodec = t.intersection([ [ConfigKey.RESPONSE_BODY_CHECK_NEGATIVE]: t.array(t.string), [ConfigKey.RESPONSE_BODY_CHECK_POSITIVE]: t.array(t.string), [ConfigKey.RESPONSE_HEADERS_CHECK]: t.record(t.string, t.string), - [ConfigKey.REQUEST_BODY_CHECK]: t.interface({ value: t.string, type: CodeEditorModeCodec }), + [ConfigKey.REQUEST_BODY_CHECK]: RequestBodyCheckCodec, [ConfigKey.REQUEST_HEADERS_CHECK]: t.record(t.string, t.string), [ConfigKey.USERNAME]: t.string, }), diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.test.tsx index c08434460aab5..6059cacb228ea 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.test.tsx @@ -106,4 +106,35 @@ describe('', () => { }); }); }); + + it('shows custom Content-Type', async () => { + const contentMode: CodeEditorMode = CodeEditorMode.PLAINTEXT; + const { getByTestId } = render( + + ); + + const key = getByTestId('keyValuePairsKey0') as HTMLInputElement; + const value = getByTestId('keyValuePairsValue0') as HTMLInputElement; + + expect(key.value).toBe('Content-Type'); + expect(value.value).toBe('custom'); + }); + + it('hides default Content-Type', async () => { + const contentMode: CodeEditorMode = CodeEditorMode.PLAINTEXT; + const { queryByTestId } = render( + + ); + + expect(queryByTestId('keyValuePairsKey0')).not.toBeInTheDocument(); + expect(queryByTestId('keyValuePairsValue0')).not.toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.tsx index c3159043b9958..0aea30159a958 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/fields/header_field.tsx @@ -28,7 +28,9 @@ export const HeaderField = ({ 'data-test-subj': dataTestSubj, readOnly, }: HeaderFieldProps) => { - const defaultValueKeys = Object.keys(defaultValue).filter((key) => key !== 'Content-Type'); // Content-Type is a secret header we hide from the user + const defaultValueKeys = Object.keys(defaultValue).filter( + filterContentType(defaultValue, contentTypes, contentMode) + ); const formattedDefaultValues: Pair[] = [ ...defaultValueKeys.map((key) => { return [key || '', defaultValue[key] || '']; // key, value @@ -72,6 +74,22 @@ export const HeaderField = ({ ); }; +// We apply default `Content-Type` headers automatically depending on the request body mime type +// We hide the default Content-Type headers from the user as an implementation detail +// However, If the user applies a custom `Content-Type` header, it should be shown +export const filterContentType = + ( + defaultValue: Record, + contentTypeMap: Record, + contentMode?: CodeEditorMode + ) => + (key: string) => { + return ( + key !== 'Content-Type' || + (key === 'Content-Type' && contentMode && defaultValue[key] !== contentTypeMap[contentMode]) + ); + }; + export const contentTypes: Record = { [CodeEditorMode.JSON]: ContentType.JSON, [CodeEditorMode.PLAINTEXT]: ContentType.TEXT, 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 1cf191a23d780..49148bb7cb4bf 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 @@ -76,6 +76,7 @@ import { ResponseBodyIndexPolicy, ResponseCheckJSON, ThrottlingConfig, + RequestBodyCheck, } from '../types'; import { AlertConfigKey, ALLOWED_SCHEDULES_IN_MINUTES } from '../constants'; import { getDefaultFormFields } from './defaults'; @@ -718,12 +719,20 @@ export const FIELD = (readOnly?: boolean): FieldMap => ({ validation: () => ({ validate: (headers) => !validateHeaders(headers), }), + dependencies: [ConfigKey.REQUEST_BODY_CHECK], error: i18n.translate('xpack.synthetics.monitorConfig.requestHeaders.error', { defaultMessage: 'Header key must be a valid HTTP token.', }), - props: (): HeaderFieldProps => ({ - readOnly, - }), + // contentMode is optional for other implementations, but required for this implemention of this field + props: ({ + dependencies, + }): HeaderFieldProps & { contentMode: HeaderFieldProps['contentMode'] } => { + const [requestBody] = dependencies; + return { + readOnly, + contentMode: (requestBody as RequestBodyCheck).type, + }; + }, }, [ConfigKey.REQUEST_BODY_CHECK]: { fieldKey: ConfigKey.REQUEST_BODY_CHECK, diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/types.ts b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/types.ts index e43031e4be5d4..3f81386a8cbdd 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/types.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_add_edit/types.ts @@ -18,6 +18,7 @@ import { FormMonitorType, MonitorFields, ResponseCheckJSON, + RequestBodyCheck, } from '../../../../../common/runtime_types/monitor_management'; import { AlertConfigKey } from './constants'; @@ -38,6 +39,7 @@ export interface FormLocation { isServiceManaged: boolean; label: string; } + export type FormConfig = MonitorFields & { isTLSEnabled: boolean; ['schedule.number']: string; @@ -57,6 +59,9 @@ export type FormConfig = MonitorFields & { supported_protocols: MonitorFields[ConfigKey.TLS_VERSION]; }; check: { + request: { + body: RequestBodyCheck; + }; response: { json: ResponseCheckJSON[]; }; 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 8d52cc5713f5b..94501fdccd30b 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -5659,6 +5659,37 @@ } } } + }, + "installation_stats": { + "type": "array", + "items": { + "properties": { + "package_policy_id": { + "type": "keyword" + }, + "feature": { + "type": "keyword" + }, + "package_version": { + "type": "keyword" + }, + "agent_policy_id": { + "type": "keyword" + }, + "deployment_mode": { + "type": "keyword" + }, + "created_at": { + "type": "date" + }, + "created_by": { + "type": "keyword" + }, + "agent_count": { + "type": "long" + } + } + } } } }, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 5574c0cb85a1c..62a79c1cff886 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -8276,7 +8276,6 @@ "xpack.apm.serverlessMetrics.summary.memoryUsageAvg": "Moy. d'utilisation de la mémoire", "xpack.apm.serverlessMetrics.summary.title": "Résumé", "xpack.apm.serviceDependencies.breakdownChartTitle": "Temps consacré par dépendance", - "xpack.apm.serviceDetail.maxGroup.message": "Le serveur APM a atteint la capacité maximale qu'il peut actuellement gérer en matière d'affichage de services individuels. Envisagez d'augmenter la capacité de votre serveur APM et/ou de régler l'instrumentation de l'application afin d'afficher toutes les données.", "xpack.apm.serviceDetails.dependenciesTabLabel": "Dépendances", "xpack.apm.serviceDetails.errorsTabLabel": "Erreurs", "xpack.apm.serviceDetails.metrics.cpuUsageChartTitle": "Utilisation CPU", @@ -8788,7 +8787,6 @@ "xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel": "Afficher la transaction dans Discover", "xpack.apm.transactionBreakdown.chartHelp": "La durée moyenne de chaque type d'intervalle. \"app\" indique que quelque chose se passait au sein du service - cela peut signifier que le temps a été passé dans le code de l'application et non dans la base de données ou les requêtes externes, ou que l'auto-instrumentation de l'agent APM ne couvre pas le code exécuté.", "xpack.apm.transactionBreakdown.chartTitle": "Temps consacré par type d'intervalle", - "xpack.apm.transactionDetail.maxGroup.message": "Le serveur APM a atteint la capacité maximale qu'il peut actuellement gérer en termes d'affichage de groupes de transactions individuels. Envisagez d'augmenter la capacité de votre serveur APM et/ou de régler l'instrumentation de l'application afin d'afficher toutes les données.", "xpack.apm.transactionDetail.remainingServices": "Transactions restantes", "xpack.apm.transactionDetail.tooltip": "Infobulle de nombre maximal de groupes de transactions atteint", "xpack.apm.transactionDetails.coldstartBadge": "démarrage à froid", @@ -20249,7 +20247,6 @@ "xpack.lens.indexPattern.timeShiftMultipleWarning": "{label} utilise un décalage temporel de {columnTimeShift} qui n'est pas un multiple de l'intervalle de l'histogramme des dates de {interval}. Pour éviter une non-correspondance des données, utilisez un multiple de {interval} comme décalage temporel.", "xpack.lens.indexPattern.timeShiftSmallWarning": "{label} utilise un décalage temporel de {columnTimeShift} qui est inférieur à l'intervalle de l'histogramme des dates de {interval}. Pour éviter une non-correspondance des données, utilisez un multiple de {interval} comme décalage temporel.", "xpack.lens.indexPattern.tsdbRollupWarning": "{label} utilise une fonction qui n'est pas prise en charge par les données cumulées. Sélectionnez une autre fonction ou modifiez la plage temporelle.", - "xpack.lens.indexPattern.uniqueLabel": "{label} [{num}]", "xpack.lens.indexPattern.valueCountOf": "Nombre de {name}", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "Afficher uniquement {indexPatternTitle}", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "Afficher uniquement le calque {layerNumber}", @@ -37655,7 +37652,7 @@ "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.days": "{value, plural, one {# jour} other {# jours}}", "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.weeks": "{value, plural, one {# semaine} other {# semaines}}", "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.months": "{value, plural, one {# mois} other {# mois}}", - "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.years": "{value, plural, one {# année} other {# années}}", + "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.years": "{value, plural, one {# année} other {# années}}", "xpack.triggersActionsUI.sections.rulesList.rulesListTable.columns.intervalTooltipText": "L'intervalle de règle de {interval} est inférieur à l'intervalle minimal configuré de {minimumInterval}. Cela peut avoir un impact sur les performances d'alerting.", "xpack.triggersActionsUI.sections.rulesList.rulesListTable.columns.ruleExecutionPercentileTooltip": "{percentileOrdinal} centile des {sampleLimit} dernières durées d'exécution de cette règle (mm:ss).", "xpack.triggersActionsUI.sections.rulesList.selectAllRulesButton": "Tout sélectionner : {formattedTotalRules} {totalRules, plural, =1 {règle} one {règles} many {règles} other {règles}}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7d0b8e2345bca..fbda4b3dfe09c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8276,7 +8276,6 @@ "xpack.apm.serverlessMetrics.summary.memoryUsageAvg": "メモリー使用状況(平均)", "xpack.apm.serverlessMetrics.summary.title": "まとめ", "xpack.apm.serviceDependencies.breakdownChartTitle": "依存関係にかかった時間", - "xpack.apm.serviceDetail.maxGroup.message": "APMサーバーは、個別のサービスを表示する際に現在処理可能な最大能力に達しました。すべてのデータを表示するには、APMサーバーの能力を拡張するか、アプリケーションインストルメンテーションをチューニングすることを検討してください。", "xpack.apm.serviceDetails.dependenciesTabLabel": "依存関係", "xpack.apm.serviceDetails.errorsTabLabel": "エラー", "xpack.apm.serviceDetails.metrics.cpuUsageChartTitle": "CPU 使用状況", @@ -8788,7 +8787,6 @@ "xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel": "Discoverでトランザクションを表示", "xpack.apm.transactionBreakdown.chartHelp": "各スパンタイプの平均期間。「app」はサービス内で何かが発生していたことを示します。これは、データベースや外部リクエストではなく、アプリケーションコードで時間がかかったこと、またはAPMエージェントの自動計測で実行されたコードが明らかにならないことを意味する場合があります。", "xpack.apm.transactionBreakdown.chartTitle": "スパンタイプ別時間", - "xpack.apm.transactionDetail.maxGroup.message": "APMサーバーは、個別のトランザクショングループを表示する際に現在処理可能な最大能力に達しました。すべてのデータを表示するには、APMサーバーの能力を拡張するか、アプリケーションインストルメンテーションをチューニングすることを検討してください。", "xpack.apm.transactionDetail.remainingServices": "残りのトランザクション", "xpack.apm.transactionDetail.tooltip": "最大トランザクショングループが達したときのツールチップ", "xpack.apm.transactionDetails.coldstartBadge": "コールドスタート", @@ -20248,7 +20246,6 @@ "xpack.lens.indexPattern.timeShiftMultipleWarning": "{label}は{columnTimeShift}の時間シフトを使用しています。これは{interval}の日付ヒストグラム間隔の乗数ではありません。不一致のデータを防止するには、時間シフトとして{interval}を使用します。", "xpack.lens.indexPattern.timeShiftSmallWarning": "{label}は{columnTimeShift}の時間シフトを使用しています。これは{interval}の日付ヒストグラム間隔よりも小さいです。不一致のデータを防止するには、時間シフトとして{interval}を使用します。", "xpack.lens.indexPattern.tsdbRollupWarning": "{label}は、ロールアップされたデータによってサポートされていない関数を使用しています。別の関数を選択するか、時間範囲を選択してください。", - "xpack.lens.indexPattern.uniqueLabel": "{label} [{num}]", "xpack.lens.indexPattern.valueCountOf": "{name}のカウント", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "{indexPatternTitle}のみを表示", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "レイヤー{layerNumber}のみを表示", @@ -37625,7 +37622,7 @@ "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.days": "{value, plural, one {# 日} other {# 日}}", "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.weeks": "{value, plural, one {# 週間} other {# 週間}}", "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.months": "{value, plural, one {# 月} other {# 月}}", - "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.years": "{value, plural, one {# 年} other {# 年}}", + "xpack.triggersActionsUI.sections.rulesList.rulesListNotifyBadge.years": "{value, plural, one {# 年} other {# 年}}", "xpack.triggersActionsUI.sections.rulesList.rulesListTable.columns.intervalTooltipText": "ルール間隔{interval}は構成された最小間隔{minimumInterval}を下回ります。これはアラートのパフォーマンスに影響する場合があります。", "xpack.triggersActionsUI.sections.rulesList.rulesListTable.columns.ruleExecutionPercentileTooltip": "このルールの過去の{sampleLimit}実行時間(mm:ss)の{percentileOrdinal}パーセンタイル。", "xpack.triggersActionsUI.sections.rulesList.selectAllRulesButton": "すべての{formattedTotalRules}件の{totalRules, plural, =1 {ルール} other {ルール}}を選択", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index db961e19dda3a..306f183b72169 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8276,7 +8276,6 @@ "xpack.apm.serverlessMetrics.summary.memoryUsageAvg": "平均内存使用率", "xpack.apm.serverlessMetrics.summary.title": "摘要", "xpack.apm.serviceDependencies.breakdownChartTitle": "依赖项花费的时间", - "xpack.apm.serviceDetail.maxGroup.message": "在显示单个服务方面,APM 服务器已达到它当前能够处理的最大容量。请考虑向上扩展 APM 服务器容量和/或调整应用程序检测以查看所有数据。", "xpack.apm.serviceDetails.dependenciesTabLabel": "依赖项", "xpack.apm.serviceDetails.errorsTabLabel": "错误", "xpack.apm.serviceDetails.metrics.cpuUsageChartTitle": "CPU 使用", @@ -8788,7 +8787,6 @@ "xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel": "在 Discover 中查看事务", "xpack.apm.transactionBreakdown.chartHelp": "每种跨度类型的平均持续时间。“应用”表示该服务内有情况发生 — 这可能指在应用程序代码而不是数据库或外部请求中花费的时间,或 APM 代理自动检测未覆盖已执行的代码。", "xpack.apm.transactionBreakdown.chartTitle": "跨度类型花费的时间", - "xpack.apm.transactionDetail.maxGroup.message": "在显示单个事务组方面,APM 服务器已达到它当前能够处理的最大容量。请考虑向上扩展 APM 服务器容量和/或调整应用程序检测以查看所有数据。", "xpack.apm.transactionDetail.remainingServices": "剩余事务", "xpack.apm.transactionDetail.tooltip": "达到最大事务组工具提示", "xpack.apm.transactionDetails.coldstartBadge": "冷启动", @@ -20248,7 +20246,6 @@ "xpack.lens.indexPattern.timeShiftMultipleWarning": "{label} 使用的时间偏移 {columnTimeShift} 不是 Date Histogram 时间间隔 {interval} 的倍数。要防止数据不匹配,请使用 {interval} 的倍数作为时间偏移。", "xpack.lens.indexPattern.timeShiftSmallWarning": "{label} 使用的时间偏移 {columnTimeShift} 小于 Date Histogram 时间间隔 {interval}。要防止数据不匹配,请使用 {interval} 的倍数作为时间偏移。", "xpack.lens.indexPattern.tsdbRollupWarning": "{label} 使用的函数不受汇总/打包数据支持。请选择其他函数,或更改时间范围。", - "xpack.lens.indexPattern.uniqueLabel": "{label} [{num}]", "xpack.lens.indexPattern.valueCountOf": "{name} 的计数", "xpack.lens.indexPatternSuggestion.removeLayerLabel": "仅显示 {indexPatternTitle}", "xpack.lens.indexPatternSuggestion.removeLayerPositionLabel": "仅显示图层 {layerNumber}", diff --git a/x-pack/test/apm_api_integration/tests/alerts/chart_preview.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/chart_preview.spec.ts deleted file mode 100644 index f95bb8de59a89..0000000000000 --- a/x-pack/test/apm_api_integration/tests/alerts/chart_preview.spec.ts +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import archives from '../../common/fixtures/es_archiver/archives_metadata'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const archiveName = 'apm_8.0.0'; - const { end } = archives[archiveName]; - const start = new Date(Date.parse(end) - 600000).toISOString(); - - const getOptions = () => ({ - params: { - query: { - start, - end, - serviceName: 'opbeans-java', - transactionType: 'request' as string | undefined, - environment: 'ENVIRONMENT_ALL', - interval: '5m', - }, - }, - }); - - registry.when(`without data loaded`, { config: 'basic', archives: [] }, () => { - it('transaction_error_rate (without data)', async () => { - const options = getOptions(); - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect(response.body.errorRateChartPreview).to.eql([]); - }); - - it('error_count (without data)', async () => { - const options = getOptions(); - options.params.query.transactionType = undefined; - - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect(response.body.errorCountChartPreview).to.eql([]); - }); - - it('transaction_duration (without data)', async () => { - const options = getOptions(); - - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect(response.body.latencyChartPreview).to.eql([]); - }); - }); - - registry.when(`with data loaded`, { config: 'basic', archives: [archiveName] }, () => { - it('transaction_error_rate (with data)', async () => { - const options = getOptions(); - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect( - response.body.errorRateChartPreview.some( - (item: { x: number; y: number | null }) => item.x && item.y - ) - ).to.equal(true); - }); - - it('transaction_error_rate with transaction name', async () => { - const options = { - params: { - query: { - start, - end, - serviceName: 'opbeans-java', - transactionName: 'APIRestController#product', - transactionType: 'request', - environment: 'ENVIRONMENT_ALL', - interval: '5m', - }, - }, - }; - - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect(response.body.errorRateChartPreview[0]).to.eql({ - x: 1627974600000, - y: 1, - }); - }); - - it('transaction_error_rate with nonexistent transaction name', async () => { - const options = { - params: { - query: { - start, - end, - serviceName: 'opbeans-java', - transactionName: 'foo', - transactionType: 'request', - environment: 'ENVIRONMENT_ALL', - interval: '5m', - }, - }, - }; - - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect( - response.body.errorRateChartPreview.every( - (item: { x: number; y: number | null }) => item.y === null - ) - ).to.equal(true); - }); - - it('error_count (with data)', async () => { - const options = getOptions(); - options.params.query.transactionType = undefined; - - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect( - response.body.errorCountChartPreview.some( - (item: { x: number; y: number | null }) => item.x && item.y - ) - ).to.equal(true); - }); - - it('error_count with error grouping key', async () => { - const options = { - params: { - query: { - start, - end, - serviceName: 'opbeans-java', - errorGroupingKey: 'd16d39e7fa133b8943cea035430a7b4e', - environment: 'ENVIRONMENT_ALL', - interval: '5m', - }, - }, - }; - - const response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', - ...options, - }); - - expect(response.status).to.be(200); - expect(response.body.errorCountChartPreview).to.eql([ - { x: 1627974600000, y: 4 }, - { x: 1627974900000, y: 2 }, - { x: 1627975200000, y: 0 }, - ]); - }); - - it('transaction_duration (with data)', async () => { - const options = getOptions(); - const response = await apmApiClient.readUser({ - ...options, - endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', - }); - - expect(response.status).to.be(200); - expect( - response.body.latencyChartPreview.some( - (item: { name: string; data: Array<{ x: number; y: number | null }> }) => - item.data.some((coordinate) => coordinate.x && coordinate.y) - ) - ).to.equal(true); - }); - - it('transaction_duration with transaction name', async () => { - const options = { - params: { - query: { - start, - end, - serviceName: 'opbeans-java', - transactionName: 'DispatcherServlet#doGet', - transactionType: 'request', - environment: 'ENVIRONMENT_ALL', - interval: '5m', - }, - }, - }; - const response = await apmApiClient.readUser({ - ...options, - endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', - }); - - expect(response.status).to.be(200); - expect(response.body.latencyChartPreview[0].data[0]).to.eql({ - x: 1627974600000, - y: 18485.85714285714, - }); - }); - - it('transaction_duration with nonexistent transaction name', async () => { - const options = { - params: { - query: { - start, - end, - serviceName: 'opbeans-java', - transactionType: 'request', - transactionName: 'foo', - environment: 'ENVIRONMENT_ALL', - interval: '5m', - }, - }, - }; - const response = await apmApiClient.readUser({ - ...options, - endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', - }); - - expect(response.status).to.be(200); - expect(response.body.latencyChartPreview).to.eql([]); - }); - }); -} diff --git a/x-pack/test/apm_api_integration/tests/alerts/generate_data.ts b/x-pack/test/apm_api_integration/tests/alerts/generate_data.ts new file mode 100644 index 0000000000000..2765c0a1e265b --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/alerts/generate_data.ts @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; + +export const config = { + appleTransaction: { + name: 'GET /apple', + successRate: 75, + failureRate: 25, + }, + bananaTransaction: { + name: 'GET /banana', + successRate: 50, + failureRate: 50, + }, +}; + +export async function generateLatencyData({ + synthtraceEsClient, + serviceName, + start, + end, +}: { + synthtraceEsClient: ApmSynthtraceEsClient; + serviceName: string; + start: number; + end: number; +}) { + const serviceInstance = apm + .service({ name: serviceName, environment: 'production', agentName: 'go' }) + .instance('instance-a'); + + const interval = '1m'; + + const { bananaTransaction, appleTransaction } = config; + + const documents = [ + timerange(start, end) + .interval(interval) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: appleTransaction.name }) + .timestamp(timestamp) + .duration(10) + ), + timerange(start, end) + .interval(interval) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: bananaTransaction.name }) + .timestamp(timestamp) + .duration(5) + ), + ]; + + await synthtraceEsClient.index(documents); +} + +export async function generateErrorData({ + synthtraceEsClient, + serviceName, + start, + end, +}: { + synthtraceEsClient: ApmSynthtraceEsClient; + serviceName: string; + start: number; + end: number; +}) { + const serviceInstance = apm + .service({ name: serviceName, environment: 'production', agentName: 'go' }) + .instance('instance-a'); + + const interval = '1m'; + + const { bananaTransaction, appleTransaction } = config; + + const documents = [appleTransaction, bananaTransaction].flatMap((transaction, index) => { + return [ + timerange(start, end) + .interval(interval) + .rate(transaction.successRate) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: transaction.name }) + .timestamp(timestamp) + .duration(10) + .success() + ), + timerange(start, end) + .interval(interval) + .rate(transaction.failureRate) + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: transaction.name }) + .errors( + serviceInstance + .error({ message: `Error ${index}`, type: transaction.name }) + .timestamp(timestamp) + ) + .duration(10) + .timestamp(timestamp) + .failure() + ), + ]; + }); + + await synthtraceEsClient.index(documents); +} diff --git a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_count.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_count.spec.ts new file mode 100644 index 0000000000000..959a1567c6c8e --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_count.spec.ts @@ -0,0 +1,285 @@ +/* + * Copyright 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 { + SERVICE_ENVIRONMENT, + SERVICE_NAME, + ERROR_GROUP_ID, +} from '@kbn/apm-plugin/common/es_fields/apm'; +import type { PreviewChartResponseItem } from '@kbn/apm-plugin/server/routes/alerts/route'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { generateErrorData } from './generate_data'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + + const getOptions = () => ({ + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }); + + registry.when(`without data loaded`, { config: 'basic', archives: [] }, () => { + it('error_count (without data)', async () => { + const options = getOptions(); + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series).to.eql([]); + }); + }); + + registry.when(`with data loaded`, { config: 'basic', archives: [] }, () => { + describe('error_count', () => { + before(async () => { + await generateErrorData({ serviceName: 'synth-go', start, end, synthtraceEsClient }); + await generateErrorData({ serviceName: 'synth-java', start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + it('with data', async () => { + const options = getOptions(); + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.some((item: PreviewChartResponseItem) => + item.data.some((coordinate) => coordinate.x && coordinate.y) + ) + ).to.equal(true); + }); + + it('with error grouping key', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + errorGroupingKey: '98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production', y: 250 }]); + }); + + it('with no group by parameter', async () => { + const options = getOptions(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(1); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production', y: 375 }]); + }); + + it('with default group by fields', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(1); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production', y: 375 }]); + }); + + it('with group by on error grouping key', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, ERROR_GROUP_ID], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(2); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: 'synth-go_production_98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + y: 250, + }, + { + name: 'synth-go_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + y: 125, + }, + ]); + }); + + it('with group by on error grouping key and filter on error grouping key', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + errorGroupingKey: 'cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, ERROR_GROUP_ID], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorCountChartPreview.series.length).to.equal(1); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: 'synth-go_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + y: 125, + }, + ]); + }); + + it('with empty service name', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: '', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production', y: 375 }, + { name: 'synth-java_production', y: 375 }, + ]); + }); + + it('with empty service name and group by on error grouping key', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: '', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, ERROR_GROUP_ID], + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/error_count/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorCountChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: 'synth-go_production_98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + y: 250, + }, + { + name: 'synth-java_production_98b75903135eac35ad42419bd3b45cf8b4270c61cbd0ede0f7e8c8a9ac9fdb03', + y: 250, + }, + { + name: 'synth-go_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + y: 125, + }, + { + name: 'synth-java_production_cf676a2665c3c548caaab78db6d23af63aed81bff4360a5b9873c07443aee78c', + y: 125, + }, + ]); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_rate.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_rate.spec.ts new file mode 100644 index 0000000000000..c3840aaff7571 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_error_rate.spec.ts @@ -0,0 +1,309 @@ +/* + * Copyright 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 { + SERVICE_ENVIRONMENT, + SERVICE_NAME, + TRANSACTION_NAME, + TRANSACTION_TYPE, +} from '@kbn/apm-plugin/common/es_fields/apm'; +import type { PreviewChartResponseItem } from '@kbn/apm-plugin/server/routes/alerts/route'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { generateErrorData } from './generate_data'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + + const getOptions = () => ({ + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + transactionType: 'request', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }); + + registry.when(`without data loaded`, { config: 'basic', archives: [] }, () => { + it('transaction_error_rate without data', async () => { + const options = getOptions(); + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series).to.eql([]); + }); + }); + + registry.when(`with data loaded`, { config: 'basic', archives: [] }, () => { + describe('transaction_error_rate', () => { + before(async () => { + await generateErrorData({ serviceName: 'synth-go', start, end, synthtraceEsClient }); + await generateErrorData({ serviceName: 'synth-java', start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + it('with data', async () => { + const options = getOptions(); + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.some((item: PreviewChartResponseItem) => + item.data.some((coordinate) => coordinate.x && coordinate.y) + ) + ).to.equal(true); + }); + + it('with transaction name', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + transactionName: 'GET /banana', + transactionType: 'request', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 50 }]); + }); + + it('with nonexistent transaction name', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + transactionName: 'foo', + transactionType: 'request', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series).to.eql([]); + }); + + it('with no group by parameter', async () => { + const options = getOptions(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(1); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 37.5 }]); + }); + + it('with default group by fields', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(1); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 37.5 }]); + }); + + it('with group by on transaction name', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(2); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: 'synth-go_production_request_GET /banana', + y: 50, + }, + { + name: 'synth-go_production_request_GET /apple', + y: 25, + }, + ]); + }); + + it('with group by on transaction name and filter on transaction name', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + transactionName: 'GET /apple', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.errorRateChartPreview.series.length).to.equal(1); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request_GET /apple', y: 25 }]); + }); + + it('with empty service name, transaction name and transaction type', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: '', + transactionName: '', + transactionType: '', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request', y: 37.5 }, + { name: 'synth-java_production_request', y: 37.5 }, + ]); + }); + + it('with empty service name, transaction name, transaction type and group by on transaction name', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: '', + transactionName: '', + transactionType: '', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_error_rate/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.errorRateChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { + name: 'synth-go_production_request_GET /banana', + y: 50, + }, + { + name: 'synth-java_production_request_GET /banana', + y: 50, + }, + { + name: 'synth-go_production_request_GET /apple', + y: 25, + }, + { + name: 'synth-java_production_request_GET /apple', + y: 25, + }, + ]); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/alerts/preview_chart_transaction_duration.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_transaction_duration.spec.ts new file mode 100644 index 0000000000000..ccb7fec009df3 --- /dev/null +++ b/x-pack/test/apm_api_integration/tests/alerts/preview_chart_transaction_duration.spec.ts @@ -0,0 +1,291 @@ +/* + * Copyright 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 { + SERVICE_ENVIRONMENT, + SERVICE_NAME, + TRANSACTION_NAME, + TRANSACTION_TYPE, +} from '@kbn/apm-plugin/common/es_fields/apm'; +import type { PreviewChartResponseItem } from '@kbn/apm-plugin/server/routes/alerts/route'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { generateLatencyData } from './generate_data'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const apmApiClient = getService('apmApiClient'); + const synthtraceEsClient = getService('synthtraceEsClient'); + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + + const getOptions = () => ({ + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + transactionType: 'request', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }); + + registry.when(`without data loaded`, { config: 'basic', archives: [] }, () => { + it('transaction_duration (without data)', async () => { + const options = getOptions(); + + const response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + ...options, + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series).to.eql([]); + }); + }); + + registry.when(`with data loaded`, { config: 'basic', archives: [] }, () => { + describe('transaction_duration', () => { + before(async () => { + await generateLatencyData({ serviceName: 'synth-go', start, end, synthtraceEsClient }); + await generateLatencyData({ serviceName: 'synth-java', start, end, synthtraceEsClient }); + }); + + after(() => synthtraceEsClient.clean()); + + it('with data', async () => { + const options = getOptions(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.latencyChartPreview.series.some((item: PreviewChartResponseItem) => + item.data.some((coordinate) => coordinate.x && coordinate.y) + ) + ).to.equal(true); + }); + + it('with transaction name', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + transactionName: 'GET /banana', + transactionType: 'request', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 5000 }]); + }); + + it('with nonexistent transaction name', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: 'synth-go', + transactionType: 'request', + transactionName: 'foo', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series).to.eql([]); + }); + + it('with no group by parameter', async () => { + const options = getOptions(); + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(1); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 7500 }]); + }); + + it('with default group by fields', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(1); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request', y: 7500 }]); + }); + + it('with group by on transaction name', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(2); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request_GET /apple', y: 10000 }, + { name: 'synth-go_production_request_GET /banana', y: 5000 }, + ]); + }); + + it('with group by on transaction name and filter on transaction name', async () => { + const options = { + params: { + query: { + ...getOptions().params.query, + transactionName: 'GET /apple', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(1); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([{ name: 'synth-go_production_request_GET /apple', y: 10000 }]); + }); + + it('with empty service name, transaction name and transaction type', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: '', + transactionName: '', + transactionType: '', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request', y: 7500 }, + { name: 'synth-java_production_request', y: 7500 }, + ]); + }); + + it('with empty service name, transaction name, transaction type and group by on transaction name', async () => { + const options = { + params: { + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + serviceName: '', + transactionName: '', + transactionType: '', + environment: 'ENVIRONMENT_ALL', + interval: '5m', + groupBy: [SERVICE_NAME, SERVICE_ENVIRONMENT, TRANSACTION_TYPE, TRANSACTION_NAME], + }, + }, + }; + const response = await apmApiClient.readUser({ + ...options, + endpoint: 'GET /internal/apm/rule_types/transaction_duration/chart_preview', + }); + + expect(response.status).to.be(200); + expect(response.body.latencyChartPreview.series.length).to.equal(4); + expect( + response.body.latencyChartPreview.series.map((item: PreviewChartResponseItem) => ({ + name: item.name, + y: item.data[0].y, + })) + ).to.eql([ + { name: 'synth-go_production_request_GET /apple', y: 10000 }, + { name: 'synth-java_production_request_GET /apple', y: 10000 }, + { name: 'synth-go_production_request_GET /banana', y: 5000 }, + { name: 'synth-java_production_request_GET /banana', y: 5000 }, + ]); + }); + }); + }); +} diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts index e4861323934f1..60b1e789ec775 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/cases/find_cases.ts @@ -92,6 +92,29 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + it('can filter by reserved kql characters in tags', async () => { + const tagsColon = ['super:bad:case']; + const tagsSlashQuote = ['awesome\\"']; + + const postedCase1 = await createCase(supertest, { ...postCaseReq, tags: tagsSlashQuote }); + const postedCase2 = await createCase(supertest, { + ...postCaseReq, + tags: tagsColon, + }); + + const cases = await findCases({ + supertest, + query: { tags: [...tagsColon, ...tagsSlashQuote] }, + }); + + expect(cases).to.eql({ + ...findCasesResp, + total: 2, + cases: [postedCase1, postedCase2], + count_open_cases: 2, + }); + }); + it('filters by status', async () => { await createCase(supertest, postCaseReq); const toCloseCase = await createCase(supertest, postCaseReq); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts index 35fa1e5acd75e..ebf7b6888fbb9 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/cases/assignees.ts @@ -189,6 +189,30 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + it('filters cases using an assignee uid with a colon in it', async () => { + await createCase(supertest, postCaseReq); + + const assigneeUid = 'abc:uid:123'; + const caseWithColonAssignee = await createCase( + supertest, + getPostCaseRequest({ + assignees: [{ uid: 'abc:uid:123' }], + }) + ); + + const cases = await findCases({ + supertest, + query: { assignees: [assigneeUid] }, + }); + + expect(cases).to.eql({ + ...findCasesResp, + total: 1, + cases: [caseWithColonAssignee], + count_open_cases: 1, + }); + }); + it("filters cases using the assigned users by constructing an or'd filter", async () => { const profileUidsToFilter = await suggestUserProfiles({ supertest: supertestWithoutAuth, diff --git a/x-pack/test/cloud_integration/config.ts b/x-pack/test/cloud_integration/config.ts index efa0096e5a199..6ce2950753394 100644 --- a/x-pack/test/cloud_integration/config.ts +++ b/x-pack/test/cloud_integration/config.ts @@ -95,7 +95,15 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { 'dateFormat:tz': 'UTC', }, }, - apps: kibanaFunctionalConfig.get('apps'), + apps: { + ...kibanaFunctionalConfig.get('apps'), + observability: { + pathname: '/app/observability', + }, + security: { + pathname: '/app/security', + }, + }, screenshots: { directory: resolve(__dirname, 'screenshots') }, junit: { diff --git a/x-pack/test/cloud_integration/tests/chat.ts b/x-pack/test/cloud_integration/tests/chat.ts index 25bb869805d12..8e60ef842896a 100644 --- a/x-pack/test/cloud_integration/tests/chat.ts +++ b/x-pack/test/cloud_integration/tests/chat.ts @@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('chat widget is present on integrations page', async () => { - PageObjects.common.navigateToUrl('integrations', 'browse', { + await PageObjects.common.navigateToUrl('integrations', 'browse', { useActualUrl: true, shouldUseHashForSubUrl: false, }); @@ -29,15 +29,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('chat widget is present on home getting_started page', async () => { - PageObjects.common.navigateToUrl('home', '/getting_started', { + await PageObjects.common.navigateToUrl('home', '/getting_started', { useActualUrl: true, shouldUseHashForSubUrl: true, }); await testSubjects.existOrFail('cloud-chat'); }); - it('chat widget is present on management page', async () => { - PageObjects.common.navigateToApp('management'); + it('chat widget is present on observability/overview page', async () => { + await PageObjects.common.navigateToUrl('observability', '/overview', { + useActualUrl: true, + shouldUseHashForSubUrl: true, + }); + await testSubjects.existOrFail('cloud-chat'); + }); + + it('chat widget is present on security/get_started page', async () => { + await PageObjects.common.navigateToUrl('security', '/get_started', { + useActualUrl: true, + shouldUseHashForSubUrl: true, + }); await testSubjects.existOrFail('cloud-chat'); }); }); diff --git a/x-pack/test/functional/apps/discover/visualize_field.ts b/x-pack/test/functional/apps/discover/visualize_field.ts index cfafd4e77b5d5..b210147132dcc 100644 --- a/x-pack/test/functional/apps/discover/visualize_field.ts +++ b/x-pack/test/functional/apps/discover/visualize_field.ts @@ -38,7 +38,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.timePicker.setDefaultAbsoluteRange(); } - describe('discover field visualize button', () => { + // FLAKY: https://github.com/elastic/kibana/issues/148225 + describe.skip('discover field visualize button', () => { before(async () => { await kibanaServer.uiSettings.replace(defaultSettings); }); diff --git a/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts b/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts index b0e1a0208bd57..ca1060c2249e9 100644 --- a/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts +++ b/x-pack/test/functional/apps/graph/feature_controls/graph_security.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const security = getService('security'); - const PageObjects = getPageObjects(['common', 'graph', 'security', 'error']); + const PageObjects = getPageObjects(['common', 'graph', 'security', 'error', 'header']); const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); const globalNav = getService('globalNav'); @@ -29,8 +29,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.security.forceLogout(); }); - // FLAKY: https://github.com/elastic/kibana/issues/53204 - describe.skip('global graph all privileges', () => { + describe('global graph all privileges', () => { before(async () => { await security.role.create('global_graph_all_role', { elasticsearch: { @@ -73,6 +72,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('landing page shows "Create new graph" button', async () => { await PageObjects.common.navigateToApp('graph'); + await PageObjects.header.waitUntilLoadingHasFinished(); await testSubjects.existOrFail('graphLandingPage', { timeout: 10000 }); await testSubjects.existOrFail('graphCreateGraphPromptButton'); }); @@ -83,6 +83,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('allows creating a new workspace', async () => { await PageObjects.common.navigateToApp('graph'); + await PageObjects.header.waitUntilLoadingHasFinished(); await testSubjects.click('graphCreateGraphPromptButton'); const breadcrumb = await testSubjects.find('~graphCurrentGraphBreadcrumb'); expect(await breadcrumb.getVisibleText()).to.equal('Unsaved graph'); @@ -136,6 +137,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('does not show a "Create new Workspace" button', async () => { await PageObjects.common.navigateToApp('graph'); + await PageObjects.header.waitUntilLoadingHasFinished(); await testSubjects.existOrFail('graphLandingPage', { timeout: 10000 }); await testSubjects.missingOrFail('newItemButton'); }); diff --git a/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts b/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts index c3b0804d2964a..af03a827a43e8 100644 --- a/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts +++ b/x-pack/test/functional/apps/graph/feature_controls/graph_spaces.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const spacesService = getService('spaces'); - const PageObjects = getPageObjects(['common', 'graph', 'security', 'error']); + const PageObjects = getPageObjects(['common', 'graph', 'security', 'error', 'header']); const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); @@ -36,6 +36,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.common.navigateToApp('home', { basePath: '/s/custom_space', }); + await PageObjects.header.waitUntilLoadingHasFinished(); const navLinks = (await appsMenu.readLinks()).map((link) => link.text); expect(navLinks).to.contain('Graph'); }); @@ -44,6 +45,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.common.navigateToApp('graph', { basePath: '/s/custom_space', }); + await PageObjects.header.waitUntilLoadingHasFinished(); await testSubjects.existOrFail('graphLandingPage', { timeout: 10000 }); await testSubjects.existOrFail('graphCreateGraphPromptButton'); }); @@ -52,6 +54,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.common.navigateToApp('graph', { basePath: '/s/custom_space', }); + await PageObjects.header.waitUntilLoadingHasFinished(); await testSubjects.click('graphCreateGraphPromptButton'); const breadcrumb = await testSubjects.find('~graphCurrentGraphBreadcrumb'); expect(await breadcrumb.getVisibleText()).to.equal('Unsaved graph'); @@ -75,6 +78,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.common.navigateToApp('home', { basePath: '/s/custom_space', }); + await PageObjects.header.waitUntilLoadingHasFinished(); const navLinks = (await appsMenu.readLinks()).map((link) => link.text); expect(navLinks).not.to.contain('Graph'); }); diff --git a/x-pack/test/functional/apps/spaces/enter_space.ts b/x-pack/test/functional/apps/spaces/enter_space.ts index 4e7655add8667..caae7bad10b0f 100644 --- a/x-pack/test/functional/apps/spaces/enter_space.ts +++ b/x-pack/test/functional/apps/spaces/enter_space.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { stripVersionQualifier } from '@kbn/std'; import { FtrProviderContext } from '../../ftr_provider_context'; export default function enterSpaceFunctionalTests({ @@ -32,7 +33,7 @@ export default function enterSpaceFunctionalTests({ { space: 'another-space' } ); const config = await kibanaServer.savedObjects.get({ - id: await kibanaServer.version.get(), + id: stripVersionQualifier(await kibanaServer.version.get()), type: 'config', }); await kibanaServer.savedObjects.update({ diff --git a/x-pack/test/functional/apps/visualize/precalculated_histogram.ts b/x-pack/test/functional/apps/visualize/precalculated_histogram.ts index 5ba6bba93b2c8..7fcc0bf432d52 100644 --- a/x-pack/test/functional/apps/visualize/precalculated_histogram.ts +++ b/x-pack/test/functional/apps/visualize/precalculated_histogram.ts @@ -40,8 +40,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowData).to.contain('"values":[0.3,1,3,4.2,4.8]'); }); - // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/159615 - describe.skip('works in visualizations', () => { + describe('works in visualizations', () => { before(async () => { await PageObjects.visualize.navigateToNewAggBasedVisualization(); await PageObjects.visualize.clickDataTable(); @@ -63,7 +62,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(data[0]).to.have.property('length', 7); // Percentile values are not deterministic, so we can't check for the exact values here, // but just check they are all within the given range - // see https://github.com/elastic/elasticsearch/issues/49225 expect(data[0].every((p: string) => Number(p) >= 0.3 && Number(p) <= 5)).to.be(true); }); @@ -78,13 +76,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('with median aggregation', async () => { - // Percentile values (which are used by median behind the scenes) are not deterministic, - // so we can't check for the exact values here, but just check they are all within the given range - // see https://github.com/elastic/elasticsearch/issues/49225 const data = await renderTableForAggregation('Median'); const value = Number(data[0][0]); - expect(value).to.be.above(3.0); - expect(value).to.be.below(3.3); + // Percentile values are not deterministic, so we can't check for the exact values here, + // but just check they are all within the given range + expect(value).to.be.above(2.9); + expect(value).to.be.below(3.1); }); it('with sum aggregation', async () => {