diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ef00064eb4b47..7076bd3fe6cf3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -578,7 +578,7 @@ packages/kbn-securitysolution-utils @elastic/security-solution-platform packages/kbn-server-http-tools @elastic/kibana-core packages/kbn-server-route-repository @elastic/apm-ui x-pack/plugins/serverless @elastic/appex-sharedux -x-pack/plugins/serverless_observability @elastic/appex-sharedux +x-pack/plugins/serverless_observability @elastic/appex-sharedux @elastic/apm-ui packages/serverless/project_switcher @elastic/appex-sharedux x-pack/plugins/serverless_search @elastic/enterprise-search-frontend x-pack/plugins/serverless_security @elastic/security-solution diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 69ebbf70dc3fe..ac57d68c018a0 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-05-26 +date: 2023-05-30 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 108f55f51a631..2daee77e515d1 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-05-26 +date: 2023-05-30 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 14217bde2c966..19586b64d82de 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-05-26 +date: 2023-05-30 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 2b58e26ba8842..40392401fee29 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index bee801f63aa06..49f8cb9541926 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -601,7 +601,23 @@ "GetResponse", ">; delete: (deleteParams: { id: string; }) => Promise<", "WriteResponseBase", - ">; } | undefined>; }; start: () => Promise; }; ruleRegistry: { setup: ", + ">; } | undefined>; alertsLocator: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + { + "pluginId": "observability", + "scope": "common", + "docId": "kibObservabilityPluginApi", + "section": "def-common.AlertsLocatorParams", + "text": "AlertsLocatorParams" + }, + ">; }; start: () => Promise; }; ruleRegistry: { setup: ", { "pluginId": "ruleRegistry", "scope": "server", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 3f16c8bdafddf..ebe27f54815af 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-05-26 +date: 2023-05-30 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 b8ef6d0688ea0..161df64f8c686 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-05-26 +date: 2023-05-30 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 eec5247737cbf..dbb5eeb29d544 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-05-26 +date: 2023-05-30 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 a8ff5fb4353af..07ab6976fdc01 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-05-26 +date: 2023-05-30 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 caf06565c430c..36c312fa6825d 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 1f9c60e7b32bb..9db7c70ed2ba5 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index fbf5fa9bbd5db..4058592aea695 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-05-26 +date: 2023-05-30 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 5d687088b1952..8ce5200617925 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-05-26 +date: 2023-05-30 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 35c23ae1ab263..3bfb8966370af 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index eb9db2544fc3a..92ceba501e2b7 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-05-26 +date: 2023-05-30 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 729106086ffff..bfdf6622fbbc8 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-05-26 +date: 2023-05-30 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 cd5052cb68829..55df360182196 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-05-26 +date: 2023-05-30 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 266a2cd19919e..33552be7f3040 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-05-26 +date: 2023-05-30 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 ab30de563d10d..e5f524bbb21c6 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-05-26 +date: 2023-05-30 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 71ce6cdb18886..382bec681204c 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-05-26 +date: 2023-05-30 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 740a53df71eeb..7d14e1b950a76 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-05-26 +date: 2023-05-30 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 2c6a345eb0cca..b64ca65d9f6be 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-05-26 +date: 2023-05-30 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 b03de93b640e8..c7f10b622b30c 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-05-26 +date: 2023-05-30 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 ffdc8fba57c90..ad3e3350b7f32 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-05-26 +date: 2023-05-30 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 38b6726215403..4b287fb836670 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 8afca470ffa0d..282f20f3f7d77 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 541f288a3b13f..4d036117e500c 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 4be7e0d96f43a..0d2d473a7ddcc 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-05-26 +date: 2023-05-30 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 c7d01259567cd..eccab0cfdd985 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-05-26 +date: 2023-05-30 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 1ee1cf553edb8..eeca946c576a6 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-05-26 +date: 2023-05-30 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 00c66fee123ed..3480770eb1ff2 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-05-26 +date: 2023-05-30 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 95f7cabc3d665..e81cb48b21ec1 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-05-26 +date: 2023-05-30 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 125476b4e6c77..8f979314d3208 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -23,9 +23,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | home, data, esUiShared, spaces, savedObjectsManagement, exploratoryView, fleet, observability, ml, apm, indexLifecycleManagement, observabilityOnboarding, synthetics, upgradeAssistant, ux, kibanaOverview | - | | | encryptedSavedObjects, actions, data, ml, logstash, securitySolution, cloudChat | - | | | actions, ml, savedObjectsTagging, enterpriseSearch | - | -| | @kbn/core-plugins-browser-internal, @kbn/core-root-browser-internal, dataViews, home, data, savedObjects, unifiedSearch, presentationUtil, visualizations, dashboard, lens, discover, fileUpload, ml, fleet, canvas, dashboardEnhanced, graph, monitoring, synthetics, transform, dataVisualizer, cloudSecurityPosture | - | -| | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, home, savedObjects, savedSearch, visualizations, dashboard, lens, ml, canvas, graph, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | -| | @kbn/core-saved-objects-browser-mocks, savedObjects, presentationUtil, savedSearch, dashboard, ml, cloudSecurityPosture, dashboardEnhanced, graph, @kbn/core-saved-objects-browser-internal | - | +| | @kbn/core-plugins-browser-internal, @kbn/core-root-browser-internal, dataViews, home, data, savedObjects, unifiedSearch, presentationUtil, visualizations, dashboard, lens, discover, fileUpload, ml, fleet, canvas, dashboardEnhanced, monitoring, synthetics, transform, dataVisualizer, cloudSecurityPosture | - | +| | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, dataViews, home, savedObjects, savedSearch, visualizations, dashboard, lens, ml, canvas, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | +| | @kbn/core-saved-objects-browser-mocks, savedObjects, presentationUtil, savedSearch, dashboard, ml, cloudSecurityPosture, dashboardEnhanced, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-mocks, dataViews, savedObjects, dashboard, ml, cloudSecurityPosture, dashboardEnhanced, monitoring, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjects, embeddable, presentationUtil, visualizations, dashboard, aiops, ml, dataVisualizer, fleet, cloudSecurityPosture, dashboardEnhanced, graph, synthetics, lens, securitySolution, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core-lifecycle-browser-mocks, @kbn/core, ml, dashboard, dataViews, savedSearch, @kbn/core-plugins-browser-internal | - | @@ -42,7 +42,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-migration-server-internal, actions, dataViews, data, alerting, lens, cases, savedObjectsTagging, visualizations, savedSearch, canvas, graph, lists, maps, securitySolution, dashboard, @kbn/core-test-helpers-so-type-serializer | - | | | discover | - | | | data, discover, imageEmbeddable, embeddable | - | -| | @kbn/core-saved-objects-browser-mocks, dataViews, savedSearch, dashboard, graph, discover, @kbn/core-saved-objects-browser-internal | - | +| | @kbn/core-saved-objects-browser-mocks, dataViews, savedSearch, dashboard, discover, @kbn/core-saved-objects-browser-internal | - | | | advancedSettings, discover | - | | | securitySolution | - | | | securitySolution | - | @@ -65,9 +65,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | securitySolution | - | | | monitoring | - | | | @kbn/core-saved-objects-api-browser, @kbn/core, savedObjects, savedObjectsManagement, visualizations, savedObjectsTagging, lens, fleet, graph, dashboard, savedObjectsTaggingOss, kibanaUtils, expressions, dataViews, data, embeddable, controls, uiActionsEnhanced, cases, maps, canvas, dashboardEnhanced, globalSearchProviders, infra | - | -| | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, savedObjects, savedSearch, dashboard, graph | - | +| | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, savedObjects, savedSearch, dashboard | - | | | @kbn/core-saved-objects-browser-mocks, home, @kbn/core-saved-objects-browser-internal | - | -| | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, savedObjects, visualizations, dashboard, graph | - | +| | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-browser-mocks, savedObjects, visualizations, dashboard | - | | | @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-mocks, dashboard, savedObjects, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-mocks, fleet, synthetics, @kbn/core-saved-objects-browser-internal | - | @@ -76,7 +76,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-internal | - | | | @kbn/core-saved-objects-browser-internal | - | -| | @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjects, visualizations | - | +| | @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjects, visualizations, graph | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server-internal, canvas | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index f0b686304a568..6016b90ab5fe6 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -731,13 +731,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [deserialize.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/deserialize.ts#:~:text=getNonScriptedFields), [datasource.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/state_management/datasource.test.ts#:~:text=getNonScriptedFields), [deserialize.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/deserialize.test.ts#:~:text=getNonScriptedFields), [deserialize.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/deserialize.test.ts#:~:text=getNonScriptedFields) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/server/plugin.ts#:~:text=license%24) | 8.8.0 | | | [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/components/save_modal.tsx#:~:text=SavedObjectSaveModal), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/components/save_modal.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | -| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/plugin.ts#:~:text=savedObjects) | - | -| | [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/save_modal.tsx#:~:text=SavedObjectsClientContract), [save_modal.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/save_modal.tsx#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectsClientContract), [store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/state_management/store.ts#:~:text=SavedObjectsClientContract), [store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/state_management/store.ts#:~:text=SavedObjectsClientContract), [use_workspace_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts#:~:text=SavedObjectsClientContract)+ 5 more | - | -| | [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=create), [saved_workspace_utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts#:~:text=create) | - | -| | [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=delete) | - | -| | [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=find), [saved_workspace_utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts#:~:text=find) | - | -| | [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=resolve) | - | -| | [app_state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/types/app_state.ts#:~:text=SimpleSavedObject), [app_state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/types/app_state.ts#:~:text=SimpleSavedObject) | - | +| | [app_state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/types/app_state.ts#:~:text=SimpleSavedObject), [app_state.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/types/app_state.ts#:~:text=SimpleSavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.test.ts#:~:text=SimpleSavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.test.ts#:~:text=SimpleSavedObject) | - | +| | [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_objects_utils/save_with_confirmation.ts#:~:text=SavedObjectsCreateOptions), [save_with_confirmation.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_objects_utils/save_with_confirmation.ts#:~:text=SavedObjectsCreateOptions) | - | | | [use_workspace_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts#:~:text=ResolvedSimpleSavedObject), [use_workspace_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts#:~:text=ResolvedSimpleSavedObject), [use_workspace_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts#:~:text=ResolvedSimpleSavedObject), [use_workspace_loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts#:~:text=ResolvedSimpleSavedObject) | - | | | [saved_workspace_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/saved_workspace_references.ts#:~:text=SavedObjectAttributes), [saved_workspace_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/saved_workspace_references.ts#:~:text=SavedObjectAttributes), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectAttributes), [saved_workspace_utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts#:~:text=SavedObjectAttributes) | - | | | [saved_workspace_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/saved_workspace_references.ts#:~:text=SavedObjectReference), [saved_workspace_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/saved_workspace_references.ts#:~:text=SavedObjectReference), [saved_workspace_references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/services/persistence/saved_workspace_references.ts#:~:text=SavedObjectReference), [persistence.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/types/persistence.ts#:~:text=SavedObjectReference), [persistence.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/graph/public/types/persistence.ts#:~:text=SavedObjectReference) | - | @@ -1140,7 +1135,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts#:~:text=authc), [create_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts#:~:text=authc), [delete_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts#:~:text=authc), [finalize_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts#:~:text=authc), [open_close_signals_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts#:~:text=authc), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts#:~:text=authc) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/drag_and_drop/helpers.ts#:~:text=BrowserField), [columns.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx#:~:text=BrowserField), [columns.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/columns.tsx#:~:text=BrowserField), [enrichment_summary.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx#:~:text=BrowserField), [enrichment_summary.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_summary.tsx#:~:text=BrowserField), [use_data_view.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/containers/source/use_data_view.tsx#:~:text=BrowserField)+ 34 more | - | -| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields)+ 97 more | - | +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields)+ 99 more | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyRequest), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyRequest) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyResponse), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyResponse) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index feab16d183dba..98f5ed6877baa 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 2c5c0eb8959ae..a8feeaf58514f 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-05-26 +date: 2023-05-30 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 3b1620248acc3..03cec77967b07 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-05-26 +date: 2023-05-30 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 d41824312cd09..981ba784311a0 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-05-26 +date: 2023-05-30 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 45aa7aa1a349f..27653953c229f 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-05-26 +date: 2023-05-30 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 88f8b13ae0d33..1eecd75c94a4f 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-05-26 +date: 2023-05-30 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 9743a327120ce..55c33d8838bc4 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-05-26 +date: 2023-05-30 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 410387ab80eb7..cd3d0579a3607 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.devdocs.json b/api_docs/enterprise_search.devdocs.json index f32dcd8b9b046..47c6d7ad5017e 100644 --- a/api_docs/enterprise_search.devdocs.json +++ b/api_docs/enterprise_search.devdocs.json @@ -38,7 +38,7 @@ "label": "ConfigType", "description": [], "signature": [ - "{ readonly host?: string | undefined; readonly customHeaders?: Readonly<{} & {}> | undefined; readonly enabled: boolean; readonly ssl: Readonly<{ certificateAuthorities?: string | string[] | undefined; } & { verificationMode: \"none\" | \"full\" | \"certificate\"; }>; readonly accessCheckTimeout: number; readonly accessCheckTimeoutWarning: number; readonly canDeployEntSearch: boolean; readonly hasConnectors: boolean; readonly hasDefaultIngestPipeline: boolean; readonly hasNativeConnectors: boolean; readonly hasWebCrawler: boolean; }" + "{ readonly host?: string | undefined; readonly customHeaders?: Readonly<{} & {}> | undefined; readonly enabled: boolean; readonly ssl: Readonly<{ certificateAuthorities?: string | string[] | undefined; } & { verificationMode: \"none\" | \"full\" | \"certificate\"; }>; readonly accessCheckTimeout: number; readonly accessCheckTimeoutWarning: number; readonly canDeployEntSearch: boolean; readonly hasConnectors: boolean; readonly hasDefaultIngestPipeline: boolean; readonly hasDocumentLevelSecurityEnabled: boolean; readonly hasNativeConnectors: boolean; readonly hasWebCrawler: boolean; }" ], "path": "x-pack/plugins/enterprise_search/server/index.ts", "deprecated": false, @@ -193,6 +193,14 @@ "section": "def-common.Type", "text": "Type" }, + "; hasDocumentLevelSecurityEnabled: ", + { + "pluginId": "@kbn/config-schema", + "scope": "common", + "docId": "kibKbnConfigSchemaPluginApi", + "section": "def-common.Type", + "text": "Type" + }, "; hasNativeConnectors: ", { "pluginId": "@kbn/config-schema", diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 4c4f9a6619dde..61375dbd21217 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-05-26 +date: 2023-05-30 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 9207691011e10..8559866d90a1c 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/platform-deployment-management](https://github.com/orgs/elasti | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 115 | 3 | 111 | 5 | +| 115 | 3 | 111 | 3 | ## Client diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index e376f206b26f5..fa43972aa8693 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-05-26 +date: 2023-05-30 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 26ba30e4dd83f..c9f72331b620a 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-05-26 +date: 2023-05-30 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 cc0b75ad8d32e..27ad912ffc268 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-05-26 +date: 2023-05-30 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 0bd02f0bdf1e9..eb2507f3599d0 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-05-26 +date: 2023-05-30 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 46527645278e6..0269c996632c7 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-05-26 +date: 2023-05-30 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 b907a6e564d2b..44f5fe77a7080 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-05-26 +date: 2023-05-30 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 0ab16523b8fd9..062cd52a81d02 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-05-26 +date: 2023-05-30 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 fa97363d29e7f..c96dc53bae7dc 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-05-26 +date: 2023-05-30 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 d5346bbec4e31..3a330fbcf24fd 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-05-26 +date: 2023-05-30 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 204ec66757d25..d8548781c448d 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-05-26 +date: 2023-05-30 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 ba9eab9cce4ec..4f26d62fb3ef7 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-05-26 +date: 2023-05-30 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 e89e6b4e6f2c2..2b9b77f1ef873 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-05-26 +date: 2023-05-30 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 ad9e8bae45e2a..16f2db98619a6 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-05-26 +date: 2023-05-30 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 c14a1a1d3f48e..a13a15f020814 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-05-26 +date: 2023-05-30 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 ed1f1765a07ba..9a2696c8024a5 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-05-26 +date: 2023-05-30 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 a1b94ef865376..b3e1c9dcb029c 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-05-26 +date: 2023-05-30 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 959ac138ff5cf..47e18705f9a9b 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-05-26 +date: 2023-05-30 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 4f7d51216f588..c63c0d688e0b8 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-05-26 +date: 2023-05-30 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 76750a1b0e024..2272519bf9e40 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-05-26 +date: 2023-05-30 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 76cfc48c8e4ac..c5926143977f5 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-05-26 +date: 2023-05-30 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 580e02b80d579..abfaef217906f 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-05-26 +date: 2023-05-30 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 d255bde141c71..a527521976d01 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-05-26 +date: 2023-05-30 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 aab2324cc7e72..44f1b599407fb 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-05-26 +date: 2023-05-30 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 ee3076fb3e5f0..cbde4fd884198 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-05-26 +date: 2023-05-30 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 4905e52f8b5d1..d3390bd3e00cd 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-05-26 +date: 2023-05-30 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 2a8cfc4cb34c0..d0ab1e2d54826 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-05-26 +date: 2023-05-30 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 8567921d00598..bf733ba0cb5d2 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-05-26 +date: 2023-05-30 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 f04402c68f9c9..6ad7ebd3cf117 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-05-26 +date: 2023-05-30 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 7bd7480454f3e..f5a75259f1e1a 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-05-26 +date: 2023-05-30 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 d5021961f917d..3ce62b46a9bc9 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-05-26 +date: 2023-05-30 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 fc7943efe2a9d..ec56ade17ac18 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-05-26 +date: 2023-05-30 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 d5e5bce7a0b30..42eeb5d3653f2 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-05-26 +date: 2023-05-30 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 a27b7ee40da42..c176a7145932f 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-05-26 +date: 2023-05-30 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 202483466c31f..83f19216f2ba3 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-05-26 +date: 2023-05-30 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 86636620125ce..bcdb09aa084e6 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-05-26 +date: 2023-05-30 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 62c5591451b05..9556a66cc7b55 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-05-26 +date: 2023-05-30 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 b4ebd918470df..51026bd41c914 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-05-26 +date: 2023-05-30 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 656559f65cd73..3f8a054b20ff5 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-05-26 +date: 2023-05-30 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 172b5c25282b7..448516af4d995 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-05-26 +date: 2023-05-30 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 870e4be7dd17b..b6ca82a1c7b43 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-05-26 +date: 2023-05-30 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 b3d1d30e6fbcc..e1a942b4907ab 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-05-26 +date: 2023-05-30 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 6921ee14f052b..0e16e78a11b9a 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-05-26 +date: 2023-05-30 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 75562e8e2e62a..7d4d50ef85080 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-05-26 +date: 2023-05-30 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 5e736f171a94f..dc0ecbc6820d5 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-05-26 +date: 2023-05-30 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 6e1d2605bc374..6ab1ba57a2d99 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-05-26 +date: 2023-05-30 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 d06294695ebd8..49ab98b28ef72 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-05-26 +date: 2023-05-30 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 93cbcb4465404..9914323279697 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-05-26 +date: 2023-05-30 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 f3abc4812153b..2a792e54d0401 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-05-26 +date: 2023-05-30 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 e3f53c133199a..875d36fe75d58 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-05-26 +date: 2023-05-30 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 535beb8acf191..4ff1cade8f814 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-05-26 +date: 2023-05-30 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 2662b661eb530..ec8f60f00ac94 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-05-26 +date: 2023-05-30 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 0d3ed617324d9..be5946eb18c00 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-05-26 +date: 2023-05-30 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 120580199d9a7..cdb370047fe96 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-05-26 +date: 2023-05-30 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 c77c94229ee2e..dee70664616ff 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-05-26 +date: 2023-05-30 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 be002864d3e3d..7a6e739a54571 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-05-26 +date: 2023-05-30 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 cf5bf19b1a605..cb30a4c3d36ce 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-05-26 +date: 2023-05-30 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 fb686e6bf182f..3fb0a1a611d60 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-05-26 +date: 2023-05-30 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 28035a32cdaaa..7ff850e637ce6 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-05-26 +date: 2023-05-30 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 40436075b4e33..5c4cd91824f4f 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-05-26 +date: 2023-05-30 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 fb0c91cb9a30e..9b1347d0cb5c3 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-05-26 +date: 2023-05-30 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 1e432aee5d26d..a0f8dc05f85f4 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-05-26 +date: 2023-05-30 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 0a732579a4ec2..be62d6923463a 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-05-26 +date: 2023-05-30 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 9f73b1afcbbf8..e41a003ef361f 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-05-26 +date: 2023-05-30 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 2c074796e1982..70a13cbeea964 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-05-26 +date: 2023-05-30 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 4869133e0a5b6..61113383e00dc 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-05-26 +date: 2023-05-30 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_table_list.mdx b/api_docs/kbn_content_management_table_list.mdx index 8b0d4e76558ef..d4f6d36d8952b 100644 --- a/api_docs/kbn_content_management_table_list.mdx +++ b/api_docs/kbn_content_management_table_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list title: "@kbn/content-management-table-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list plugin -date: 2023-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list'] --- import kbnContentManagementTableListObj from './kbn_content_management_table_list.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 2b0286e2fedd5..60674d390e7eb 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-05-26 +date: 2023-05-30 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 83327bd195d5d..9664bc9e1f38f 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-05-26 +date: 2023-05-30 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 ab2840e66091f..8e492135ff2f7 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-05-26 +date: 2023-05-30 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 ace54062e3705..47d4920c5b088 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-05-26 +date: 2023-05-30 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 18e3480f826f1..81d12cee46320 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-05-26 +date: 2023-05-30 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 0b5cdd24a8523..777fe901454f4 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-05-26 +date: 2023-05-30 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 08d24f3bc7d17..55f87ff6d11ff 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-05-26 +date: 2023-05-30 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 faa4b4407908d..72ab86b87fee6 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-05-26 +date: 2023-05-30 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 150cc92804f32..f9bdbbac5eef6 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-05-26 +date: 2023-05-30 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 f9e5618dbda44..b6dcc40a39757 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-05-26 +date: 2023-05-30 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 2321258ca9eee..848d4c3892325 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-05-26 +date: 2023-05-30 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 d89fa4dfc1773..6e213e794711d 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-05-26 +date: 2023-05-30 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 42bfe98b78a7e..f6b27817e8660 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-05-26 +date: 2023-05-30 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 8fc12527e6443..c7ce29236726e 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-05-26 +date: 2023-05-30 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 2ff94b411a691..7e067b99f2090 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-05-26 +date: 2023-05-30 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 83f75100aacbf..41f33120bb423 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-05-26 +date: 2023-05-30 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 2b6da1c7dbd9a..bd11b8970b342 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-05-26 +date: 2023-05-30 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 d9ad401c83067..d4d17928a5f00 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-05-26 +date: 2023-05-30 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 a2a04706331b6..ae836ab1930a6 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-05-26 +date: 2023-05-30 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 99e90b584d92b..906328c031c2f 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-05-26 +date: 2023-05-30 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 935a53720ba98..b69f14ac0ff8a 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-05-26 +date: 2023-05-30 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 088ad7f504833..348a647a9eab9 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-05-26 +date: 2023-05-30 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 97d2a9d42f781..8fb7cff2fe6a8 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-05-26 +date: 2023-05-30 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 c470f434ad566..5743bf02f6099 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-05-26 +date: 2023-05-30 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 2b7b586dfbc0b..9bd6014588c4b 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-05-26 +date: 2023-05-30 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 5b37408b7a056..1fbc45c85edf4 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-05-26 +date: 2023-05-30 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 7c7078da595c0..287ae5138b9d9 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-05-26 +date: 2023-05-30 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 925e8baaacf4d..6bb6240bd0c8c 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-05-26 +date: 2023-05-30 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 a90c673aec4d6..5d59f4f5b4cc5 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-05-26 +date: 2023-05-30 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 b552154f3e5a4..8661ee35cc825 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-05-26 +date: 2023-05-30 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 611af93db42ed..60cf882192392 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-05-26 +date: 2023-05-30 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 9bd457752e076..4a3d79877eaf4 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-05-26 +date: 2023-05-30 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 b09e6c9a63ff2..fc74be2d7d5da 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-05-26 +date: 2023-05-30 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 ebadc607e9319..b4c5b0e027a63 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-05-26 +date: 2023-05-30 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 6206825872480..5df33a4d079da 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-05-26 +date: 2023-05-30 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 9a501adc52856..e05d3b28ac342 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-05-26 +date: 2023-05-30 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 d9d47283c4bb1..b2fa542c5064c 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-05-26 +date: 2023-05-30 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 54aa62a8bfbd8..b240eb0a42cec 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-05-26 +date: 2023-05-30 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 a2c49e906c76f..4dd7e37955509 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-05-26 +date: 2023-05-30 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 1b363537c4bdf..0ba86b6876435 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-05-26 +date: 2023-05-30 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 74beda2e1df19..34efcf2ed177e 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-05-26 +date: 2023-05-30 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 3dc4a94426037..8d128b0516aac 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-05-26 +date: 2023-05-30 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 cadfd6a7db3d6..3e116ea9a882c 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-05-26 +date: 2023-05-30 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 7f7f935584db3..1f12926b3dd78 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-05-26 +date: 2023-05-30 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 f3d030cba6616..2c9135b833ec1 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-05-26 +date: 2023-05-30 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 84e62ab61443d..956cd062939be 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-05-26 +date: 2023-05-30 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 0f0caea96550f..5eff7d8063d3b 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-05-26 +date: 2023-05-30 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 98cc94c96ff95..3f446b5d34972 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-05-26 +date: 2023-05-30 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 f85bdb4d5f8f1..d0200ba456aeb 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-05-26 +date: 2023-05-30 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 fdc4f313a1b60..e1e135c463d1a 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-05-26 +date: 2023-05-30 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 d7b72e71259c7..92c1a9eb97d5a 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-05-26 +date: 2023-05-30 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 216ea090eca9c..6cb6fbcdb8d54 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-05-26 +date: 2023-05-30 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 608e41e5e5d71..7a173bed8147a 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-05-26 +date: 2023-05-30 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 7aa7c6fda12ba..cf9511d36734b 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-05-26 +date: 2023-05-30 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 5a00237c45399..468735ad53da4 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-05-26 +date: 2023-05-30 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 5e144b8cc04bb..ac00359e4fc13 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-05-26 +date: 2023-05-30 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 f76fd1f4b3d0a..38391dd5c72a6 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-05-26 +date: 2023-05-30 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 b05b6808b3897..37eae801518a4 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-05-26 +date: 2023-05-30 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 39e6c79ee9df4..6a679dfee4b1c 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-05-26 +date: 2023-05-30 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 5d829a63b9c5f..4733052291a0d 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-05-26 +date: 2023-05-30 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 d9d2f2b72dee8..b67fc3baab1aa 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-05-26 +date: 2023-05-30 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 39c1ac16fbb38..3a80d44a396d5 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-05-26 +date: 2023-05-30 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 9af6d81343a39..09ab68fcf3642 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-05-26 +date: 2023-05-30 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 e4ab555a46b0a..39276c59a35e4 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-05-26 +date: 2023-05-30 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 95e9bc30b96e9..b17a1be5e306f 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-05-26 +date: 2023-05-30 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 e99b46b979d11..89fbe8186a3e3 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-05-26 +date: 2023-05-30 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 b7f8cb807db28..5f380d3775d97 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-05-26 +date: 2023-05-30 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 bd1fffabf4a65..435193cd21e38 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-05-26 +date: 2023-05-30 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 e22d8e9bbdbf1..d0fcebca9fa84 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-05-26 +date: 2023-05-30 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 6a74dc6460228..3228b3c447052 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index d50834a05cd85..97bf4b3ab6b66 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-05-26 +date: 2023-05-30 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 a1a81b3669b27..66a1e031f6985 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-05-26 +date: 2023-05-30 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 96bd541952dc3..80cc6859281d9 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-05-26 +date: 2023-05-30 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 253cdc5a2665b..3412c6ccae783 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-05-26 +date: 2023-05-30 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 21738f8f97593..a16cf2d7f741f 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-05-26 +date: 2023-05-30 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 e87ec99942212..fd20640b514ba 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-05-26 +date: 2023-05-30 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 aeab5656e7fa3..b475d7c81ee52 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-05-26 +date: 2023-05-30 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 39f58697155df..feacfb4c1effb 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-05-26 +date: 2023-05-30 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 604db517c7c6f..ff911e156c4ec 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-05-26 +date: 2023-05-30 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 e94f8721f8215..a391c67dcf5ec 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-05-26 +date: 2023-05-30 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 076e813a9a31d..d5de0306310ca 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-05-26 +date: 2023-05-30 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.devdocs.json b/api_docs/kbn_core_lifecycle_browser.devdocs.json index 30fcbe077a4c0..c646c8e5f12d2 100644 --- a/api_docs/kbn_core_lifecycle_browser.devdocs.json +++ b/api_docs/kbn_core_lifecycle_browser.devdocs.json @@ -669,10 +669,6 @@ "plugin": "dashboardEnhanced", "path": "x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/components/collect_config_container.tsx" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/plugin.ts" - }, { "plugin": "monitoring", "path": "x-pack/plugins/monitoring/public/application/pages/elasticsearch/ingest_pipeline_modal.tsx" diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index a05782b61486d..5ad9ba2b7d23f 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-05-26 +date: 2023-05-30 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 efcb96fd6bc41..d1f7f5a3f1577 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-05-26 +date: 2023-05-30 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 3cabe83f72c29..4fd63d586c842 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-05-26 +date: 2023-05-30 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 d61103c7873f8..317de7c4c098e 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-05-26 +date: 2023-05-30 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 9d280ca9932ff..95004930af6f9 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-05-26 +date: 2023-05-30 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 0508ef7cf4e95..3ada5203d5806 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-05-26 +date: 2023-05-30 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 65342b919bd37..584157e38b4c3 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-05-26 +date: 2023-05-30 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 d498b47515696..2e038326ab271 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-05-26 +date: 2023-05-30 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 7dcf26a68f617..9ab4d0a4559c7 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-05-26 +date: 2023-05-30 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 41b613e9fce56..aab71741258b0 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-05-26 +date: 2023-05-30 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 51a07d350fb33..4b589b32aa4ac 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-05-26 +date: 2023-05-30 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 f475b14089e85..c1a4a557d88d8 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-05-26 +date: 2023-05-30 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 dfb4de5684ee3..2c465892a6a28 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-05-26 +date: 2023-05-30 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 9269aed612f36..3242aab8e0690 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-05-26 +date: 2023-05-30 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 be4a72b2449ed..d353e778869b8 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-05-26 +date: 2023-05-30 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 ece070939e936..c0af4ec6e10de 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-05-26 +date: 2023-05-30 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 9cf7ef04260e4..d6f34cac7f267 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-05-26 +date: 2023-05-30 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 0fc560efaa028..60bf5cc1fa367 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-05-26 +date: 2023-05-30 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 551af7fff1dd0..5fb04d2958e5d 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-05-26 +date: 2023-05-30 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 9bc99d19a7403..58c1e9c037f45 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-05-26 +date: 2023-05-30 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 60123b2e47de1..0127ccda01eb4 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-05-26 +date: 2023-05-30 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 0e08f9378e6b9..c6cb17db9cbd9 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-05-26 +date: 2023-05-30 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 704d6d403898e..776325a777c99 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-05-26 +date: 2023-05-30 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 ab3777adacc22..692c4fe735b20 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-05-26 +date: 2023-05-30 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 cef31130e73c4..0bbaa549bfea3 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-05-26 +date: 2023-05-30 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 218d9d2814a0d..d5f869119ccf9 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-05-26 +date: 2023-05-30 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 d4f153c649e10..a885a0731106e 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-05-26 +date: 2023-05-30 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 d0fc5395619a8..3c4806cca4994 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-05-26 +date: 2023-05-30 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 b88f38ebf5dff..db5b34a4018b6 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-05-26 +date: 2023-05-30 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 3665655a3ba22..5b195a878dd10 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-05-26 +date: 2023-05-30 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 df3e621773237..e1c9581f67c80 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-05-26 +date: 2023-05-30 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 c16c732a25efc..8c92986ffff31 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-05-26 +date: 2023-05-30 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 e118d54cb7522..397a422f00d98 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-05-26 +date: 2023-05-30 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 46101e1927807..3ba81cb9f92d5 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-05-26 +date: 2023-05-30 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.devdocs.json b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json index 4ccb23a8855a5..4e5225b4c6380 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json @@ -1126,66 +1126,6 @@ "plugin": "canvas", "path": "x-pack/plugins/canvas/public/services/platform.ts" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/services/save_modal.tsx" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/services/save_modal.tsx" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/state_management/store.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/state_management/store.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/use_workspace_loader.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/use_workspace_loader.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/application.tsx" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/application.tsx" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/state_management/mocks.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/state_management/mocks.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts" @@ -1322,14 +1262,6 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_actions/clone_panel_action.tsx" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts" - }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/saved_object.test.ts" @@ -1650,10 +1582,6 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_listing/dashboard_listing.tsx" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, { "plugin": "@kbn/core-saved-objects-browser-internal", "path": "packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts" @@ -1939,14 +1867,6 @@ "plugin": "dashboardEnhanced", "path": "x-pack/plugins/dashboard_enhanced/public/services/drilldowns/abstract_dashboard_drilldown/components/collect_config_container.tsx" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts" - }, { "plugin": "ml", "path": "x-pack/plugins/ml/public/application/services/dashboard_service.test.ts" @@ -2328,10 +2248,6 @@ "plugin": "dashboard", "path": "src/plugins/dashboard/public/services/dashboard_saved_object/lib/load_dashboard_state_from_saved_object.ts" }, - { - "plugin": "graph", - "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" - }, { "plugin": "savedSearch", "path": "src/plugins/saved_search/public/services/saved_searches/get_saved_searches.test.ts" @@ -2847,6 +2763,14 @@ "plugin": "visualizations", "path": "src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts" }, + { + "plugin": "graph", + "path": "x-pack/plugins/graph/public/helpers/saved_objects_utils/save_with_confirmation.ts" + }, + { + "plugin": "graph", + "path": "x-pack/plugins/graph/public/helpers/saved_objects_utils/save_with_confirmation.ts" + }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/save_with_confirmation.test.ts" @@ -3523,6 +3447,14 @@ "plugin": "synthetics", "path": "x-pack/plugins/synthetics/common/types/synthetics_monitor.ts" }, + { + "plugin": "graph", + "path": "x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.test.ts" + }, + { + "plugin": "graph", + "path": "x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.test.ts" + }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts" diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index b44921f435a5d..529341bcd3b09 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-05-26 +date: 2023-05-30 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 1bfca4afb09e6..bbca67a0d84c1 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-05-26 +date: 2023-05-30 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 e13cb823fd4f3..8f0db43297cf5 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-05-26 +date: 2023-05-30 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 52d90ed6ac7da..1376f78c143e3 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-05-26 +date: 2023-05-30 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 2da2fb68c93b0..d0fbad201e3f7 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-05-26 +date: 2023-05-30 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 8c5e3237ef893..31ad3ac9e207c 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-05-26 +date: 2023-05-30 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 a005e09e690e7..71d9e8ff15fbe 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-05-26 +date: 2023-05-30 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 96ab7149865f7..833e5aa8a85d9 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-05-26 +date: 2023-05-30 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 00e321b0abe9d..978d632b0a2c5 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-05-26 +date: 2023-05-30 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 ece1b5b9e4523..5add916820eb8 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-05-26 +date: 2023-05-30 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 5c0f40f5f48e7..2692c95542260 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-05-26 +date: 2023-05-30 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 edce205cc541c..602855a96ea03 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-05-26 +date: 2023-05-30 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 1fc18f1738f88..95130a07842df 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-05-26 +date: 2023-05-30 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 2b8b6c6a015ed..73733bff6f097 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-05-26 +date: 2023-05-30 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 22d6560cba893..180c2c06d8c1f 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-05-26 +date: 2023-05-30 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 9d591c1d725ff..c29bbe6c2a429 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-05-26 +date: 2023-05-30 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 5efd3ba1b666c..7afaf5ae77842 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-05-26 +date: 2023-05-30 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 434d4ad08f3cc..0240d90217db4 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-05-26 +date: 2023-05-30 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 e0ec0ac62d02e..d8f80374e3bfa 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-05-26 +date: 2023-05-30 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 911ba36f65241..6f1158ce0721a 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-05-26 +date: 2023-05-30 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 7fc826bdec5a8..a240ab7a11f13 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-05-26 +date: 2023-05-30 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 eaf55852f712c..02b67ba23ab70 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-05-26 +date: 2023-05-30 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 a8f0aaec42ea2..7e0eec398dd1a 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-05-26 +date: 2023-05-30 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 f12c169ee1ff6..61fa00d19ddf9 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-05-26 +date: 2023-05-30 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 5eb3379df8242..2ce77a9b63242 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-05-26 +date: 2023-05-30 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 5d87a60fecf18..7be0d1de16c18 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-05-26 +date: 2023-05-30 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 031e76c1a63a3..f5734bd6d84a9 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-05-26 +date: 2023-05-30 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 3a1047d20a4b4..aa1a8d968e7bc 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-05-26 +date: 2023-05-30 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 71a3767182c89..4094d89c65955 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-05-26 +date: 2023-05-30 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 9995d451339b7..a0e37194d07e1 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-05-26 +date: 2023-05-30 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 67bda80c475b6..accfb0469e313 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-05-26 +date: 2023-05-30 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 0ec9bca1d058a..4c0ecb03bfa40 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-05-26 +date: 2023-05-30 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 b23c954c7098e..fdf03974150d0 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-05-26 +date: 2023-05-30 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 65427dde9f7dd..b631350889441 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-05-26 +date: 2023-05-30 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 833d3e5610ac2..8a40cd8477b3e 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-05-26 +date: 2023-05-30 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 9a5a243bd03ab..62103713d7854 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-05-26 +date: 2023-05-30 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 dbf74d14b67cc..e8e3b119068f3 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-05-26 +date: 2023-05-30 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 d2ab800eca5b3..83b69b032b01b 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-05-26 +date: 2023-05-30 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 493d840edf07a..8261e9e71dfb1 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-05-26 +date: 2023-05-30 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 e8ba67e258ebf..1922ea8818071 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-05-26 +date: 2023-05-30 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 05960123d3dd1..5045da36b4ed5 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-05-26 +date: 2023-05-30 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 1df045a7d7f1f..0f2de0b032283 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-05-26 +date: 2023-05-30 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 f6e2b4e93ec19..a54d5be3ab96b 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-05-26 +date: 2023-05-30 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 62677abc79018..e23cbf72dd1df 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-05-26 +date: 2023-05-30 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 7247a741f0066..992f102f9a00c 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-05-26 +date: 2023-05-30 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 be0738b0fd5f8..189342a2b89a8 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-05-26 +date: 2023-05-30 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 99da00dcbe093..45fd63db82fbd 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 838c3fa8e6725..45624d93b6777 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-05-26 +date: 2023-05-30 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 f1cb9e9e5c8fe..b433a820fb3cc 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-05-26 +date: 2023-05-30 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 3fba7bdc90d74..138f221388794 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-05-26 +date: 2023-05-30 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 7836967c226ab..50c29946987c3 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-05-26 +date: 2023-05-30 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 94b65db948430..85819e415890c 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-05-26 +date: 2023-05-30 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 c1a25981bc8c1..e45353b55f429 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-05-26 +date: 2023-05-30 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 0f19c9d13e81b..f201323607209 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-05-26 +date: 2023-05-30 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 325bb5e2a2d78..b0f78edb1947b 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-05-26 +date: 2023-05-30 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 fb85e7b309134..9de649ef8819f 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-05-26 +date: 2023-05-30 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 3b6931508ee7b..3bd520bcba82a 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-05-26 +date: 2023-05-30 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_es.mdx b/api_docs/kbn_es.mdx index be12e05869caf..661fbe771ad1a 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-05-26 +date: 2023-05-30 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 02aa9ca1bd576..c441762bdb7a8 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-05-26 +date: 2023-05-30 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 157502c0be944..e46857b9d0d9b 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-05-26 +date: 2023-05-30 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 86128d9d23286..e9e33d08a204a 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-05-26 +date: 2023-05-30 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 4c2531a6a1d33..9899f0ac376c0 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-05-26 +date: 2023-05-30 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 902d9210ece7d..d5c18a80b2c4b 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-05-26 +date: 2023-05-30 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 7c5c1dfcee50b..4974f9da23211 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-05-26 +date: 2023-05-30 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 c59cd3dd8524e..05f3b75178e27 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-05-26 +date: 2023-05-30 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 25f243e13a912..263efba493d4f 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-05-26 +date: 2023-05-30 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 29af7497fee09..bc5f0abf89882 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-05-26 +date: 2023-05-30 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 3c7f1300dad69..861970d49c6f1 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-05-26 +date: 2023-05-30 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 fc82e1c7b89cd..46fe0623be83b 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-05-26 +date: 2023-05-30 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 a3cfc535bf41e..7afafd146eae9 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-05-26 +date: 2023-05-30 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 f0189c9eb9212..4b1bb6b87ce95 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-05-26 +date: 2023-05-30 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 d1af8aa94ec2e..e851e4c6a49bc 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-05-26 +date: 2023-05-30 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 43b8d0a56480b..21b7a84cde002 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-05-26 +date: 2023-05-30 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 8130b18bc163b..bbac66171cad1 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-05-26 +date: 2023-05-30 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 e0e8dc3506dd7..53c126d75fda2 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-05-26 +date: 2023-05-30 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 10be0c2d0e738..9c98aaeb77b73 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-05-26 +date: 2023-05-30 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 e4bda34c3fdfd..c373f893aa435 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-05-26 +date: 2023-05-30 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 66f874140310d..33a1feb130b7a 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-05-26 +date: 2023-05-30 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 2a25bab24ef90..0c42830b24133 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-05-26 +date: 2023-05-30 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 fed9c50a64575..cd06cd2d9a6fa 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-05-26 +date: 2023-05-30 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 78c8b649afbe5..39fd0da37a355 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-05-26 +date: 2023-05-30 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 60e637d0e5e25..131d121725ed2 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-05-26 +date: 2023-05-30 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 adb35bd0f9304..52730d101a4f7 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-05-26 +date: 2023-05-30 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 873b5308ea038..b31a0c8af7954 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-05-26 +date: 2023-05-30 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 1562ecfef569c..8147e6339248c 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-05-26 +date: 2023-05-30 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 c8d162b9e185b..048e4fe0e2ef2 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-05-26 +date: 2023-05-30 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 e7de00d94df7f..01c10065901f7 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-05-26 +date: 2023-05-30 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 30560f8ce00c7..f866b6afe0fd1 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-05-26 +date: 2023-05-30 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 783278dad1777..8dfabe1b9b779 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-05-26 +date: 2023-05-30 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 754af0131e03c..5bfec8b03c6c2 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-05-26 +date: 2023-05-30 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 5210074679eca..0bf1247dad029 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-05-26 +date: 2023-05-30 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 96d78712ab7d2..e49f0e85f21e9 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-05-26 +date: 2023-05-30 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 b08e4aeca8ee6..47175192795c4 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-05-26 +date: 2023-05-30 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 e92c04f5e1ac9..9881e274b5e2a 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-05-26 +date: 2023-05-30 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_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 2eb79932fa94d..f73d9d61fa23c 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-05-26 +date: 2023-05-30 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_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index 599333d5f2d92..463e2233b16e3 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-05-26 +date: 2023-05-30 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 3fc6af35a7278..ce0128ab6e99b 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-05-26 +date: 2023-05-30 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 2c47d32d61608..7cd882cc0fcd2 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-05-26 +date: 2023-05-30 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 4b06998234557..decf67769c74a 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-05-26 +date: 2023-05-30 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 733b0605c54c1..59c810993412a 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-05-26 +date: 2023-05-30 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 e954fad62a1bc..7a2e0c6c8e2fd 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-05-26 +date: 2023-05-30 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 fb5eef926c378..e41eafe62898a 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-05-26 +date: 2023-05-30 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 67abc8de39fac..390d07f8f7272 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-05-26 +date: 2023-05-30 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 23b4fd76a33e3..3b96dda01a69c 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-05-26 +date: 2023-05-30 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 53ddcfda354b4..a7087eec75315 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-05-26 +date: 2023-05-30 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_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 49ceddc374ea8..959588bda88d5 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-05-26 +date: 2023-05-30 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 e8799e1589483..622a862fc1be7 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-05-26 +date: 2023-05-30 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 299203afc7966..2325748d101e4 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-05-26 +date: 2023-05-30 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 cc45e6ddc4107..810be013da1b3 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-05-26 +date: 2023-05-30 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 8829c3d3076ae..fa93bbf1409fc 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-05-26 +date: 2023-05-30 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 2f20e154a2d9c..778d09e809c6d 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-05-26 +date: 2023-05-30 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 5f9f7a5b33666..0b3d96fa5c279 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-05-26 +date: 2023-05-30 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 7c0abd6f8d327..c11afaafd7b14 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-05-26 +date: 2023-05-30 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 08a97d09332e1..51484ca3c7d2d 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-05-26 +date: 2023-05-30 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 d0c7aae56126f..d3cd20133a96c 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-05-26 +date: 2023-05-30 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 7bf45375d99ae..a4e4b36e70e0b 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-05-26 +date: 2023-05-30 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 eb9da249cd7c1..bb13253e7a38d 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-05-26 +date: 2023-05-30 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 45fedc2a4ce47..4f52d965b6285 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-05-26 +date: 2023-05-30 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 14578fd329013..adf5ab5dc994c 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-05-26 +date: 2023-05-30 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 f19853b5d0035..3463e9fda6078 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-05-26 +date: 2023-05-30 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 512eeaff8e9d8..0b3640427ca5d 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-05-26 +date: 2023-05-30 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 8986c9c89fbf0..126cca6410032 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-05-26 +date: 2023-05-30 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 c85db157bf54a..2c898b3e4ca84 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-05-26 +date: 2023-05-30 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 9cc9ced1b37cb..596c16a6ccb06 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-05-26 +date: 2023-05-30 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 10091fb9dc8fc..7908b219cd159 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-05-26 +date: 2023-05-30 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 4d72efb5aefd1..f7f6c33cc66d2 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-05-26 +date: 2023-05-30 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 9fc714430443d..2a639891f56c7 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-05-26 +date: 2023-05-30 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 cb26016972044..2e7d633e82c6b 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-05-26 +date: 2023-05-30 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 037d6d891797d..fb4918880513b 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-05-26 +date: 2023-05-30 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 e84b473bc8e4f..069a23b84f35d 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-05-26 +date: 2023-05-30 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 9835596511b9d..1967c9106740d 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-05-26 +date: 2023-05-30 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 18b965f15fd8a..d83a8c3f86c8c 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-05-26 +date: 2023-05-30 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 c9936b55f89f8..8b79fb2e0e261 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-05-26 +date: 2023-05-30 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 d1bbff6c80f32..c9ef5a34808a9 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-05-26 +date: 2023-05-30 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 bf62549f89a19..7fd1cc657c4d3 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-05-26 +date: 2023-05-30 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 803c859798f04..45cb56eecb883 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-05-26 +date: 2023-05-30 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 b26b46bd44318..34890c6756b15 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-05-26 +date: 2023-05-30 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 8234b0a72e5f9..d1c3c9b435573 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-05-26 +date: 2023-05-30 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 60b42ab768a99..195ff8c8e0b5a 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-05-26 +date: 2023-05-30 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 0257c12053419..e633874b65550 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-05-26 +date: 2023-05-30 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 9f5d49f633c06..0e297220b1e46 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-05-26 +date: 2023-05-30 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 442b40f96c867..ab14c2a49485a 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-05-26 +date: 2023-05-30 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 d897b6422a84e..e99721fc0cd75 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-05-26 +date: 2023-05-30 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 4bf980ae54505..306ae0e686367 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-05-26 +date: 2023-05-30 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 7b3271f411ef0..54b7f62afb4fb 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-05-26 +date: 2023-05-30 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 9590af45e8ba5..3c91c241bc685 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-05-26 +date: 2023-05-30 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 3843018736874..496fea0f9bae2 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-05-26 +date: 2023-05-30 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 f446f8a55c5be..42f934cf28cb1 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-05-26 +date: 2023-05-30 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 24a0f22e55324..830e534ea98e8 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-05-26 +date: 2023-05-30 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 09dd61fd84fdf..5508c4eb64cf3 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-05-26 +date: 2023-05-30 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 7e60dbfcb9342..cd272d27312eb 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-05-26 +date: 2023-05-30 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 4d89fc9f2e546..2c73ee4f30ec9 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-05-26 +date: 2023-05-30 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 af55d9f0a2e5f..9c3eef2bebc8c 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-05-26 +date: 2023-05-30 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 e967fe48cd8f6..30f16325a2ba4 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-05-26 +date: 2023-05-30 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 3a8e5c45bf798..6f343628b1c54 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-05-26 +date: 2023-05-30 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 812533f950be0..94c253309d8d2 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-05-26 +date: 2023-05-30 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 9e6e29be98923..9f58747411826 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-05-26 +date: 2023-05-30 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 495d462bb7d6e..f8de1703f5b1f 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-05-26 +date: 2023-05-30 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 c6723b540165a..d2fa0cafa1e3f 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-05-26 +date: 2023-05-30 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 2facc7db6e26a..013ac6a644507 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-05-26 +date: 2023-05-30 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 31801ca484d0f..459eefbf8a212 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-05-26 +date: 2023-05-30 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 2269e13a3880b..49e3f66039f66 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-05-26 +date: 2023-05-30 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 77be6ecc4a7b6..e8791c5adbbbd 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-05-26 +date: 2023-05-30 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 f8def2d76d7ee..322dccead1787 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-05-26 +date: 2023-05-30 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 16e6f860733ce..f347b9457ffb7 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-05-26 +date: 2023-05-30 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 335babaeff34d..df634c2e89fc6 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-05-26 +date: 2023-05-30 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 5f0eba3298962..78cfd80df75d1 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-05-26 +date: 2023-05-30 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 58b52f47e55bf..5fc633ecfade7 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-05-26 +date: 2023-05-30 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 f113a2f767969..4bf45112700cc 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-05-26 +date: 2023-05-30 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 865f5b8bf2561..cdc67e80895dd 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-05-26 +date: 2023-05-30 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 5e36ab2d735c8..81a5264919de2 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-05-26 +date: 2023-05-30 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 1f7e01c437a76..d48054d21a494 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-05-26 +date: 2023-05-30 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 2c3f7d4a5b8ea..4d76c4670cbfb 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-05-26 +date: 2023-05-30 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 af4caa73555d6..185cf0c9b512f 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-05-26 +date: 2023-05-30 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 ff8ddfbe82f00..783c3ae7063ce 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-05-26 +date: 2023-05-30 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 429f46496cc88..fdd6471a9dce1 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-05-26 +date: 2023-05-30 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 938593f55ca11..5fdd2df8a9d8b 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-05-26 +date: 2023-05-30 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 68f4799fb49a7..5e06c5c63d44c 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-05-26 +date: 2023-05-30 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 94f39007099f1..e2ff2ff7df258 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-05-26 +date: 2023-05-30 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 9d2adff3651fe..0ffc56381f762 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-05-26 +date: 2023-05-30 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 b1c29f359b41b..f022fcccfdc12 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-05-26 +date: 2023-05-30 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 f82a0137d5952..eaec0f8bad1f8 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-05-26 +date: 2023-05-30 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 a318586ab08f2..dc12ce7818f1f 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-05-26 +date: 2023-05-30 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 b8e4e65d29088..3ce801fa64920 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-05-26 +date: 2023-05-30 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 c61d7ffd29f16..d52e52d16094d 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-05-26 +date: 2023-05-30 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 31e85d648a546..727526468dfa6 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-05-26 +date: 2023-05-30 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 d4e2137c5f621..123a595f6f9cd 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-05-26 +date: 2023-05-30 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 b3f7cbe1c8d90..82454c82ded94 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-05-26 +date: 2023-05-30 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 1f166c90bf089..af232892d829b 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-05-26 +date: 2023-05-30 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 a569ea1111d20..e0f012c930673 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-05-26 +date: 2023-05-30 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 7273dd4044d0a..e9ee5620dc45a 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-05-26 +date: 2023-05-30 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.devdocs.json b/api_docs/kbn_slo_schema.devdocs.json index dc76894b66b50..fa95305013f5d 100644 --- a/api_docs/kbn_slo_schema.devdocs.json +++ b/api_docs/kbn_slo_schema.devdocs.json @@ -227,6 +227,52 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/slo-schema", + "id": "def-common.Duration.isEqual", + "type": "Function", + "tags": [], + "label": "isEqual", + "description": [], + "signature": [ + "(other: ", + { + "pluginId": "@kbn/slo-schema", + "scope": "common", + "docId": "kibKbnSloSchemaPluginApi", + "section": "def-common.Duration", + "text": "Duration" + }, + ") => boolean" + ], + "path": "packages/kbn-slo-schema/src/models/duration.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/slo-schema", + "id": "def-common.Duration.isEqual.$1", + "type": "Object", + "tags": [], + "label": "other", + "description": [], + "signature": [ + { + "pluginId": "@kbn/slo-schema", + "scope": "common", + "docId": "kibKbnSloSchemaPluginApi", + "section": "def-common.Duration", + "text": "Duration" + } + ], + "path": "packages/kbn-slo-schema/src/models/duration.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/slo-schema", "id": "def-common.Duration.format", diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 6b1917ed5c80b..2148bca6d776e 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/actionable-observability](https://github.com/orgs/elastic/team | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 103 | 0 | 103 | 0 | +| 105 | 0 | 105 | 0 | ## Common diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 112f29549ea38..c781fdb9326e5 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-05-26 +date: 2023-05-30 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 ba4e4576ad541..85f73e505b92b 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-05-26 +date: 2023-05-30 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 2db366045e062..40564ede58ff1 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-05-26 +date: 2023-05-30 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 de12e79cd0fdf..0c5972791d6eb 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-05-26 +date: 2023-05-30 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 db0a3d961c368..3f4e339afd2b2 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-05-26 +date: 2023-05-30 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 437a6e2712f74..a45714dee7e86 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-05-26 +date: 2023-05-30 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 fd6317d6600df..bcf49d5ae2dd7 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-05-26 +date: 2023-05-30 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 29e84be8e5846..b929ac28b916f 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-05-26 +date: 2023-05-30 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 3a82460214645..ef55a2417f75e 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-05-26 +date: 2023-05-30 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 064116bdc71d5..30cbbc89a34f2 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-05-26 +date: 2023-05-30 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 d89b505063c3f..be14020cde647 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-05-26 +date: 2023-05-30 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 482d4ad93aa97..afb39884d398a 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-05-26 +date: 2023-05-30 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 6a9a9c5198cc0..3e4355fcaa062 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-05-26 +date: 2023-05-30 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 515f16e1e0a87..b74f5fbf15bce 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-05-26 +date: 2023-05-30 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 e47cfc775fead..c4b68d83854c7 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-05-26 +date: 2023-05-30 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 edd78bd72421d..6bf7970da834a 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-05-26 +date: 2023-05-30 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 1a5522e7aa76a..927d8ebcaa1cf 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-05-26 +date: 2023-05-30 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 faaaf97145660..8767382e06854 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-05-26 +date: 2023-05-30 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 0f4b7ba5d27d5..9c7b6f120adbc 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-05-26 +date: 2023-05-30 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 6885a036fc873..be070430ba431 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-05-26 +date: 2023-05-30 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 80849d940553c..ed135aa8694a3 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-05-26 +date: 2023-05-30 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 e2a7e1d56afb0..c865a4a385d2f 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-05-26 +date: 2023-05-30 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 97f8eaf0b7231..64e785f344242 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-05-26 +date: 2023-05-30 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 b2d2dda2dbb22..4cda4d9b6926d 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-05-26 +date: 2023-05-30 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 75fd81803cdcd..fc4a49081a19f 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-05-26 +date: 2023-05-30 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 eae76551f3f0d..2db06ec7438a6 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-05-26 +date: 2023-05-30 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 3916df0d08aa9..e9ffdebf1867e 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-05-26 +date: 2023-05-30 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 d219e4cdff2b2..e7e60089367af 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-05-26 +date: 2023-05-30 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 adb1cdded3e4d..367842fcf61ae 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-05-26 +date: 2023-05-30 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 24732609cd298..312cbbc74ad18 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-05-26 +date: 2023-05-30 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 4c52e94b9b558..5956e17c5215e 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-05-26 +date: 2023-05-30 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 444726189f0f1..b4abe59386443 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-05-26 +date: 2023-05-30 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 e38647b62b94d..52af07aa2175d 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-05-26 +date: 2023-05-30 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 76306df4a2381..9810889d8a48f 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-05-26 +date: 2023-05-30 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 f4b87dd3b46c9..c60e3ecf60c9e 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-05-26 +date: 2023-05-30 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 8f999983b75c1..7356213ba2d6d 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-05-26 +date: 2023-05-30 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 3bb81902ac6de..965a4a74e765c 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-05-26 +date: 2023-05-30 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 0dfeb1f4e26e7..0e2ac541524dd 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-05-26 +date: 2023-05-30 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 ebfd017e5342e..35f2f3dfb1f9d 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index d0052f5961b3e..a6b4a9e5d6ab6 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -3468,6 +3468,21 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "observability", + "id": "def-public.alertsLocatorID", + "type": "string", + "tags": [], + "label": "alertsLocatorID", + "description": [], + "signature": [ + "\"ALERTS_LOCATOR\"" + ], + "path": "x-pack/plugins/observability/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-public.apmServiceGroupMaxNumberOfServices", @@ -3790,6 +3805,51 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "observability", + "id": "def-public.ruleDetailsLocatorID", + "type": "string", + "tags": [], + "label": "ruleDetailsLocatorID", + "description": [], + "signature": [ + "\"RULE_DETAILS_LOCATOR\"" + ], + "path": "x-pack/plugins/observability/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observability", + "id": "def-public.rulesLocatorID", + "type": "string", + "tags": [], + "label": "rulesLocatorID", + "description": [], + "signature": [ + "\"RULES_LOCATOR\"" + ], + "path": "x-pack/plugins/observability/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "observability", + "id": "def-public.sloDetailsLocatorID", + "type": "string", + "tags": [], + "label": "sloDetailsLocatorID", + "description": [], + "signature": [ + "\"SLO_DETAILS_LOCATOR\"" + ], + "path": "x-pack/plugins/observability/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-public.StringOrNull", @@ -7521,7 +7581,7 @@ "section": "def-common.Duration", "text": "Duration" }, - "; isRolling: boolean; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; }; compositeMethod: \"weightedAverage\"; sources: { id: string; revision: number; weight: number; }[]; } & { id?: string | undefined; tags?: string[] | undefined; }; }; }) => Promise; } & ", + "; isRolling: boolean; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; }; compositeMethod: \"weightedAverage\"; sources: { id: string; revision: number; weight: number; }[]; } & { id?: string | undefined; tags?: string[] | undefined; }; }; }) => Promise<{ id: string; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -8589,7 +8649,7 @@ "section": "def-common.Duration", "text": "Duration" }, - "; isRolling: boolean; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; }; compositeMethod: \"weightedAverage\"; sources: { id: string; revision: number; weight: number; }[]; } & { id?: string | undefined; tags?: string[] | undefined; }; }; }) => Promise; } & ", + "; isRolling: boolean; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; }; compositeMethod: \"weightedAverage\"; sources: { id: string; revision: number; weight: number; }[]; } & { id?: string | undefined; tags?: string[] | undefined; }; }; }) => Promise<{ id: string; }>; } & ", { "pluginId": "observability", "scope": "server", @@ -11551,7 +11611,23 @@ "GetResponse", ">; delete: (deleteParams: { id: string; }) => Promise<", "WriteResponseBase", - ">; } | undefined>; }" + ">; } | undefined>; alertsLocator: ", + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + { + "pluginId": "observability", + "scope": "common", + "docId": "kibObservabilityPluginApi", + "section": "def-common.AlertsLocatorParams", + "text": "AlertsLocatorParams" + }, + ">; }" ], "path": "x-pack/plugins/observability/server/plugin.ts", "deprecated": false, @@ -11939,7 +12015,118 @@ "initialIsOpen": false } ], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "observability", + "id": "def-common.AlertsLocatorParams", + "type": "Interface", + "tags": [], + "label": "AlertsLocatorParams", + "description": [], + "signature": [ + { + "pluginId": "observability", + "scope": "common", + "docId": "kibObservabilityPluginApi", + "section": "def-common.AlertsLocatorParams", + "text": "AlertsLocatorParams" + }, + " extends ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.SerializableRecord", + "text": "SerializableRecord" + } + ], + "path": "x-pack/plugins/observability/common/locators/alerts.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "observability", + "id": "def-common.AlertsLocatorParams.baseUrl", + "type": "string", + "tags": [], + "label": "baseUrl", + "description": [], + "path": "x-pack/plugins/observability/common/locators/alerts.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-common.AlertsLocatorParams.spaceId", + "type": "string", + "tags": [], + "label": "spaceId", + "description": [], + "path": "x-pack/plugins/observability/common/locators/alerts.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-common.AlertsLocatorParams.rangeFrom", + "type": "string", + "tags": [], + "label": "rangeFrom", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/observability/common/locators/alerts.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-common.AlertsLocatorParams.rangeTo", + "type": "string", + "tags": [], + "label": "rangeTo", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/observability/common/locators/alerts.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-common.AlertsLocatorParams.kuery", + "type": "string", + "tags": [], + "label": "kuery", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/observability/common/locators/alerts.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-common.AlertsLocatorParams.status", + "type": "CompoundType", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "AlertStatus", + " | undefined" + ], + "path": "x-pack/plugins/observability/common/locators/alerts.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "enums": [ { "parentPluginId": "observability", @@ -11967,6 +12154,21 @@ } ], "misc": [ + { + "parentPluginId": "observability", + "id": "def-common.alertsLocatorID", + "type": "string", + "tags": [], + "label": "alertsLocatorID", + "description": [], + "signature": [ + "\"ALERTS_LOCATOR\"" + ], + "path": "x-pack/plugins/observability/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "observability", "id": "def-common.apmAWSLambdaPriceFactor", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 61942b421e1c9..06e8210933664 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/actionable-observability](https://github.com/orgs/elastic/team | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 472 | 43 | 466 | 14 | +| 484 | 43 | 478 | 15 | ## Client @@ -65,6 +65,9 @@ Contact [@elastic/actionable-observability](https://github.com/orgs/elastic/team ### Functions +### Interfaces + + ### Enums diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 600e99fae94f9..747a51e8011f9 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-05-26 +date: 2023-05-30 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 d4b4509eaffbf..810d5fd391bbf 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-05-26 +date: 2023-05-30 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 561396237c54c..d822b0f9dee70 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-05-26 +date: 2023-05-30 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 50afe53d346c3..a2589668838d3 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -21,7 +21,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 69758 | 522 | 60059 | 1348 | +| 69768 | 522 | 60072 | 1348 | ## Plugin Directory @@ -69,7 +69,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Extends embeddable plugin with more functionality | 14 | 0 | 14 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 51 | 0 | 44 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Adds dashboards for discovering and managing Enterprise Search products. | 9 | 0 | 9 | 0 | -| | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 115 | 3 | 111 | 5 | +| | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 115 | 3 | 111 | 3 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | The Event Annotation service contains expressions for event annotations | 172 | 30 | 172 | 3 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 116 | 0 | 116 | 11 | | | [@elastic/uptime](https://github.com/orgs/elastic/teams/uptime) | - | 141 | 1 | 141 | 14 | @@ -129,7 +129,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 34 | 0 | 34 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | -| | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 472 | 43 | 466 | 14 | +| | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 484 | 43 | 478 | 15 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 7 | 0 | 7 | 0 | | | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 266 | 1 | 265 | 11 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 24 | 0 | 24 | 7 | @@ -151,7 +151,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-reporting-services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 27 | 0 | 8 | 5 | | searchprofiler | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 283 | 0 | 94 | 1 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 123 | 0 | 82 | 27 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 125 | 0 | 84 | 28 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | The core Serverless plugin, providing APIs to Serverless Project plugins. | 11 | 0 | 10 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Serverless customizations for observability. | 6 | 0 | 6 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Serverless customizations for search. | 6 | 0 | 6 | 0 | @@ -173,7 +173,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 257 | 1 | 214 | 20 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [@elastic/kibana-localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 550 | 11 | 521 | 49 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 544 | 11 | 518 | 49 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 144 | 2 | 102 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 206 | 0 | 140 | 9 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list which can be integrated into apps | 293 | 0 | 267 | 8 | @@ -545,7 +545,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 15 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 3 | 0 | -| | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 103 | 0 | 103 | 0 | +| | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 105 | 0 | 105 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 20 | 0 | 12 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 100 | 2 | 64 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 4 | 0 | 2 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index daf0185de7721..70bc5bea7fc48 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-05-26 +date: 2023-05-30 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 7ac58b510e479..0b4afe468e2cc 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-05-26 +date: 2023-05-30 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 1e100f177162c..dd8bb08e77a6c 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-05-26 +date: 2023-05-30 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 6134134a81439..05327c2170acd 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 6a99d88772e32..234acb6026e68 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-05-26 +date: 2023-05-30 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 cdbe72e059236..b7b55ca56904c 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-05-26 +date: 2023-05-30 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 2883f25d0b9e0..aa0869a6ba430 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-05-26 +date: 2023-05-30 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 c3678df87d22e..918f5e08d9d66 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-05-26 +date: 2023-05-30 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 672290258f6c1..e27f487770e28 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-05-26 +date: 2023-05-30 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 c6608cfb8f4b2..828977d222e7f 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-05-26 +date: 2023-05-30 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 78c1c006ab6ed..6806cf94ccbc8 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-05-26 +date: 2023-05-30 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 362d715965595..ec53128b11a01 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-05-26 +date: 2023-05-30 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 3874a0aabfe2b..caf67891563f9 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-05-26 +date: 2023-05-30 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 a0758fbc63b68..d074a19dd0857 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-05-26 +date: 2023-05-30 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 f93a226be35b4..0ceda14a57677 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-05-26 +date: 2023-05-30 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 0cfc74be93037..65c3edcf3fc96 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index fa8d4af1d5af1..580d691d6faf3 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -1411,6 +1411,40 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.PluginStart.setGetStartedPage", + "type": "Function", + "tags": [], + "label": "setGetStartedPage", + "description": [], + "signature": [ + "(getStartedComponent: ", + "GetStartedComponent", + ") => void" + ], + "path": "x-pack/plugins/security_solution/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "securitySolution", + "id": "def-public.PluginStart.setGetStartedPage.$1", + "type": "Function", + "tags": [], + "label": "getStartedComponent", + "description": [], + "signature": [ + "GetStartedComponent" + ], + "path": "x-pack/plugins/security_solution/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "lifecycle": "start", diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index a18dd9488372c..7a11a26dd8507 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 123 | 0 | 82 | 27 | +| 125 | 0 | 84 | 28 | ## Client diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 172083c905d0a..fd4cb94b18006 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-05-26 +date: 2023-05-30 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 b6a37825ae60a..d249bda728857 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-05-26 +date: 2023-05-30 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 f7065eed056e7..f2da7c483f6b6 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-05-26 +date: 2023-05-30 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 de5edbf128f66..d6c94fb0b4359 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-05-26 +date: 2023-05-30 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 aa0ea01b4718a..88ec0654391f8 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-05-26 +date: 2023-05-30 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 b2986a6656985..59748269720b1 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-05-26 +date: 2023-05-30 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 11794635a5d9d..b576fc5382ca1 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-05-26 +date: 2023-05-30 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 43497e18f19d0..b30e7a4407245 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-05-26 +date: 2023-05-30 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 ee553580342ba..f629c503007c3 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-05-26 +date: 2023-05-30 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 74c8fc454417e..928e951fbba5d 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-05-26 +date: 2023-05-30 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 fe27b3f8efc11..ba274579c9838 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-05-26 +date: 2023-05-30 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 8231bc5c26d41..d1af1fc778144 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-05-26 +date: 2023-05-30 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 8aadca40aaeed..4d573258e090e 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-05-26 +date: 2023-05-30 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 93a5878b6e961..f91437e970aa3 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-05-26 +date: 2023-05-30 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 04ba9cdd5dcd1..4eb493d7db601 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-05-26 +date: 2023-05-30 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 b443aaac5af93..2e7f89c50b2ee 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-05-26 +date: 2023-05-30 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 649936cef67d0..100df62204f92 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.devdocs.json b/api_docs/timelines.devdocs.json index 9726c2e691410..03f2681b5c646 100644 --- a/api_docs/timelines.devdocs.json +++ b/api_docs/timelines.devdocs.json @@ -4691,6 +4691,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/flyout/right/context.tsx" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.tsx" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.tsx" + }, { "plugin": "@kbn/securitysolution-data-table", "path": "x-pack/packages/security-solution/data_table/mock/mock_source.ts" diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index b55e09925c775..f12941cb8433c 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-05-26 +date: 2023-05-30 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 0a5dfec0dc07b..72569a2039f81 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index 8bd2aebccfba4..990a7738968c9 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -382,38 +382,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.ButtonGroupField", - "type": "Function", - "tags": [], - "label": "ButtonGroupField", - "description": [], - "signature": [ - "React.NamedExoticComponent" - ], - "path": "x-pack/plugins/triggers_actions_ui/public/application/components/button_group_field.tsx", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.ButtonGroupField.$1", - "type": "Uncategorized", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "P" - ], - "path": "node_modules/@types/react/index.d.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "triggersActionsUi", "id": "def-public.CreateConnectorFlyout", @@ -858,46 +826,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.HiddenField", - "type": "Function", - "tags": [], - "label": "HiddenField", - "description": [], - "signature": [ - "React.NamedExoticComponent<", - "Props", - "> & { readonly type: (props: ", - "Props", - ") => JSX.Element; }" - ], - "path": "x-pack/plugins/triggers_actions_ui/public/application/components/hidden_field.tsx", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.HiddenField.$1", - "type": "Uncategorized", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "P" - ], - "path": "node_modules/@types/react/index.d.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "triggersActionsUi", "id": "def-public.JsonEditorWithMessageVariables", @@ -1333,38 +1261,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.PasswordField", - "type": "Function", - "tags": [], - "label": "PasswordField", - "description": [], - "signature": [ - "React.NamedExoticComponent" - ], - "path": "x-pack/plugins/triggers_actions_ui/public/application/components/password_field.tsx", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ - { - "parentPluginId": "triggersActionsUi", - "id": "def-public.PasswordField.$1", - "type": "Uncategorized", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "P" - ], - "path": "node_modules/@types/react/index.d.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "triggersActionsUi", "id": "def-public.SectionLoading", diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index cc8a399effde2..69c190a486d37 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.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 | |-------------------|-----------|------------------------|-----------------| -| 550 | 11 | 521 | 49 | +| 544 | 11 | 518 | 49 | ## Client diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 5d744d37cd317..48a179ee43791 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-05-26 +date: 2023-05-30 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 47b2ec60a49c4..80e150a981e1a 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-05-26 +date: 2023-05-30 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 26e397d3c0ae0..65feb5cabd9c3 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-05-26 +date: 2023-05-30 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 4c81c9558e23f..d4546f5598142 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-05-26 +date: 2023-05-30 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 17e91becfcecc..6fc41e055f655 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-05-26 +date: 2023-05-30 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 165bb0d8d3734..a7c229ee87213 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-05-26 +date: 2023-05-30 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 d33fc2c1662fa..745331d898761 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-05-26 +date: 2023-05-30 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 310fa50438e00..cc71eee0ffc2a 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-05-26 +date: 2023-05-30 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 3ba5e498f9666..6545a48b4c3f2 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-05-26 +date: 2023-05-30 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 b7411d19ef55b..0501d0b9c7938 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-05-26 +date: 2023-05-30 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 3ee1664d1b9f5..e2ae86298bbcb 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-05-26 +date: 2023-05-30 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 14249990eeaf2..fa7527c6ad4a1 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-05-26 +date: 2023-05-30 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 c6d2fcf1ef862..e1943faa46368 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-05-26 +date: 2023-05-30 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 fca8b4872f8fd..0350b5ddc6af7 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-05-26 +date: 2023-05-30 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 0f642daba37eb..04b7e56d915ce 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-05-26 +date: 2023-05-30 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 5cbba4f9fb1bd..7687223c7bc0f 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-05-26 +date: 2023-05-30 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 53487798aafd9..a3966cf6fa5a0 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-05-26 +date: 2023-05-30 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 3a72690db580e..0c116426d81ea 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-05-26 +date: 2023-05-30 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 30ebb8e894074..add998c65ee51 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-05-26 +date: 2023-05-30 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 316f61cbf6edf..c80cf62a97086 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-05-26 +date: 2023-05-30 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 10361da592e5b..ea5befd4070f7 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-05-26 +date: 2023-05-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/config/serverless.yml b/config/serverless.yml index 153ca487205ca..6c8c8938bc22c 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -18,6 +18,7 @@ xpack.license_management.enabled: false #xpack.canvas.enabled: false #only disabable in dev-mode xpack.reporting.enabled: false xpack.cloud_integrations.data_migration.enabled: false +data.search.sessions.enabled: false # Enforce restring access to internal APIs see https://github.com/elastic/kibana/issues/151940 # server.restrictInternalApis: true diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 7e7c4d5b9ff5c..ac894d34e2d12 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -478,8 +478,6 @@ Uptime:: [[release-notes-8.7.1]] == {kib} 8.7.1 -coming::[8.7.1] - Review the following information about the {kib} 8.7.1 release. [float] @@ -1089,6 +1087,18 @@ For each {kibana-ref}/xpack-spaces.html[space], complete the following to change . Enter `100`, then click *Save changes*. ==== +[discrete] +[[breaking-158338]] +.CSV reports use PIT instead of Scroll +[%collapsible] +==== +*Details* + +CSV reports now use PIT instead of Scroll. Previously generated CSV reports that used an index alias with alias-only privileges, but without privileges on the alias referenced-indices will no longer generate. For more information, refer to {kibana-pull}158338[#158338]. + +*Impact* + +To generate CSV reports, grant `read` privileges to the underlying indices. +==== + To review the breaking changes in previous versions, refer to the following: {kibana-ref-all}/8.5/release-notes-8.5.0.html#breaking-changes-8.5.0[8.5.0] | {kibana-ref-all}/8.4/release-notes-8.4.0.html#breaking-changes-8.4.0[8.4.0] | {kibana-ref-all}/8.3/release-notes-8.3.0.html#breaking-changes-8.3.0[8.3.0] | {kibana-ref-all}/8.2/release-notes-8.2.0.html#breaking-changes-8.2.0[8.2.0] | {kibana-ref-all}/8.1/release-notes-8.1.0.html#breaking-changes-8.1.0[8.1.0] | {kibana-ref-all}/8.0/release-notes-8.0.0.html#breaking-changes-8.0.0[8.0.0] | {kibana-ref-all}/8.0/release-notes-8.0.0-rc2.html#breaking-changes-8.0.0-rc2[8.0.0-rc2] | {kibana-ref-all}/8.0/release-notes-8.0.0-rc1.html#breaking-changes-8.0.0-rc1[8.0.0-rc1] | {kibana-ref-all}/8.0/release-notes-8.0.0-beta1.html#breaking-changes-8.0.0-beta1[8.0.0-beta1] | {kibana-ref-all}/8.0/release-notes-8.0.0-alpha2.html#breaking-changes-8.0.0-alpha2[8.0.0-alpha2] | {kibana-ref-all}/8.0/release-notes-8.0.0-alpha1.html#breaking-changes-8.0.0-alpha1[8.0.0-alpha1] diff --git a/docs/setup/access.asciidoc b/docs/setup/access.asciidoc index 77ad6ffb9c602..a828eb345ac83 100644 --- a/docs/setup/access.asciidoc +++ b/docs/setup/access.asciidoc @@ -39,19 +39,26 @@ For JSON-formatted server status details, use the `localhost:5601/api/status` AP [float] [[not-ready]] -=== {kib} not ready +=== Troubleshoot {kib} UI error -If you receive an error that the {kib} `server is not ready`, check the following: +Troubleshoot the `{kib} Server is not Ready yet` error. -* The {es} connectivity: +. From within a {kib} node, confirm the connection to {es}: + [source,sh] ---- `curl -XGET elasticsearch_ip_or_hostname:9200/` ---- -* The {kib} logs: -** Linux, DEB or RPM package: `/var/log/kibana/kibana.log` -** Linux, tar.gz package: `$KIBANA_HOME/log/kibana.log` -** Windows: `$KIBANA_HOME\log\kibana.log` -* The health status of `.kibana*` indices - +. Guarantee the health of the three {kib}-backing indices. All indices must appear and display `status:green` and `status:open`: ++ +[source,sh] +---- +`curl -XGET elasticsearch_ip_or_hostname:9200/_cat/indices/.kibana,.kibana_task_manager,.kibana_security_session?v=true` +---- +. <>. +. Choose any {kib} node, then update the config to set the <>. +. <>, then check the start-up debug logs for `ERROR` messages or other start-up issues. ++ +For example: +* When {kib} is unable to connect to a healthy {es} cluster, the `master_not_discovered_exception` or `Unable to revive connection` errors appear. +* When one or more {kib}-backing indices are unhealthy, the `index_not_green_timeout` error appears. diff --git a/package.json b/package.json index 9020fbb393a52..cd2786c9a9e13 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@elastic/apm-rum-react": "^1.4.2", "@elastic/charts": "55.0.0", "@elastic/datemath": "5.0.3", - "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.6.0-canary.3", + "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.8.0-canary.2", "@elastic/ems-client": "8.4.0", "@elastic/eui": "80.0.0", "@elastic/filesaver": "1.1.2", diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_create.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_create.ts index c7802397739c2..52e59ca23519c 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_create.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_create.ts @@ -71,6 +71,7 @@ export const performBulkCreate = async ( encryption: encryptionHelper, preflight: preflightHelper, serializer: serializerHelper, + migration: migrationHelper, } = helpers; const { securityExtension } = extensions; const namespace = commonHelper.getCurrentNamespace(options.namespace); @@ -213,7 +214,7 @@ export const performBulkCreate = async ( const originId = Object.keys(object).includes('originId') ? object.originId : existingOriginId; - const migrated = migrator.migrateDocument({ + const migrated = migrationHelper.migrateInputDocument({ id: object.id, type: object.type, attributes: await encryptionHelper.optionallyEncryptAttributes( diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts index c2d23e3d7c094..3a135d4b73ce8 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/bulk_get.ts @@ -60,6 +60,7 @@ export const performBulkGet = async ( common: commonHelper, validation: validationHelper, encryption: encryptionHelper, + migration: migrationHelper, } = helpers; const { securityExtension, spacesExtension } = extensions; @@ -203,7 +204,7 @@ export const performBulkGet = async ( const document = getSavedObjectFromSource(registry, type, id, doc, { migrationVersionCompatibility, }); - const migrated = migrator.migrateDocument(document); + const migrated = migrationHelper.migrateStorageDocument(document); return migrated; }), diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/create.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/create.ts index b8b9b8a0d2dbb..cbde193f0f922 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/create.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/create.ts @@ -44,6 +44,7 @@ export const performCreate = async ( encryption: encryptionHelper, preflight: preflightHelper, serializer: serializerHelper, + migration: migrationHelper, } = helpers; const { securityExtension } = extensions; @@ -114,7 +115,7 @@ export const performCreate = async ( // 1. If the originId has been *explicitly set* in the options (defined or undefined), respect that. // 2. Otherwise, preserve the originId of the existing object that is being overwritten, if any. const originId = Object.keys(options).includes('originId') ? options.originId : existingOriginId; - const migrated = migrator.migrateDocument({ + const migrated = migrationHelper.migrateInputDocument({ id, type, ...(savedObjectNamespace && { namespace: savedObjectNamespace }), diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts index c13743221af36..4fa0068313b51 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/find.ts @@ -57,6 +57,7 @@ export const performFind = async ( common: commonHelper, encryption: encryptionHelper, serializer: serializerHelper, + migration: migrationHelper, } = helpers; const { securityExtension, spacesExtension } = extensions; let namespaces!: string[]; @@ -237,15 +238,18 @@ export const performFind = async ( per_page: perPage, total: body.hits.total, saved_objects: body.hits.hits.map( - (hit: estypes.SearchHit): SavedObjectsFindResult => ({ - ...(migrator.migrateDocument( + (hit: estypes.SearchHit): SavedObjectsFindResult => { + const savedObject = migrationHelper.migrateStorageDocument( serializerHelper.rawToSavedObject(hit as SavedObjectsRawDoc, { migrationVersionCompatibility, }) - ) as SavedObject), - score: hit._score!, - sort: hit.sort, - }) + ) as SavedObject; + return { + ...savedObject, + score: hit._score!, + sort: hit.sort, + }; + } ), pit_id: body.pit_id, } as typeof result; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts index e515728fa19db..215036f29583c 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/get.ts @@ -34,7 +34,11 @@ export const performGet = async ( extensions = {}, }: ApiExecutionContext ): Promise> => { - const { common: commonHelper, encryption: encryptionHelper } = helpers; + const { + common: commonHelper, + encryption: encryptionHelper, + migration: migrationHelper, + } = helpers; const { securityExtension } = extensions; const namespace = commonHelper.getCurrentNamespace(options.namespace); @@ -82,7 +86,7 @@ export const performGet = async ( let migrated: SavedObject; try { - migrated = migrator.migrateDocument(document) as SavedObject; + migrated = migrationHelper.migrateStorageDocument(document) as SavedObject; } catch (error) { throw SavedObjectsErrorHelpers.decorateGeneralError( error, diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts index 7c59a738ad3d7..9989b4264f28f 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts @@ -11,13 +11,16 @@ import type { IEncryptionHelper } from './encryption'; import type { IValidationHelper } from './validation'; import type { IPreflightCheckHelper } from './preflight_check'; import type { ISerializerHelper } from './serializer'; +import type { IMigrationHelper } from './migration'; -export { CommonHelper } from './common'; -export { EncryptionHelper } from './encryption'; -export { ValidationHelper } from './validation'; -export { SerializerHelper } from './serializer'; +export { CommonHelper, type ICommonHelper } from './common'; +export { EncryptionHelper, type IEncryptionHelper } from './encryption'; +export { ValidationHelper, type IValidationHelper } from './validation'; +export { SerializerHelper, type ISerializerHelper } from './serializer'; +export { MigrationHelper, type IMigrationHelper } from './migration'; export { PreflightCheckHelper, + type IPreflightCheckHelper, type PreflightCheckNamespacesParams, type PreflightCheckNamespacesResult, } from './preflight_check'; @@ -28,4 +31,5 @@ export interface RepositoryHelpers { validation: IValidationHelper; preflight: IPreflightCheckHelper; serializer: ISerializerHelper; + migration: IMigrationHelper; } diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.ts new file mode 100644 index 0000000000000..c7ae86b101984 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/migration.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { PublicMethodsOf } from '@kbn/utility-types'; +import type { SavedObjectUnsanitizedDoc } from '@kbn/core-saved-objects-server'; +import type { IKibanaMigrator } from '@kbn/core-saved-objects-base-server-internal'; + +export type IMigrationHelper = PublicMethodsOf; + +/** + * Repository helper for document migrations. + */ +export class MigrationHelper { + private migrator: IKibanaMigrator; + + constructor({ migrator }: { migrator: IKibanaMigrator }) { + this.migrator = migrator; + } + + /** + * Migrate the given SO document, throwing if a downgrade is required. + * This function is meant to be used by write APIs (create, update) for documents provided as input. + * before storing it in the index. It will therefore throw if the document is in a higher / unknown version. + */ + migrateInputDocument(document: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc { + return this.migrator.migrateDocument(document, { allowDowngrade: false }); + } + + /** + * Migrate the given SO document, accepting downgrades. + * This function is meant to be used by read APIs (get, find) for documents fetched from the index. + * It will therefore accept downgrading the document before returning it from the API. + */ + migrateStorageDocument(document: SavedObjectUnsanitizedDoc): SavedObjectUnsanitizedDoc { + return this.migrator.migrateDocument(document, { allowDowngrade: true }); + } +} diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts index 6ff63bc437189..6abb1b6acf55f 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/increment_counter_internal.ts @@ -32,7 +32,7 @@ export const incrementCounterInternal = async ( { type, id, counterFields, options }: PerformIncrementCounterInternalParams, { registry, helpers, client, serializer, migrator }: ApiExecutionContext ): Promise> => { - const { common: commonHelper, preflight: preflightHelper } = helpers; + const { common: commonHelper, preflight: preflightHelper, migration: migrationHelper } = helpers; const { migrationVersion, @@ -97,7 +97,7 @@ export const incrementCounterInternal = async ( } // attributes: { [counterFieldName]: incrementBy }, - const migrated = migrator.migrateDocument({ + const migrated = migrationHelper.migrateInputDocument({ id, type, ...(savedObjectNamespace && { namespace: savedObjectNamespace }), diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts index fe3cdc5ba5583..d1fb50a1bc08a 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.test.ts @@ -386,8 +386,14 @@ describe('internalBulkResolve', () => { ]); expect(migrator.migrateDocument).toHaveBeenCalledTimes(2); - expect(migrator.migrateDocument).nthCalledWith(1, 'mock-obj-for-1'); - expect(migrator.migrateDocument).nthCalledWith(2, 'mock-obj-for-2'); + expect(migrator.migrateDocument).nthCalledWith( + 1, + 'mock-obj-for-1', + expect.objectContaining({ allowDowngrade: expect.any(Boolean) }) + ); + expect(migrator.migrateDocument).nthCalledWith(2, 'mock-obj-for-2', { + allowDowngrade: expect.any(Boolean), + }); }); }); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts index ed77fbe69b2f8..53cb04453555c 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/internals/internal_bulk_resolve.ts @@ -187,7 +187,7 @@ export async function internalBulkResolve( const object = getSavedObjectFromSource(registry, objectType, objectId, doc, { migrationVersionCompatibility, }); - const migrated = migrator.migrateDocument(object) as SavedObject; + const migrated = migrator.migrateDocument(object, { allowDowngrade: true }) as SavedObject; if (!encryptionExtension?.isEncryptableType(migrated.type)) { return migrated; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts index eceb738ac7ae9..27f3d45c642de 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts @@ -47,6 +47,7 @@ export const performUpdate = async ( common: commonHelper, encryption: encryptionHelper, preflight: preflightHelper, + migration: migrationHelper, } = helpers; const { securityExtension } = extensions; @@ -108,7 +109,7 @@ export const performUpdate = async ( savedObjectNamespaces = preflightResult!.savedObjectNamespaces; } - const migrated = migrator.migrateDocument({ + const migrated = migrationHelper.migrateInputDocument({ id, type, ...(savedObjectNamespace && { namespace: savedObjectNamespace }), diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts index 2a27208956591..ab41890d36368 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts @@ -148,7 +148,13 @@ describe('SavedObjectsRepository', () => { const expectMigrationArgs = (args: unknown, contains = true, n = 1) => { const obj = contains ? expect.objectContaining(args) : expect.not.objectContaining(args); - expect(migrator.migrateDocument).toHaveBeenNthCalledWith(n, obj); + expect(migrator.migrateDocument).toHaveBeenNthCalledWith( + n, + obj, + expect.objectContaining({ + allowDowngrade: expect.any(Boolean), + }) + ); }; beforeEach(() => { @@ -1406,8 +1412,8 @@ describe('SavedObjectsRepository', () => { 'migrated', ]); expect(migrator.migrateDocument).toHaveBeenCalledTimes(2); - expect(migrator.migrateDocument).nthCalledWith(1, expect.objectContaining({ id: obj1.id })); - expect(migrator.migrateDocument).nthCalledWith(2, expect.objectContaining({ id: obj2.id })); + expectMigrationArgs({ id: obj1.id }, true, 1); + expectMigrationArgs({ id: obj2.id }, true, 2); }); }); }); @@ -3992,15 +3998,13 @@ describe('SavedObjectsRepository', () => { expect(migrator.migrateDocument).toHaveBeenCalledTimes( noNamespaceSearchResults.hits.hits.length ); - expect(migrator.migrateDocument).toHaveBeenCalledWith( - expect.objectContaining({ - type, - id: noNamespaceSearchResults.hits.hits[0]._id.replace( - /(index-pattern|config|globalType)\:/, - '' - ), - }) - ); + expectMigrationArgs({ + type, + id: noNamespaceSearchResults.hits.hits[0]._id.replace( + /(index-pattern|config|globalType)\:/, + '' + ), + }); }); }); @@ -4360,12 +4364,10 @@ describe('SavedObjectsRepository', () => { ); await expect(getSuccess(client, repository, registry, type, id)).resolves.toBe('migrated'); expect(migrator.migrateDocument).toHaveBeenCalledTimes(1); - expect(migrator.migrateDocument).toHaveBeenCalledWith( - expect.objectContaining({ - id, - type, - }) - ); + expectMigrationArgs({ + id, + type, + }); }); }); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts index 409138cd635de..321c5811ea6d8 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts @@ -64,14 +64,7 @@ import { } from '@kbn/core-saved-objects-base-server-internal'; import { PointInTimeFinder } from './point_in_time_finder'; import { createRepositoryEsClient, type RepositoryEsClient } from './repository_es_client'; -import { - RepositoryHelpers, - CommonHelper, - EncryptionHelper, - ValidationHelper, - PreflightCheckHelper, - SerializerHelper, -} from './apis/helpers'; +import type { RepositoryHelpers } from './apis/helpers'; import { type ApiExecutionContext, performCreate, @@ -93,6 +86,7 @@ import { performUpdateObjectsSpaces, performCollectMultiNamespaceReferences, } from './apis'; +import { createRepositoryHelpers } from './utils'; /** * Constructor options for {@link SavedObjectsRepository} @@ -198,42 +192,16 @@ export class SavedObjectsRepository implements ISavedObjectsRepository { this.serializer = serializer; this.logger = logger; this.extensions = extensions; - - const commonHelper = new CommonHelper({ - spaceExtension: extensions?.spacesExtension, - encryptionExtension: extensions?.encryptionExtension, - createPointInTimeFinder: this.createPointInTimeFinder.bind(this), - defaultIndex: index, - kibanaVersion: migrator.kibanaVersion, - registry: typeRegistry, - }); - const encryptionHelper = new EncryptionHelper({ - encryptionExtension: extensions?.encryptionExtension, - securityExtension: extensions?.securityExtension, - }); - const validationHelper = new ValidationHelper({ - registry: typeRegistry, + this.helpers = createRepositoryHelpers({ logger, - kibanaVersion: migrator.kibanaVersion, - }); - const preflightCheckHelper = new PreflightCheckHelper({ - getIndexForType: commonHelper.getIndexForType.bind(commonHelper), - createPointInTimeFinder: commonHelper.createPointInTimeFinder.bind(commonHelper), - serializer, - registry: typeRegistry, client: this.client, - }); - const serializerHelper = new SerializerHelper({ - registry: typeRegistry, + index, + typeRegistry, serializer, + extensions, + migrator, + createPointInTimeFinder: this.createPointInTimeFinder.bind(this), }); - this.helpers = { - common: commonHelper, - preflight: preflightCheckHelper, - validation: validationHelper, - encryption: encryptionHelper, - serializer: serializerHelper, - }; this.apiExecutionContext = { client: this.client, extensions: this.extensions, diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/create_helpers.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/create_helpers.ts new file mode 100644 index 0000000000000..17a17be122916 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/create_helpers.ts @@ -0,0 +1,93 @@ +/* + * Copyright 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 { Logger } from '@kbn/logging'; +import type { + IKibanaMigrator, + SavedObjectsSerializer, +} from '@kbn/core-saved-objects-base-server-internal'; +import type { + ISavedObjectTypeRegistry, + SavedObjectsExtensions, +} from '@kbn/core-saved-objects-server'; +import { + RepositoryHelpers, + CommonHelper, + EncryptionHelper, + ValidationHelper, + PreflightCheckHelper, + SerializerHelper, + MigrationHelper, +} from '../apis/helpers'; +import type { RepositoryEsClient } from '../repository_es_client'; +import { CreatePointInTimeFinderFn } from '../point_in_time_finder'; + +interface CreateRepositoryHelpersOptions { + index: string; + client: RepositoryEsClient; + typeRegistry: ISavedObjectTypeRegistry; + serializer: SavedObjectsSerializer; + migrator: IKibanaMigrator; + logger: Logger; + extensions?: SavedObjectsExtensions; + createPointInTimeFinder: CreatePointInTimeFinderFn; +} + +export const createRepositoryHelpers = ({ + logger, + extensions, + index, + client, + typeRegistry, + serializer, + migrator, + createPointInTimeFinder, +}: CreateRepositoryHelpersOptions): RepositoryHelpers => { + const commonHelper = new CommonHelper({ + spaceExtension: extensions?.spacesExtension, + encryptionExtension: extensions?.encryptionExtension, + createPointInTimeFinder, + defaultIndex: index, + kibanaVersion: migrator.kibanaVersion, + registry: typeRegistry, + }); + const encryptionHelper = new EncryptionHelper({ + encryptionExtension: extensions?.encryptionExtension, + securityExtension: extensions?.securityExtension, + }); + const validationHelper = new ValidationHelper({ + registry: typeRegistry, + logger, + kibanaVersion: migrator.kibanaVersion, + }); + const preflightCheckHelper = new PreflightCheckHelper({ + getIndexForType: commonHelper.getIndexForType.bind(commonHelper), + createPointInTimeFinder: commonHelper.createPointInTimeFinder.bind(commonHelper), + serializer, + registry: typeRegistry, + client, + }); + const serializerHelper = new SerializerHelper({ + registry: typeRegistry, + serializer, + }); + const migrationHelper = new MigrationHelper({ + migrator, + }); + + const helpers: RepositoryHelpers = { + common: commonHelper, + preflight: preflightCheckHelper, + validation: validationHelper, + encryption: encryptionHelper, + serializer: serializerHelper, + migration: migrationHelper, + }; + + return helpers; +}; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts index 84c2379905b31..ba96c10da0090 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts @@ -8,3 +8,4 @@ export { decorateEsError } from './decorate_es_error'; export { getRootFields, includedFields } from './included_fields'; +export { createRepositoryHelpers } from './create_helpers'; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts index d5caf01cf59c0..69f0124f681e1 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts @@ -13,8 +13,23 @@ import type { ValidationHelper, PreflightCheckHelper, SerializerHelper, + MigrationHelper, } from '../lib/apis/helpers'; +export type MigrationHelperMock = jest.Mocked>; + +const createMigrationHelperMock = (): MigrationHelperMock => { + const mock: MigrationHelperMock = { + migrateInputDocument: jest.fn(), + migrateStorageDocument: jest.fn(), + }; + + mock.migrateInputDocument.mockImplementation((doc) => doc); + mock.migrateStorageDocument.mockImplementation((doc) => doc); + + return mock; +}; + export type CommonHelperMock = jest.Mocked>; const createCommonHelperMock = (): CommonHelperMock => { @@ -88,6 +103,7 @@ export interface RepositoryHelpersMock { validation: ValidationHelperMock; preflight: PreflightCheckHelperMock; serializer: SerializerHelperMock; + migration: MigrationHelperMock; } const createRepositoryHelpersMock = (): RepositoryHelpersMock => { @@ -97,6 +113,7 @@ const createRepositoryHelpersMock = (): RepositoryHelpersMock => { validation: createValidationHelperMock(), preflight: createPreflightCheckHelperMock(), serializer: createSerializerHelperMock(), + migration: createMigrationHelperMock(), }; }; @@ -107,4 +124,5 @@ export const apiHelperMocks = { createValidationHelper: createValidationHelperMock, createSerializerHelper: createSerializerHelperMock, createPreflightCheckHelper: createPreflightCheckHelperMock, + createMigrationHelper: createMigrationHelperMock, }; diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts index 8af470de187f0..c402031897445 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/saved_objects_config.ts @@ -9,6 +9,7 @@ import { valid } from 'semver'; import { schema, TypeOf } from '@kbn/config-schema'; import type { ServiceConfigDescriptor } from '@kbn/core-base-server-internal'; +import buffer from 'buffer'; const migrationSchema = schema.object({ algorithm: schema.oneOf([schema.literal('v2'), schema.literal('zdt')], { @@ -16,6 +17,10 @@ const migrationSchema = schema.object({ }), batchSize: schema.number({ defaultValue: 1_000 }), maxBatchSizeBytes: schema.byteSize({ defaultValue: '100mb' }), // 100mb is the default http.max_content_length Elasticsearch config value + maxReadBatchSizeBytes: schema.byteSize({ + defaultValue: buffer.constants.MAX_STRING_LENGTH, + max: buffer.constants.MAX_STRING_LENGTH, + }), discardUnknownObjects: schema.maybe( schema.string({ validate: (value: string) => diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts index 3845ab745cfdb..2a0da30136a7b 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/index.ts @@ -47,6 +47,7 @@ export type { ReindexResponse, UpdateByQueryResponse, UpdateAndPickupMappingsResponse, + EsResponseTooLargeError, } from './src/actions'; export { isClusterShardLimitExceeded, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap index 421e081b44a69..651182fb621fa 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap @@ -166,7 +166,9 @@ Object { "message": "Log from LEGACY_REINDEX control state", }, ], + "maxBatchSize": 1000, "maxBatchSizeBytes": 100000000, + "maxReadBatchSizeBytes": 536870888, "migrationDocLinks": Object { "clusterShardLimitExceeded": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#cluster-shard-limit-exceeded", "repeatedTimeoutRequests": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#_repeated_time_out_requests_that_eventually_fail", @@ -392,7 +394,9 @@ Object { "message": "Log from LEGACY_DELETE control state", }, ], + "maxBatchSize": 1000, "maxBatchSizeBytes": 100000000, + "maxReadBatchSizeBytes": 536870888, "migrationDocLinks": Object { "clusterShardLimitExceeded": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#cluster-shard-limit-exceeded", "repeatedTimeoutRequests": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#_repeated_time_out_requests_that_eventually_fail", @@ -622,7 +626,9 @@ Object { "message": "Log from LEGACY_DELETE control state", }, ], + "maxBatchSize": 1000, "maxBatchSizeBytes": 100000000, + "maxReadBatchSizeBytes": 536870888, "migrationDocLinks": Object { "clusterShardLimitExceeded": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#cluster-shard-limit-exceeded", "repeatedTimeoutRequests": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#_repeated_time_out_requests_that_eventually_fail", @@ -856,7 +862,9 @@ Object { "message": "Log from DONE control state", }, ], + "maxBatchSize": 1000, "maxBatchSizeBytes": 100000000, + "maxReadBatchSizeBytes": 536870888, "migrationDocLinks": Object { "clusterShardLimitExceeded": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#cluster-shard-limit-exceeded", "repeatedTimeoutRequests": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#_repeated_time_out_requests_that_eventually_fail", @@ -1110,7 +1118,9 @@ Object { "message": "Log from LEGACY_DELETE control state", }, ], + "maxBatchSize": 1000, "maxBatchSizeBytes": 100000000, + "maxReadBatchSizeBytes": 536870888, "migrationDocLinks": Object { "clusterShardLimitExceeded": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#cluster-shard-limit-exceeded", "repeatedTimeoutRequests": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#_repeated_time_out_requests_that_eventually_fail", @@ -1347,7 +1357,9 @@ Object { "message": "Log from FATAL control state", }, ], + "maxBatchSize": 1000, "maxBatchSizeBytes": 100000000, + "maxReadBatchSizeBytes": 536870888, "migrationDocLinks": Object { "clusterShardLimitExceeded": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#cluster-shard-limit-exceeded", "repeatedTimeoutRequests": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#_repeated_time_out_requests_that_eventually_fail", diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts index 989e50af73683..ffe0189abe237 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts @@ -72,7 +72,7 @@ describe('catchRetryableEsClientErrors', () => { }); }); it('ResponseError with retryable status code', async () => { - const statusCodes = [503, 401, 403, 408, 410]; + const statusCodes = [503, 401, 403, 408, 410, 429]; return Promise.all( statusCodes.map(async (status) => { const error = new esErrors.ResponseError( diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts index 168e3170d30bf..74877c9386422 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.ts @@ -15,6 +15,7 @@ const retryResponseStatuses = [ 403, // AuthenticationException 408, // RequestTimeout 410, // Gone + 429, // TooManyRequests -> ES circuit breaker ]; export interface RetryableEsClientError { diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts index b81101879a734..dbe61920b31b3 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/index.ts @@ -146,6 +146,11 @@ export interface RequestEntityTooLargeException { type: 'request_entity_too_large_exception'; } +export interface EsResponseTooLargeError { + type: 'es_response_too_large'; + contentLength: number; +} + /** @internal */ export interface AcknowledgeResponse { acknowledged: boolean; @@ -168,6 +173,7 @@ export interface ActionErrorTypeMap { index_not_green_timeout: IndexNotGreenTimeout; index_not_yellow_timeout: IndexNotYellowTimeout; cluster_shard_limit_exceeded: ClusterShardLimitExceeded; + es_response_too_large: EsResponseTooLargeError; } /** diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.test.ts index d2f7a3ab3c3d7..181ae3d8b6a98 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.test.ts @@ -32,23 +32,54 @@ describe('readWithPit', () => { pitId: 'pitId', query: { match_all: {} }, batchSize: 10_000, + maxResponseSizeBytes: 100_000, })(); expect(client.search).toHaveBeenCalledTimes(1); - expect(client.search).toHaveBeenCalledWith({ - allow_partial_search_results: false, - pit: { - id: 'pitId', - keep_alive: '10m', - }, - query: { - match_all: {}, + expect(client.search).toHaveBeenCalledWith( + { + allow_partial_search_results: false, + pit: { + id: 'pitId', + keep_alive: '10m', + }, + query: { + match_all: {}, + }, + search_after: undefined, + seq_no_primary_term: undefined, + size: 10000, + sort: '_shard_doc:asc', + track_total_hits: true, }, - search_after: undefined, - seq_no_primary_term: undefined, - size: 10000, - sort: '_shard_doc:asc', - track_total_hits: true, + { maxResponseSize: 100_000 } + ); + }); + + it('returns left es_response_too_large when client throws RequestAbortedError', async () => { + // Create a mock client that rejects all methods with a RequestAbortedError + // response. + const retryableError = new EsErrors.RequestAbortedError( + 'The content length (536870889) is bigger than the maximum allow string (536870888)' + ); + const client = elasticsearchClientMock.createInternalClient( + elasticsearchClientMock.createErrorTransportRequestPromise(retryableError) + ); + + const task = readWithPit({ + client, + pitId: 'pitId', + query: { match_all: {} }, + batchSize: 10_000, + }); + try { + await task(); + } catch (e) { + /** ignore */ + } + await expect(task()).resolves.toEqual({ + _tag: 'Left', + left: { contentLength: 536870889, type: 'es_response_too_large' }, }); }); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.ts index 1d0303947c1b6..91652f2175ff7 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/read_with_pit.ts @@ -9,6 +9,7 @@ import * as Either from 'fp-ts/lib/Either'; import * as TaskEither from 'fp-ts/lib/TaskEither'; import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { errors as EsErrors } from '@elastic/elasticsearch'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { SavedObjectsRawDoc } from '@kbn/core-saved-objects-server'; import { @@ -16,6 +17,7 @@ import { type RetryableEsClientError, } from './catch_retryable_es_client_errors'; import { DEFAULT_PIT_KEEP_ALIVE } from './open_pit'; +import { EsResponseTooLargeError } from '.'; /** @internal */ export interface ReadWithPit { @@ -32,6 +34,7 @@ export interface ReadWithPitParams { batchSize: number; searchAfter?: number[]; seqNoPrimaryTerm?: boolean; + maxResponseSizeBytes?: number; } /* @@ -45,32 +48,39 @@ export const readWithPit = batchSize, searchAfter, seqNoPrimaryTerm, - }: ReadWithPitParams): TaskEither.TaskEither => + maxResponseSizeBytes, + }: ReadWithPitParams): TaskEither.TaskEither< + RetryableEsClientError | EsResponseTooLargeError, + ReadWithPit + > => () => { return client - .search({ - seq_no_primary_term: seqNoPrimaryTerm, - // Fail if the index being searched doesn't exist or is closed - // allow_no_indices: false, - // By default ES returns a 200 with partial results if there are shard - // request timeouts or shard failures which can lead to data loss for - // migrations - allow_partial_search_results: false, - // Sort fields are required to use searchAfter so we sort by the - // natural order of the index which is the most efficient option - // as order is not important for the migration - sort: '_shard_doc:asc', - pit: { id: pitId, keep_alive: DEFAULT_PIT_KEEP_ALIVE }, - size: batchSize, - search_after: searchAfter, - /** - * We want to know how many documents we need to process so we can log the progress. - * But we also want to increase the performance of these requests, - * so we ask ES to report the total count only on the first request (when searchAfter does not exist) - */ - track_total_hits: typeof searchAfter === 'undefined', - query, - }) + .search( + { + seq_no_primary_term: seqNoPrimaryTerm, + // Fail if the index being searched doesn't exist or is closed + // allow_no_indices: false, + // By default ES returns a 200 with partial results if there are shard + // request timeouts or shard failures which can lead to data loss for + // migrations + allow_partial_search_results: false, + // Sort fields are required to use searchAfter so we sort by the + // natural order of the index which is the most efficient option + // as order is not important for the migration + sort: '_shard_doc:asc', + pit: { id: pitId, keep_alive: DEFAULT_PIT_KEEP_ALIVE }, + size: batchSize, + search_after: searchAfter, + /** + * We want to know how many documents we need to process so we can log the progress. + * But we also want to increase the performance of these requests, + * so we ask ES to report the total count only on the first request (when searchAfter does not exist) + */ + track_total_hits: typeof searchAfter === 'undefined', + query, + }, + { maxResponseSize: maxResponseSizeBytes } + ) .then((body) => { const totalHits = typeof body.hits.total === 'number' @@ -93,5 +103,22 @@ export const readWithPit = totalHits, }); }) + .catch((e) => { + if ( + e instanceof EsErrors.RequestAbortedError && + /The content length \(\d+\) is bigger than the maximum/.test(e.message) + ) { + return Either.left({ + type: 'es_response_too_large' as const, + contentLength: Number.parseInt( + e.message.match(/The content length \((\d+)\) is bigger than the maximum/)?.[1] ?? + '-1', + 10 + ), + }); + } else { + throw e; + } + }) .catch(catchRetryableEsClientErrors); }; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts index 21b6e437d481c..60b47ada7828c 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts @@ -27,6 +27,7 @@ const migrationsConfig = { retryAttempts: 15, batchSize: 1000, maxBatchSizeBytes: ByteSizeValue.parse('100mb'), + maxReadBatchSizeBytes: ByteSizeValue.parse('500mb'), } as unknown as SavedObjectsMigrationConfigType; const createInitialStateCommonParams = { @@ -217,7 +218,9 @@ describe('createInitialState', () => { "knownTypes": Array [], "legacyIndex": ".kibana_task_manager", "logs": Array [], + "maxBatchSize": 1000, "maxBatchSizeBytes": 104857600, + "maxReadBatchSizeBytes": 524288000, "migrationDocLinks": Object { "clusterShardLimitExceeded": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#cluster-shard-limit-exceeded", "repeatedTimeoutRequests": "https://www.elastic.co/guide/en/kibana/test-branch/resolve-migrations-failures.html#_repeated_time_out_requests_that_eventually_fail", diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.ts index 5f2e09c01db6d..0b61d891619c4 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.ts @@ -126,7 +126,9 @@ export const createInitialState = ({ retryDelay: 0, retryAttempts: migrationsConfig.retryAttempts, batchSize: migrationsConfig.batchSize, + maxBatchSize: migrationsConfig.batchSize, maxBatchSizeBytes: migrationsConfig.maxBatchSizeBytes.getValueInBytes(), + maxReadBatchSizeBytes: migrationsConfig.maxReadBatchSizeBytes.getValueInBytes(), discardUnknownObjects: migrationsConfig.discardUnknownObjects === kibanaVersion, discardCorruptObjects: migrationsConfig.discardCorruptObjects === kibanaVersion, logs: [], diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.test.ts index 18955bfc751ae..f9537a584881e 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/kibana_migrator.test.ts @@ -243,9 +243,9 @@ describe('KibanaMigrator', () => { const migrator = new KibanaMigrator(options); migrator.prepareMigrations(); await expect(migrator.runMigrations()).rejects.toMatchInlineSnapshot(` - [Error: Unable to complete saved object migrations for the [.my-index] index. Error: Reindex failed with the following error: - {"_tag":"Some","value":{"type":"elasticsearch_exception","reason":"task failed with an error"}}] - `); + [Error: Unable to complete saved object migrations for the [.my-index] index. Error: Reindex failed with the following error: + {"_tag":"Some","value":{"type":"elasticsearch_exception","reason":"task failed with an error"}}] + `); expect(loggingSystemMock.collect(options.logger).error[0][0]).toMatchInlineSnapshot(` [Error: Reindex failed with the following error: {"_tag":"Some","value":{"type":"elasticsearch_exception","reason":"task failed with an error"}}] @@ -533,6 +533,7 @@ const mockOptions = () => { algorithm: 'v2', batchSize: 20, maxBatchSizeBytes: ByteSizeValue.parse('20mb'), + maxReadBatchSizeBytes: new ByteSizeValue(536870888), pollInterval: 20000, scrollDuration: '10m', skip: false, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/migrations_state_action_machine.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/migrations_state_action_machine.test.ts index 04ecf73e23872..2f734b3a56487 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/migrations_state_action_machine.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/migrations_state_action_machine.test.ts @@ -51,6 +51,7 @@ describe('migrationsStateActionMachine', () => { algorithm: 'v2', batchSize: 1000, maxBatchSizeBytes: new ByteSizeValue(1e8), + maxReadBatchSizeBytes: new ByteSizeValue(536870888), pollInterval: 0, scrollDuration: '0s', skip: false, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/helpers.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/helpers.ts index c8d8884c980cd..e83601a49e172 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/helpers.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/helpers.ts @@ -17,6 +17,7 @@ import type { SavedObjectsRawDoc } from '@kbn/core-saved-objects-server'; import type { IndexMapping } from '@kbn/core-saved-objects-base-server-internal'; import type { AliasAction, FetchIndexResponse } from '../actions'; import type { BulkIndexOperationTuple } from './create_batches'; +import { OutdatedDocumentsSearchRead, ReindexSourceToTempRead } from '../state'; /** @internal */ export type Aliases = Partial>; @@ -285,3 +286,11 @@ export function getMigrationType({ */ export const getTempIndexName = (indexPrefix: string, kibanaVersion: string): string => `${indexPrefix}_${kibanaVersion}_reindex_temp`; + +/** Increase batchSize by 20% until a maximum of maxBatchSize */ +export const increaseBatchSize = ( + stateP: OutdatedDocumentsSearchRead | ReindexSourceToTempRead +) => { + const increasedBatchSize = Math.floor(stateP.batchSize * 1.2); + return increasedBatchSize > stateP.maxBatchSize ? stateP.maxBatchSize : increasedBatchSize; +}; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts index 969a7704e4e75..892ca75aea2f0 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.test.ts @@ -86,7 +86,9 @@ describe('migrations v2 model', () => { retryDelay: 0, retryAttempts: 15, batchSize: 1000, + maxBatchSize: 1000, maxBatchSizeBytes: 1e8, + maxReadBatchSizeBytes: 1234, discardUnknownObjects: false, discardCorruptObjects: false, indexPrefix: '.kibana', @@ -1832,6 +1834,8 @@ describe('migrations v2 model', () => { expect(newState.lastHitSortValue).toBe(lastHitSortValue); expect(newState.progress.processed).toBe(undefined); expect(newState.progress.total).toBe(1); + expect(newState.maxBatchSize).toBe(1000); + expect(newState.batchSize).toBe(1000); // don't increase batchsize above default expect(newState.logs).toMatchInlineSnapshot(` Array [ Object { @@ -1842,6 +1846,83 @@ describe('migrations v2 model', () => { `); }); + it('REINDEX_SOURCE_TO_TEMP_READ -> REINDEX_SOURCE_TO_TEMP_TRANSFORM increases batchSize if < maxBatchSize', () => { + const outdatedDocuments = [{ _id: '1', _source: { type: 'vis' } }]; + const lastHitSortValue = [123456]; + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_READ'> = Either.right({ + outdatedDocuments, + lastHitSortValue, + totalHits: 1, + processedDocs: 1, + }); + let newState = model({ ...state, batchSize: 500 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(600); + newState = model({ ...state, batchSize: 600 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(720); + newState = model({ ...state, batchSize: 720 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(864); + newState = model({ ...state, batchSize: 864 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(1000); // + 20% would have been 1036 + expect(newState.controlState).toBe('REINDEX_SOURCE_TO_TEMP_TRANSFORM'); + expect(newState.maxBatchSize).toBe(1000); + }); + + it('REINDEX_SOURCE_TO_TEMP_READ -> REINDEX_SOURCE_TO_TEMP_READ if left es_response_too_large', () => { + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_READ'> = Either.left({ + type: 'es_response_too_large', + contentLength: 4567, + }); + const newState = model(state, res) as ReindexSourceToTempRead; + expect(newState.controlState).toBe('REINDEX_SOURCE_TO_TEMP_READ'); + expect(newState.lastHitSortValue).toBe(undefined); // lastHitSortValue should not be set + expect(newState.progress.processed).toBe(undefined); // don't increment progress + expect(newState.batchSize).toBe(500); // halves the batch size + expect(newState.maxBatchSize).toBe(1000); // leaves maxBatchSize unchanged + expect(newState.logs).toMatchInlineSnapshot(` + Array [ + Object { + "level": "warning", + "message": "Read a batch with a response content length of 4567 bytes which exceeds migrations.maxReadBatchSizeBytes, retrying by reducing the batch size in half to 500.", + }, + ] + `); + }); + + it('REINDEX_SOURCE_TO_TEMP_READ -> REINDEX_SOURCE_TO_TEMP_READ if left es_response_too_large will not reduce batch size below 1', () => { + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_READ'> = Either.left({ + type: 'es_response_too_large', + contentLength: 2345, + }); + const newState = model({ ...state, batchSize: 1.5 }, res) as ReindexSourceToTempRead; + expect(newState.controlState).toBe('REINDEX_SOURCE_TO_TEMP_READ'); + expect(newState.lastHitSortValue).toBe(undefined); // lastHitSortValue should not be set + expect(newState.progress.processed).toBe(undefined); // don't increment progress + expect(newState.batchSize).toBe(1); // don't halve the batch size or go below 1 + expect(newState.maxBatchSize).toBe(1000); // leaves maxBatchSize unchanged + expect(newState.logs).toMatchInlineSnapshot(` + Array [ + Object { + "level": "warning", + "message": "Read a batch with a response content length of 2345 bytes which exceeds migrations.maxReadBatchSizeBytes, retrying by reducing the batch size in half to 1.", + }, + ] + `); + }); + + it('REINDEX_SOURCE_TO_TEMP_READ -> FATAL if left es_response_too_large and batchSize already 1', () => { + const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_READ'> = Either.left({ + type: 'es_response_too_large', + contentLength: 2345, + }); + const newState = model({ ...state, batchSize: 1 }, res) as FatalState; + expect(newState.controlState).toBe('FATAL'); + expect(newState.batchSize).toBe(1); // don't halve the batch size or go below 1 + expect(newState.maxBatchSize).toBe(1000); // leaves maxBatchSize unchanged + expect(newState.reason).toMatchInlineSnapshot( + `"After reducing the read batch size to a single document, the Elasticsearch response content length was 2345bytes which still exceeded migrations.maxReadBatchSizeBytes. Increase migrations.maxReadBatchSizeBytes and try again."` + ); + }); + it('REINDEX_SOURCE_TO_TEMP_READ -> REINDEX_SOURCE_TO_TEMP_CLOSE_PIT if no outdated documents to reindex', () => { const res: ResponseType<'REINDEX_SOURCE_TO_TEMP_READ'> = Either.right({ outdatedDocuments: [], @@ -2304,6 +2385,8 @@ describe('migrations v2 model', () => { expect(newState.lastHitSortValue).toBe(lastHitSortValue); expect(newState.progress.processed).toBe(undefined); expect(newState.progress.total).toBe(10); + expect(newState.maxBatchSize).toBe(1000); + expect(newState.batchSize).toBe(1000); // don't increase batchsize above default expect(newState.logs).toMatchInlineSnapshot(` Array [ Object { @@ -2345,6 +2428,83 @@ describe('migrations v2 model', () => { `); }); + it('OUTDATED_DOCUMENTS_SEARCH_READ -> OUTDATED_DOCUMENTS_TRANSFORM increases batchSize up to maxBatchSize', () => { + const outdatedDocuments = [{ _id: '1', _source: { type: 'vis' } }]; + const lastHitSortValue = [123456]; + const res: ResponseType<'OUTDATED_DOCUMENTS_SEARCH_READ'> = Either.right({ + outdatedDocuments, + lastHitSortValue, + totalHits: 1, + processedDocs: [], + }); + let newState = model({ ...state, batchSize: 500 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(600); + newState = model({ ...state, batchSize: 600 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(720); + newState = model({ ...state, batchSize: 720 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(864); + newState = model({ ...state, batchSize: 864 }, res) as ReindexSourceToTempTransform; + expect(newState.batchSize).toBe(1000); // + 20% would have been 1036 + expect(newState.controlState).toBe('OUTDATED_DOCUMENTS_TRANSFORM'); + expect(newState.maxBatchSize).toBe(1000); + }); + + it('OUTDATED_DOCUMENTS_SEARCH_READ -> OUTDATED_DOCUMENTS_SEARCH_READ if left es_response_too_large', () => { + const res: ResponseType<'OUTDATED_DOCUMENTS_SEARCH_READ'> = Either.left({ + type: 'es_response_too_large', + contentLength: 3456, + }); + const newState = model(state, res) as ReindexSourceToTempRead; + expect(newState.controlState).toBe('OUTDATED_DOCUMENTS_SEARCH_READ'); + expect(newState.lastHitSortValue).toBe(undefined); // lastHitSortValue should not be set + expect(newState.progress.processed).toBe(undefined); // don't increment progress + expect(newState.batchSize).toBe(500); // halves the batch size + expect(newState.maxBatchSize).toBe(1000); // leaves maxBatchSize unchanged + expect(newState.logs).toMatchInlineSnapshot(` + Array [ + Object { + "level": "warning", + "message": "Read a batch with a response content length of 3456 bytes which exceeds migrations.maxReadBatchSizeBytes, retrying by reducing the batch size in half to 500.", + }, + ] + `); + }); + + it('OUTDATED_DOCUMENTS_SEARCH_READ -> OUTDATED_DOCUMENTS_SEARCH_READ if left es_response_too_large will not reduce batch size below 1', () => { + const res: ResponseType<'OUTDATED_DOCUMENTS_SEARCH_READ'> = Either.left({ + type: 'es_response_too_large', + contentLength: 2345, + }); + const newState = model({ ...state, batchSize: 1.5 }, res) as ReindexSourceToTempRead; + expect(newState.controlState).toBe('OUTDATED_DOCUMENTS_SEARCH_READ'); + expect(newState.lastHitSortValue).toBe(undefined); // lastHitSortValue should not be set + expect(newState.progress.processed).toBe(undefined); // don't increment progress + expect(newState.batchSize).toBe(1); // don't halve the batch size or go below 1 + expect(newState.maxBatchSize).toBe(1000); // leaves maxBatchSize unchanged + expect(newState.logs).toMatchInlineSnapshot(` + Array [ + Object { + "level": "warning", + "message": "Read a batch with a response content length of 2345 bytes which exceeds migrations.maxReadBatchSizeBytes, retrying by reducing the batch size in half to 1.", + }, + ] + `); + }); + + it('OUTDATED_DOCUMENTS_SEARCH_READ -> FATAL if left es_response_too_large and batchSize already 1', () => { + const res: ResponseType<'OUTDATED_DOCUMENTS_SEARCH_READ'> = Either.left({ + type: 'es_response_too_large', + contentLength: 2345, + }); + const newState = model({ ...state, batchSize: 1 }, res) as FatalState; + expect(newState.controlState).toBe('FATAL'); + expect(newState.batchSize).toBe(1); // don't halve the batch size or go below 1 + expect(newState.maxBatchSize).toBe(1000); // leaves maxBatchSize unchanged + expect(newState.reason).toMatchInlineSnapshot( + `"After reducing the read batch size to a single document, the response content length was 2345 bytes which still exceeded migrations.maxReadBatchSizeBytes. Increase migrations.maxReadBatchSizeBytes and try again."` + ); + }); + it('OUTDATED_DOCUMENTS_SEARCH_READ -> OUTDATED_DOCUMENTS_SEARCH_CLOSE_PIT if no outdated documents to transform', () => { const res: ResponseType<'OUTDATED_DOCUMENTS_SEARCH_READ'> = Either.right({ outdatedDocuments: [], diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts index 54657310912f8..fdeb2d346c2d6 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/model/model.ts @@ -43,6 +43,7 @@ import { versionMigrationCompleted, buildRemoveAliasActions, MigrationType, + increaseBatchSize, } from './helpers'; import { buildTempIndexMap, createBatches } from './create_batches'; import type { MigrationLog } from '../types'; @@ -833,6 +834,8 @@ export const model = (currentState: State, resW: ResponseType): lastHitSortValue: res.right.lastHitSortValue, progress, logs, + // We succeeded in reading this batch, so increase the batch size for the next request. + batchSize: increaseBatchSize(stateP), }; } else { // we don't have any more outdated documents and need to either fail or move on to updating the target mappings. @@ -875,7 +878,32 @@ export const model = (currentState: State, resW: ResponseType): }; } } else { - throwBadResponse(stateP, res); + const left = res.left; + if (isTypeof(left, 'es_response_too_large')) { + if (stateP.batchSize === 1) { + return { + ...stateP, + controlState: 'FATAL', + reason: `After reducing the read batch size to a single document, the Elasticsearch response content length was ${left.contentLength}bytes which still exceeded migrations.maxReadBatchSizeBytes. Increase migrations.maxReadBatchSizeBytes and try again.`, + }; + } else { + const batchSize = Math.max(Math.floor(stateP.batchSize / 2), 1); + return { + ...stateP, + batchSize, + controlState: 'REINDEX_SOURCE_TO_TEMP_READ', + logs: [ + ...stateP.logs, + { + level: 'warning', + message: `Read a batch with a response content length of ${left.contentLength} bytes which exceeds migrations.maxReadBatchSizeBytes, retrying by reducing the batch size in half to ${batchSize}.`, + }, + ], + }; + } + } else { + throwBadResponse(stateP, left); + } } } else if (stateP.controlState === 'REINDEX_SOURCE_TO_TEMP_CLOSE_PIT') { const res = resW as ExcludeRetryableEsError>; @@ -1139,6 +1167,8 @@ export const model = (currentState: State, resW: ResponseType): lastHitSortValue: res.right.lastHitSortValue, progress, logs, + // We succeeded in reading this batch, so increase the batch size for the next request. + batchSize: increaseBatchSize(stateP), }; } else { // we don't have any more outdated documents and need to either fail or move on to updating the target mappings. @@ -1179,7 +1209,32 @@ export const model = (currentState: State, resW: ResponseType): }; } } else { - throwBadResponse(stateP, res); + const left = res.left; + if (isTypeof(left, 'es_response_too_large')) { + if (stateP.batchSize === 1) { + return { + ...stateP, + controlState: 'FATAL', + reason: `After reducing the read batch size to a single document, the response content length was ${left.contentLength} bytes which still exceeded migrations.maxReadBatchSizeBytes. Increase migrations.maxReadBatchSizeBytes and try again.`, + }; + } else { + const batchSize = Math.max(Math.floor(stateP.batchSize / 2), 1); + return { + ...stateP, + batchSize, + controlState: 'OUTDATED_DOCUMENTS_SEARCH_READ', + logs: [ + ...stateP.logs, + { + level: 'warning', + message: `Read a batch with a response content length of ${left.contentLength} bytes which exceeds migrations.maxReadBatchSizeBytes, retrying by reducing the batch size in half to ${batchSize}.`, + }, + ], + }; + } + } else { + throwBadResponse(stateP, left); + } } } else if (stateP.controlState === 'OUTDATED_DOCUMENTS_TRANSFORM') { const res = resW as ExcludeRetryableEsError>; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts index 2ed66ad9933e3..1b5a9fe99fe3a 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/next.ts @@ -219,6 +219,7 @@ export const nextActionMap = ( query: state.outdatedDocumentsQuery, batchSize: state.batchSize, searchAfter: state.lastHitSortValue, + maxResponseSizeBytes: state.maxReadBatchSizeBytes, }), OUTDATED_DOCUMENTS_SEARCH_CLOSE_PIT: (state: OutdatedDocumentsSearchClosePit) => Actions.closePit({ client, pitId: state.pitId }), diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts index 6a483da04a399..8a6be0269947e 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/state.ts @@ -63,7 +63,6 @@ export interface BaseState extends ControlState { * max_retry_time = 11.7 minutes */ readonly retryAttempts: number; - /** * The number of documents to process in each batch. This determines the * maximum number of documents that will be read and written in a single @@ -83,6 +82,12 @@ export interface BaseState extends ControlState { * When writing batches, we limit the number of documents in a batch * (batchSize) as well as the size of the batch in bytes (maxBatchSizeBytes). */ + readonly maxBatchSize: number; + /** + * The number of documents to process in each batch. Under most circumstances + * batchSize == maxBatchSize. But if we fail to read a batch because of a + * Nodejs `RangeError` we'll temporarily half `batchSize` and retry. + */ readonly batchSize: number; /** * When writing batches, limits the batch size in bytes to ensure that we @@ -90,6 +95,12 @@ export interface BaseState extends ControlState { * http.max_content_length which defaults to 100mb. */ readonly maxBatchSizeBytes: number; + /** + * If a read batch exceeds this limit we half the batchSize and retry. By + * not JSON.parsing and transforming large batches we can avoid RangeErrors + * or Kibana OOMing. + */ + readonly maxReadBatchSizeBytes: number; readonly logs: MigrationLog[]; /** * If saved objects exist which have an unknown type they will cause diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/create_target_index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/create_target_index.ts index 9b4d7b8efa6d4..16f8dd6e5ede7 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/create_target_index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/create_target_index.ts @@ -53,5 +53,6 @@ export const createTargetIndex: ModelStage< aliases: [], aliasActions, skipDocumentMigration: true, + previousAlgorithm: 'zdt', }; }; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.test.ts index a44754622be6e..de19ff0304f2f 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.test.ts @@ -46,6 +46,22 @@ describe('Stage: documentsUpdateInit', () => { context.typeRegistry.registerType(createType({ name: 'bar' })); }); + describe('when state.previousAlgorithm is `v2`', () => { + it('DOCUMENTS_UPDATE_INIT -> SET_DOC_MIGRATION_STARTED', () => { + const state = createState({ + previousAlgorithm: 'v2', + }); + const res: ResponseType<'DOCUMENTS_UPDATE_INIT'> = Either.right('noop' as const); + + const newState = documentsUpdateInit( + state, + res as StateActionResponse<'DOCUMENTS_UPDATE_INIT'>, + context + ); + expect(newState.controlState).toEqual('SET_DOC_MIGRATION_STARTED'); + }); + }); + describe('when checkVersionCompatibility returns `greater`', () => { beforeEach(() => { checkVersionCompatibilityMock.mockReturnValue({ diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.ts index f5e1dd3605555..3722dd99428c5 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/documents_update_init.ts @@ -27,6 +27,34 @@ export const documentsUpdateInit: ModelStage< const types = context.types.map((type) => context.typeRegistry.getType(type)!); const logs: MigrationLog[] = [...state.logs]; + const excludeFilterHooks = Object.fromEntries( + context.types + .map((name) => context.typeRegistry.getType(name)!) + .filter((type) => !!type.excludeOnUpgrade) + .map((type) => [type.name, type.excludeOnUpgrade!]) + ); + const outdatedDocumentsQuery = getOutdatedDocumentsQuery({ types }); + const transformRawDocs = createDocumentTransformFn({ + serializer: context.serializer, + documentMigrator: context.documentMigrator, + }); + const commonState = { + logs, + excludeOnUpgradeQuery: excludeUnusedTypesQuery, + excludeFromUpgradeFilterHooks: excludeFilterHooks, + outdatedDocumentsQuery, + transformRawDocs, + }; + + // index was previously using the v2 algo, we skip compat check and jump to next stage + if (state.previousAlgorithm === 'v2') { + return { + ...state, + ...commonState, + controlState: 'SET_DOC_MIGRATION_STARTED', + }; + } + const versionCheck = checkVersionCompatibility({ mappings: state.previousMappings, types, @@ -43,24 +71,9 @@ export const documentsUpdateInit: ModelStage< // app version is greater than the index mapping version. // scenario of an upgrade: we need to run the document migration. case 'greater': - const excludeFilterHooks = Object.fromEntries( - context.types - .map((name) => context.typeRegistry.getType(name)!) - .filter((type) => !!type.excludeOnUpgrade) - .map((type) => [type.name, type.excludeOnUpgrade!]) - ); - const outdatedDocumentsQuery = getOutdatedDocumentsQuery({ types }); - const transformRawDocs = createDocumentTransformFn({ - serializer: context.serializer, - documentMigrator: context.documentMigrator, - }); return { ...state, - logs, - excludeOnUpgradeQuery: excludeUnusedTypesQuery, - excludeFromUpgradeFilterHooks: excludeFilterHooks, - outdatedDocumentsQuery, - transformRawDocs, + ...commonState, controlState: 'SET_DOC_MIGRATION_STARTED', }; // app version and index mapping version are the same. diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.mocks.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.mocks.ts index 89c513fa2a66d..c6a03c7ee6860 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.mocks.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.mocks.ts @@ -11,6 +11,7 @@ export const checkVersionCompatibilityMock = jest.fn(); export const buildIndexMappingsMock = jest.fn(); export const generateAdditiveMappingDiffMock = jest.fn(); export const getAliasActionsMock = jest.fn(); +export const checkIndexCurrentAlgorithmMock = jest.fn(); jest.doMock('../../utils', () => { const realModule = jest.requireActual('../../utils'); @@ -21,5 +22,16 @@ jest.doMock('../../utils', () => { buildIndexMappings: buildIndexMappingsMock, generateAdditiveMappingDiff: generateAdditiveMappingDiffMock, getAliasActions: getAliasActionsMock, + checkIndexCurrentAlgorithm: checkIndexCurrentAlgorithmMock, + }; +}); + +export const getAliasesMock = jest.fn(); + +jest.doMock('../../../model/helpers', () => { + const realModule = jest.requireActual('../../../model/helpers'); + return { + ...realModule, + getAliases: getAliasesMock, }; }); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts index 925e263a26d3f..45c4d3181fce5 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.test.ts @@ -12,6 +12,8 @@ import { buildIndexMappingsMock, generateAdditiveMappingDiffMock, getAliasActionsMock, + checkIndexCurrentAlgorithmMock, + getAliasesMock, } from './init.test.mocks'; import * as Either from 'fp-ts/lib/Either'; import { FetchIndexResponse } from '../../../actions'; @@ -52,6 +54,9 @@ describe('Stage: init', () => { }); generateAdditiveMappingDiffMock.mockReset().mockReturnValue({}); getAliasActionsMock.mockReset().mockReturnValue([]); + checkIndexCurrentAlgorithmMock.mockReset().mockReturnValue('zdt'); + getAliasesMock.mockReset().mockReturnValue(Either.right({})); + buildIndexMappingsMock.mockReset().mockReturnValue({}); context = createContextMock({ indexPrefix: '.kibana', types: ['foo', 'bar'] }); context.typeRegistry.registerType({ @@ -87,10 +92,17 @@ describe('Stage: init', () => { const fetchIndexResponse = createResponse(); const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const aliases = { '.foo': '.bar' }; + getAliasesMock.mockReturnValue(Either.right(aliases)); + init(state, res, context); expect(getCurrentIndexMock).toHaveBeenCalledTimes(1); - expect(getCurrentIndexMock).toHaveBeenCalledWith(fetchIndexResponse, context.indexPrefix); + expect(getCurrentIndexMock).toHaveBeenCalledWith({ + indices: Object.keys(fetchIndexResponse), + indexPrefix: context.indexPrefix, + aliases, + }); }); it('calls checkVersionCompatibility with the correct parameters', () => { @@ -109,232 +121,364 @@ describe('Stage: init', () => { }); }); - describe('when getCurrentIndex returns undefined', () => { + describe('when checkIndexCurrentAlgorithm returns `unknown`', () => { beforeEach(() => { - getCurrentIndexMock.mockReturnValue(undefined); + checkIndexCurrentAlgorithmMock.mockReset().mockReturnValue('unknown'); }); - it('calls buildIndexMappings with the correct parameters', () => { + it('adds a log entry about the algo check', () => { const state = createState(); - const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); - init(state, res, context); + const newState = init(state, res, context); - expect(buildIndexMappingsMock).toHaveBeenCalledTimes(1); - expect(buildIndexMappingsMock).toHaveBeenCalledWith({ - types: ['foo', 'bar'].map((type) => context.typeRegistry.getType(type)), - }); + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: current algo check result: unknown` + ); }); - it('INIT -> CREATE_TARGET_INDEX', () => { + it('INIT -> FATAL', () => { const state = createState(); const fetchIndexResponse = createResponse(); const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); - const mockMappings = { properties: { someMappings: 'string' } }; - buildIndexMappingsMock.mockReturnValue(mockMappings); - const newState = init(state, res, context); expect(newState).toEqual( expect.objectContaining({ - controlState: 'CREATE_TARGET_INDEX', - currentIndex: '.kibana_1', - indexMappings: mockMappings, + controlState: 'FATAL', + reason: 'Cannot identify algorithm used for index .kibana_1', }) ); }); }); - describe('when checkVersionCompatibility returns `greater`', () => { - it('calls generateAdditiveMappingDiff with the correct parameters', () => { - const state = createState(); - const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + describe('when checkIndexCurrentAlgorithm returns `v2-incompatible`', () => { + beforeEach(() => { + checkIndexCurrentAlgorithmMock.mockReset().mockReturnValue('v2-incompatible'); + }); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'greater', - }); + it('adds a log entry about the algo check', () => { + const state = createState(); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); - init(state, res, context); + const newState = init(state, res, context); - expect(generateAdditiveMappingDiffMock).toHaveBeenCalledTimes(1); - expect(generateAdditiveMappingDiffMock).toHaveBeenCalledWith({ - types: ['foo', 'bar'].map((type) => context.typeRegistry.getType(type)), - meta: fetchIndexResponse[currentIndex].mappings._meta, - deletedTypes: context.deletedTypes, - }); + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: current algo check result: v2-incompatible` + ); }); - it('INIT -> UPDATE_INDEX_MAPPINGS', () => { + it('INIT -> FATAL', () => { const state = createState(); const fetchIndexResponse = createResponse(); const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'greater', - }); - generateAdditiveMappingDiffMock.mockReturnValue({ someToken: {} }); - const newState = init(state, res, context); expect(newState).toEqual( expect.objectContaining({ - controlState: 'UPDATE_INDEX_MAPPINGS', - currentIndex, - previousMappings: fetchIndexResponse[currentIndex].mappings, - additiveMappingChanges: { someToken: {} }, - skipDocumentMigration: false, + controlState: 'FATAL', + reason: 'Index .kibana_1 is using an incompatible version of the v2 algorithm', }) ); }); + }); + + describe('when checkIndexCurrentAlgorithm returns `v2-compatible`', () => { + beforeEach(() => { + checkIndexCurrentAlgorithmMock.mockReset().mockReturnValue('v2-compatible'); + buildIndexMappingsMock.mockReturnValue({}); + }); - it('adds a log entry about the version check', () => { + it('adds a log entry about the algo check', () => { const state = createState(); const res: StateActionResponse<'INIT'> = Either.right(createResponse()); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'greater', + init(state, res, context); + + expect(buildIndexMappingsMock).toHaveBeenCalledTimes(1); + expect(buildIndexMappingsMock).toHaveBeenLastCalledWith({ + types: ['foo', 'bar'].map((type) => context.typeRegistry.getType(type)), }); + }); + + it('calls buildIndexMappings with the correct parameters', () => { + const state = createState(); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); const newState = init(state, res, context); - expect(newState.logs.map((entry) => entry.message)).toEqual([ - `INIT: mapping version check result: greater`, - ]); + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: current algo check result: v2-compatible` + ); }); - }); - describe('when checkVersionCompatibility returns `equal`', () => { - it('INIT -> UPDATE_ALIASES if alias actions are not empty', () => { + it('INIT -> UPDATE_INDEX_MAPPINGS', () => { const state = createState(); const fetchIndexResponse = createResponse(); const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'equal', - }); - getAliasActionsMock.mockReturnValue([{ add: { index: '.kibana_1', alias: '.kibana' } }]); + const mockMappings = { properties: { someMappings: 'string' } }; + buildIndexMappingsMock.mockReturnValue(mockMappings); const newState = init(state, res, context); expect(newState).toEqual( expect.objectContaining({ - controlState: 'UPDATE_ALIASES', + controlState: 'UPDATE_INDEX_MAPPINGS', currentIndex, previousMappings: fetchIndexResponse[currentIndex].mappings, + additiveMappingChanges: mockMappings.properties, skipDocumentMigration: false, }) ); }); + }); - it('INIT -> INDEX_STATE_UPDATE_DONE if alias actions are empty', () => { - const state = createState(); - const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + describe('when checkIndexCurrentAlgorithm returns `zdt`', () => { + beforeEach(() => { + checkIndexCurrentAlgorithmMock.mockReset().mockReturnValue('zdt'); + }); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'equal', - }); - getAliasActionsMock.mockReturnValue([]); + it('adds a log entry about the algo check', () => { + const state = createState(); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); const newState = init(state, res, context); - expect(newState).toEqual( - expect.objectContaining({ - controlState: 'INDEX_STATE_UPDATE_DONE', - currentIndex, - previousMappings: fetchIndexResponse[currentIndex].mappings, - skipDocumentMigration: false, - }) + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: current algo check result: zdt` ); }); - it('adds a log entry about the version check', () => { - const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + describe('when getCurrentIndex returns undefined', () => { + beforeEach(() => { + getCurrentIndexMock.mockReturnValue(undefined); + }); + + it('calls buildIndexMappings with the correct parameters', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'equal', + init(state, res, context); + + expect(buildIndexMappingsMock).toHaveBeenCalledTimes(1); + expect(buildIndexMappingsMock).toHaveBeenCalledWith({ + types: ['foo', 'bar'].map((type) => context.typeRegistry.getType(type)), + }); }); - const newState = init(state, res, context); + it('INIT -> CREATE_TARGET_INDEX', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + + const mockMappings = { properties: { someMappings: 'string' } }; + buildIndexMappingsMock.mockReturnValue(mockMappings); + + const newState = init(state, res, context); - expect(newState.logs.map((entry) => entry.message)).toEqual([ - `INIT: mapping version check result: equal`, - ]); + expect(newState).toEqual( + expect.objectContaining({ + controlState: 'CREATE_TARGET_INDEX', + currentIndex: '.kibana_1', + indexMappings: mockMappings, + }) + ); + }); }); - }); - describe('when checkVersionCompatibility returns `lesser`', () => { - it('INIT -> INDEX_STATE_UPDATE_DONE', () => { - const state = createState(); - const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + describe('when checkVersionCompatibility returns `greater`', () => { + it('calls generateAdditiveMappingDiff with the correct parameters', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'greater', + }); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'lesser', + init(state, res, context); + + expect(generateAdditiveMappingDiffMock).toHaveBeenCalledTimes(1); + expect(generateAdditiveMappingDiffMock).toHaveBeenCalledWith({ + types: ['foo', 'bar'].map((type) => context.typeRegistry.getType(type)), + meta: fetchIndexResponse[currentIndex].mappings._meta, + deletedTypes: context.deletedTypes, + }); }); - const newState = init(state, res, context); + it('INIT -> UPDATE_INDEX_MAPPINGS', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'greater', + }); + generateAdditiveMappingDiffMock.mockReturnValue({ someToken: {} }); + + const newState = init(state, res, context); + + expect(newState).toEqual( + expect.objectContaining({ + controlState: 'UPDATE_INDEX_MAPPINGS', + currentIndex, + previousMappings: fetchIndexResponse[currentIndex].mappings, + additiveMappingChanges: { someToken: {} }, + skipDocumentMigration: false, + }) + ); + }); - expect(newState).toEqual( - expect.objectContaining({ - controlState: 'INDEX_STATE_UPDATE_DONE', - }) - ); + it('adds a log entry about the version check', () => { + const state = createState(); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'greater', + }); + + const newState = init(state, res, context); + + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: mapping version check result: greater` + ); + }); }); - it('adds a log entry about the version check', () => { - const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + describe('when checkVersionCompatibility returns `equal`', () => { + it('INIT -> UPDATE_ALIASES if alias actions are not empty', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'equal', + }); + getAliasActionsMock.mockReturnValue([{ add: { index: '.kibana_1', alias: '.kibana' } }]); + + const newState = init(state, res, context); + + expect(newState).toEqual( + expect.objectContaining({ + controlState: 'UPDATE_ALIASES', + currentIndex, + previousMappings: fetchIndexResponse[currentIndex].mappings, + skipDocumentMigration: false, + }) + ); + }); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'lesser', + it('INIT -> INDEX_STATE_UPDATE_DONE if alias actions are empty', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'equal', + }); + getAliasActionsMock.mockReturnValue([]); + + const newState = init(state, res, context); + + expect(newState).toEqual( + expect.objectContaining({ + controlState: 'INDEX_STATE_UPDATE_DONE', + currentIndex, + previousMappings: fetchIndexResponse[currentIndex].mappings, + skipDocumentMigration: false, + }) + ); }); - const newState = init(state, res, context); + it('adds a log entry about the version check', () => { + const state = createState(); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'equal', + }); - expect(newState.logs.map((entry) => entry.message)).toEqual([ - `INIT: mapping version check result: lesser`, - ]); + const newState = init(state, res, context); + + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: mapping version check result: equal` + ); + }); }); - }); - describe('when checkVersionCompatibility returns `conflict`', () => { - it('INIT -> FATAL', () => { - const state = createState(); - const fetchIndexResponse = createResponse(); - const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + describe('when checkVersionCompatibility returns `lesser`', () => { + it('INIT -> INDEX_STATE_UPDATE_DONE', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'lesser', + }); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'conflict', + const newState = init(state, res, context); + + expect(newState).toEqual( + expect.objectContaining({ + controlState: 'INDEX_STATE_UPDATE_DONE', + }) + ); }); - const newState = init(state, res, context); + it('adds a log entry about the version check', () => { + const state = createState(); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); - expect(newState).toEqual( - expect.objectContaining({ - controlState: 'FATAL', - reason: 'Model version conflict: inconsistent higher/lower versions', - }) - ); + checkVersionCompatibilityMock.mockReturnValue({ + status: 'lesser', + }); + + const newState = init(state, res, context); + + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: mapping version check result: lesser` + ); + }); }); - it('adds a log entry about the version check', () => { - const state = createState(); - const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + describe('when checkVersionCompatibility returns `conflict`', () => { + it('INIT -> FATAL', () => { + const state = createState(); + const fetchIndexResponse = createResponse(); + const res: StateActionResponse<'INIT'> = Either.right(fetchIndexResponse); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'conflict', + }); + + const newState = init(state, res, context); - checkVersionCompatibilityMock.mockReturnValue({ - status: 'conflict', + expect(newState).toEqual( + expect.objectContaining({ + controlState: 'FATAL', + reason: 'Model version conflict: inconsistent higher/lower versions', + }) + ); }); - const newState = init(state, res, context); + it('adds a log entry about the version check', () => { + const state = createState(); + const res: StateActionResponse<'INIT'> = Either.right(createResponse()); + + checkVersionCompatibilityMock.mockReturnValue({ + status: 'conflict', + }); - expect(newState.logs.map((entry) => entry.message)).toEqual([ - `INIT: mapping version check result: conflict`, - ]); + const newState = init(state, res, context); + + expect(newState.logs.map((entry) => entry.message)).toContain( + `INIT: mapping version check result: conflict` + ); + }); }); }); }); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts index 57f63fe403866..96fdf7dac4a95 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/model/stages/init.ts @@ -12,12 +12,15 @@ import { delayRetryState } from '../../../model/retry_state'; import { throwBadResponse } from '../../../model/helpers'; import type { MigrationLog } from '../../../types'; import { isTypeof } from '../../actions'; +import { getAliases } from '../../../model/helpers'; import { getCurrentIndex, checkVersionCompatibility, buildIndexMappings, getAliasActions, generateAdditiveMappingDiff, + checkIndexCurrentAlgorithm, + removePropertiesFromV2, } from '../../utils'; import type { ModelStage } from '../types'; @@ -43,9 +46,25 @@ export const init: ModelStage< const logs: MigrationLog[] = [...state.logs]; const indices = res.right; - const currentIndex = getCurrentIndex(indices, context.indexPrefix); + const aliasesRes = getAliases(indices); + if (Either.isLeft(aliasesRes)) { + return { + ...state, + controlState: 'FATAL', + reason: `The ${ + aliasesRes.left.alias + } alias is pointing to multiple indices: ${aliasesRes.left.indices.join(',')}.`, + }; + } + const aliasMap = aliasesRes.right; - // No indices were found, likely because it is the first time Kibana boots. + const currentIndex = getCurrentIndex({ + indices: Object.keys(indices), + aliases: aliasMap, + indexPrefix: context.indexPrefix, + }); + + // No indices were found, likely because it is a fresh cluster. // In that case, we just create the index. if (!currentIndex) { return { @@ -60,37 +79,82 @@ export const init: ModelStage< // Index was found. This is the standard scenario, we check the model versions // compatibility before going further. const currentMappings = indices[currentIndex].mappings; - const versionCheck = checkVersionCompatibility({ - mappings: currentMappings, - types, - source: 'mappingVersions', - deletedTypes: context.deletedTypes, - }); + + // Index is already present, so we check which algo was last used on it + const currentAlgo = checkIndexCurrentAlgorithm(currentMappings); logs.push({ level: 'info', - message: `INIT: mapping version check result: ${versionCheck.status}`, + message: `INIT: current algo check result: ${currentAlgo}`, }); - const aliases = Object.keys(indices[currentIndex].aliases); + // incompatible (pre 8.8/index-split https://github.com/elastic/kibana/pull/154888) v2 algo => we terminate + if (currentAlgo === 'v2-incompatible') { + return { + ...state, + logs, + controlState: 'FATAL', + reason: `Index ${currentIndex} is using an incompatible version of the v2 algorithm`, + }; + } + // unknown algo => we terminate + if (currentAlgo === 'unknown') { + return { + ...state, + logs, + controlState: 'FATAL', + reason: `Cannot identify algorithm used for index ${currentIndex}`, + }; + } + + const existingAliases = Object.keys(indices[currentIndex].aliases); const aliasActions = getAliasActions({ - existingAliases: aliases, + existingAliases, currentIndex, indexPrefix: context.indexPrefix, kibanaVersion: context.kibanaVersion, }); // cloning as we may be mutating it in later stages. - const currentIndexMeta = cloneDeep(currentMappings._meta!); + let currentIndexMeta = cloneDeep(currentMappings._meta!); + if (currentAlgo === 'v2-compatible') { + currentIndexMeta = removePropertiesFromV2(currentIndexMeta); + } const commonState = { logs, currentIndex, currentIndexMeta, - aliases, + aliases: existingAliases, aliasActions, previousMappings: currentMappings, + previousAlgorithm: currentAlgo === 'v2-compatible' ? ('v2' as const) : ('zdt' as const), }; + // compatible (8.8+) v2 algo => we jump to update index mapping + if (currentAlgo === 'v2-compatible') { + const indexMappings = buildIndexMappings({ types }); + return { + ...state, + controlState: 'UPDATE_INDEX_MAPPINGS', + ...commonState, + additiveMappingChanges: indexMappings.properties, + }; + } + + // Index was found and is already using ZDT algo. This is the standard scenario. + // We check the model versions compatibility before going further. + const versionCheck = checkVersionCompatibility({ + mappings: currentMappings, + types, + source: 'mappingVersions', + deletedTypes: context.deletedTypes, + }); + + logs.push({ + level: 'info', + message: `INIT: mapping version check result: ${versionCheck.status}`, + }); + switch (versionCheck.status) { // app version is greater than the index mapping version. // scenario of an upgrade: we need to update the mappings diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/state/types.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/state/types.ts index 94fb5a18b2927..7a1768745982e 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/state/types.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/state/types.ts @@ -17,7 +17,7 @@ import type { MigrationLog, Progress, TransformRawDocs } from '../../types'; import type { ControlState } from '../../state_action_machine'; import type { BulkOperationBatch } from '../../model/create_batches'; import type { AliasAction } from '../../actions'; -import { TransformErrorObjects } from '../../core'; +import type { TransformErrorObjects } from '../../core'; export interface BaseState extends ControlState { readonly retryCount: number; @@ -65,6 +65,11 @@ export interface PostInitState extends BaseState { * All operations updating this field will update in the state accordingly. */ readonly currentIndexMeta: IndexMappingMeta; + /** + * The previous algorithm that was last used to migrate this index. + * Used for v2->zdt state conversion. + */ + readonly previousAlgorithm: 'zdt' | 'v2'; } /** diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/context.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/context.ts index 89aa1a13fa928..69722cb9652e8 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/context.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/context.ts @@ -31,6 +31,7 @@ export const createMigrationConfigMock = ( algorithm: 'zdt', batchSize: 1000, maxBatchSizeBytes: new ByteSizeValue(1e8), + maxReadBatchSizeBytes: new ByteSizeValue(1e6), pollInterval: 0, scrollDuration: '0s', skip: false, diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/state.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/state.ts index 6f1ce7fd1c0c2..0eed35bc10dad 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/state.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/test_helpers/state.ts @@ -19,6 +19,7 @@ export const createPostInitState = (): PostInitState => ({ previousMappings: { properties: {} }, currentIndexMeta: {}, skipDocumentMigration: false, + previousAlgorithm: 'zdt', }); export const createPostDocInitState = (): PostDocInitState => ({ diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/check_index_algorithm.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/check_index_algorithm.test.ts new file mode 100644 index 0000000000000..b453cefe309a1 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/check_index_algorithm.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { IndexMapping } from '@kbn/core-saved-objects-base-server-internal'; +import { checkIndexCurrentAlgorithm } from './check_index_algorithm'; + +describe('checkIndexCurrentAlgorithm', () => { + it('returns `unknown` if _meta is not present on the mapping', () => { + const mapping: IndexMapping = { + properties: {}, + }; + + expect(checkIndexCurrentAlgorithm(mapping)).toEqual('unknown'); + }); + + it('returns `unknown` if both v2 and zdt metas are present', () => { + const mapping: IndexMapping = { + properties: {}, + _meta: { + migrationMappingPropertyHashes: { + foo: 'someHash', + }, + docVersions: { + foo: '8.8.0', + }, + }, + }; + + expect(checkIndexCurrentAlgorithm(mapping)).toEqual('unknown'); + }); + + it('returns `zdt` if only zdt metas are present', () => { + const mapping: IndexMapping = { + properties: {}, + _meta: { + docVersions: { + foo: '8.8.0', + }, + mappingVersions: { + foo: '8.8.0', + }, + }, + }; + + expect(checkIndexCurrentAlgorithm(mapping)).toEqual('zdt'); + }); + + it('returns `v2-incompatible` if v2 hashes are present but not indexTypesMap', () => { + const mapping: IndexMapping = { + properties: {}, + _meta: { + migrationMappingPropertyHashes: { + foo: 'someHash', + }, + }, + }; + + expect(checkIndexCurrentAlgorithm(mapping)).toEqual('v2-incompatible'); + }); + + it('returns `v2-compatible` if v2 hashes and indexTypesMap are present', () => { + const mapping: IndexMapping = { + properties: {}, + _meta: { + migrationMappingPropertyHashes: { + foo: 'someHash', + }, + indexTypesMap: { + '.kibana': ['foo'], + }, + }, + }; + + expect(checkIndexCurrentAlgorithm(mapping)).toEqual('v2-compatible'); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/check_index_algorithm.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/check_index_algorithm.ts new file mode 100644 index 0000000000000..7e06a2a6c06a9 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/check_index_algorithm.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { IndexMapping } from '@kbn/core-saved-objects-base-server-internal'; + +/** + * The list of values returned by `checkIndexCurrentAlgorithm`. + * + * - `zdt` + * - `v2-compatible` + * - `v2-incompatible` + * - `unknown` + */ +export type CheckCurrentAlgorithmResult = 'zdt' | 'v2-compatible' | 'v2-incompatible' | 'unknown'; + +export const checkIndexCurrentAlgorithm = ( + indexMapping: IndexMapping +): CheckCurrentAlgorithmResult => { + const meta = indexMapping._meta; + if (!meta) { + return 'unknown'; + } + + const hasV2Meta = !!meta.migrationMappingPropertyHashes; + const hasZDTMeta = !!meta.docVersions || !!meta.mappingVersions; + + if (hasV2Meta && hasZDTMeta) { + return 'unknown'; + } + if (hasV2Meta) { + const isCompatible = !!meta.indexTypesMap; + return isCompatible ? 'v2-compatible' : 'v2-incompatible'; + } + if (hasZDTMeta) { + return 'zdt'; + } + return 'unknown'; +}; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.test.ts index d6db500dca633..d3ff2b4d90e90 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.test.ts @@ -7,42 +7,79 @@ */ import { getCurrentIndex } from './get_current_index'; -import type { FetchIndexResponse } from '../../actions'; describe('getCurrentIndex', () => { - const createIndexResponse = (...indexNames: string[]): FetchIndexResponse => { - return indexNames.reduce((resp, indexName) => { - resp[indexName] = { aliases: {}, mappings: { properties: {} }, settings: {} }; - return resp; - }, {}); - }; + it('returns the target of the alias matching the index prefix if present in the list', () => { + expect( + getCurrentIndex({ + indices: ['.kibana_1', '.kibana_2', '.kibana_8.8.0_001'], + indexPrefix: '.kibana', + aliases: { + '.kibana': '.kibana_8.8.0_001', + }, + }) + ).toEqual('.kibana_8.8.0_001'); + }); + + it('ignores the target of the alias matching the index prefix if not present in the list', () => { + expect( + getCurrentIndex({ + indices: ['.kibana_1'], + indexPrefix: '.kibana', + aliases: { + '.kibana': '.foobar_9000', + }, + }) + ).toEqual('.kibana_1'); + }); it('returns the highest numbered index matching the index prefix', () => { - const resp = createIndexResponse('.kibana_1', '.kibana_2'); - expect(getCurrentIndex(resp, '.kibana')).toEqual('.kibana_2'); + expect( + getCurrentIndex({ + indices: ['.kibana_1', '.kibana_2'], + indexPrefix: '.kibana', + aliases: {}, + }) + ).toEqual('.kibana_2'); }); it('ignores other indices', () => { - const resp = createIndexResponse('.kibana_1', '.kibana_2', '.foo_3'); - expect(getCurrentIndex(resp, '.kibana')).toEqual('.kibana_2'); + expect( + getCurrentIndex({ + indices: ['.kibana_1', '.kibana_2', '.foo_3'], + indexPrefix: '.kibana', + aliases: {}, + }) + ).toEqual('.kibana_2'); }); it('ignores other indices including the prefix', () => { - const resp = createIndexResponse('.kibana_1', '.kibana_2', '.kibana_task_manager_3'); - expect(getCurrentIndex(resp, '.kibana')).toEqual('.kibana_2'); + expect( + getCurrentIndex({ + indices: ['.kibana_1', '.kibana_2', '.kibana_task_manager_3'], + indexPrefix: '.kibana', + aliases: {}, + }) + ).toEqual('.kibana_2'); }); it('ignores other indices including a subpart of the prefix', () => { - const resp = createIndexResponse( - '.kibana_3', - '.kibana_task_manager_1', - '.kibana_task_manager_2' - ); - expect(getCurrentIndex(resp, '.kibana_task_manager')).toEqual('.kibana_task_manager_2'); + expect( + getCurrentIndex({ + indices: ['.kibana_3', '.kibana_task_manager_1', '.kibana_task_manager_2'], + indexPrefix: '.kibana_task_manager', + aliases: {}, + }) + ).toEqual('.kibana_task_manager_2'); }); it('returns undefined if no indices match', () => { - const resp = createIndexResponse('.kibana_task_manager_1', '.kibana_task_manager_2'); - expect(getCurrentIndex(resp, '.kibana')).toBeUndefined(); + expect( + getCurrentIndex({ + indices: ['.kibana_task_manager_1', '.kibana_task_manager_2'], + indexPrefix: '.kibana', + aliases: {}, + }) + ).toBeUndefined(); }); }); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.ts index 59eea5c550804..dd0d2c706a4bd 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/get_current_index.ts @@ -7,16 +7,26 @@ */ import { escapeRegExp } from 'lodash'; -import type { FetchIndexResponse } from '../../actions'; +import type { Aliases } from '../../model/helpers'; + +export const getCurrentIndex = ({ + indices, + aliases, + indexPrefix, +}: { + indices: string[]; + aliases: Aliases; + indexPrefix: string; +}): string | undefined => { + // if there is already a current alias pointing to an index, we reuse the index. + if (aliases[indexPrefix] && indices.includes(aliases[indexPrefix]!)) { + return aliases[indexPrefix]; + } -export const getCurrentIndex = ( - indices: FetchIndexResponse, - indexPrefix: string -): string | undefined => { const matcher = new RegExp(`^${escapeRegExp(indexPrefix)}[_](?\\d+)$`); let lastCount = -1; - Object.keys(indices).forEach((indexName) => { + indices.forEach((indexName) => { const match = matcher.exec(indexName); if (match && match.groups?.counter) { const suffix = parseInt(match.groups.counter, 10); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/index.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/index.ts index 76c66a9fc9bd0..b1e68c6947823 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/index.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/index.ts @@ -18,4 +18,9 @@ export { setMetaMappingMigrationComplete, setMetaDocMigrationStarted, setMetaDocMigrationComplete, + removePropertiesFromV2, } from './update_index_meta'; +export { + checkIndexCurrentAlgorithm, + type CheckCurrentAlgorithmResult, +} from './check_index_algorithm'; diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.test.ts index da9654400bf6f..55d4b552c3b03 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.test.ts @@ -14,6 +14,7 @@ import { setMetaDocMigrationStarted, setMetaDocMigrationComplete, setMetaMappingMigrationComplete, + removePropertiesFromV2, } from './update_index_meta'; const getDefaultMeta = (): IndexMappingMeta => ({ @@ -80,3 +81,20 @@ describe('setMetaDocMigrationComplete', () => { }); }); }); + +describe('removePropertiesFromV2', () => { + it('removes meta properties used by the v2 algorithm', () => { + const meta: IndexMappingMeta = { + ...getDefaultMeta(), + indexTypesMap: { + '.kibana': ['foo'], + }, + migrationMappingPropertyHashes: { + foo: 'someHash', + }, + }; + + const output = removePropertiesFromV2(meta); + expect(output).toEqual(getDefaultMeta()); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.ts index 2d06f5adcb378..e2b0ca750e673 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/zdt/utils/update_index_meta.ts @@ -56,3 +56,10 @@ export const setMetaDocMigrationComplete = ({ }, }; }; + +export const removePropertiesFromV2 = (meta: IndexMappingMeta): IndexMappingMeta => { + const cleaned = { ...meta }; + delete cleaned.indexTypesMap; + delete cleaned.migrationMappingPropertyHashes; + return cleaned; +}; diff --git a/src/core/server/integration_tests/saved_objects/migrations/fixtures/zdt_base.fixtures.ts b/src/core/server/integration_tests/saved_objects/migrations/fixtures/zdt_base.fixtures.ts index 09a8cfe329079..525684170e54c 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/fixtures/zdt_base.fixtures.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/fixtures/zdt_base.fixtures.ts @@ -8,19 +8,23 @@ import { SavedObjectsModelVersion, SavedObjectMigrationFn } from '@kbn/core-saved-objects-server'; import { createType } from '../test_utils'; -import { type KibanaMigratorTestKitParams } from '../kibana_migrator_test_kit'; +import { type KibanaMigratorTestKitParams, currentVersion } from '../kibana_migrator_test_kit'; export const getBaseMigratorParams = ({ + migrationAlgorithm = 'zdt', // default to true here as most tests need to run the full migration runOnNonMigratorNodes = true, + kibanaVersion = currentVersion, }: { runOnNonMigratorNodes?: boolean; + migrationAlgorithm?: 'v2' | 'zdt'; + kibanaVersion?: string; } = {}): KibanaMigratorTestKitParams => ({ kibanaIndex: '.kibana', - kibanaVersion: '8.8.0', + kibanaVersion, settings: { migrations: { - algorithm: 'zdt', + algorithm: migrationAlgorithm, zdt: { metaPickupSyncDelaySec: 5, runOnNonMigratorNodes, diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts index 8bf85d5c04c66..38d4075f9516c 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts @@ -22,6 +22,7 @@ import { type OpenPitResponse, reindex, readWithPit, + type EsResponseTooLargeError, type ReadWithPit, setWriteBlock, updateAliases, @@ -87,6 +88,7 @@ describe('migration actions', () => { { _source: { title: 'doc 3' } }, { _source: { title: 'saved object 4', type: 'another_unused_type' } }, { _source: { title: 'f-agent-event 5', type: 'f_agent_event' } }, + { _source: { title: new Array(1000).fill('a').join(), type: 'large' } }, // "large" saved object ] as unknown as SavedObjectsRawDoc[]; await bulkOverwriteTransformedDocuments({ client, @@ -727,6 +729,7 @@ describe('migration actions', () => { expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) .toMatchInlineSnapshot(` Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a", "doc 1", "doc 2", "doc 3", @@ -763,6 +766,7 @@ describe('migration actions', () => { expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) .toMatchInlineSnapshot(` Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a", "doc 1", "doc 2", "doc 3", @@ -792,6 +796,7 @@ describe('migration actions', () => { expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) .toMatchInlineSnapshot(` Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a_updated", "doc 1_updated", "doc 2_updated", "doc 3_updated", @@ -843,6 +848,7 @@ describe('migration actions', () => { expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) .toMatchInlineSnapshot(` Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a_updated", "doc 1_updated", "doc 2_updated", "doc 3_updated", @@ -893,6 +899,7 @@ describe('migration actions', () => { expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) .toMatchInlineSnapshot(` Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a_updated", "doc 1", "doc 2", "doc 3_updated", @@ -1119,7 +1126,7 @@ describe('migration actions', () => { }); const docsResponse = (await readWithPitTask()) as Either.Right; - await expect(docsResponse.right.outdatedDocuments.length).toBe(5); + await expect(docsResponse.right.outdatedDocuments.length).toBe(6); }); it('requests the batchSize of documents from an index', async () => { @@ -1170,6 +1177,7 @@ describe('migration actions', () => { expect(docsResponse.right.outdatedDocuments.map((doc) => doc._source.title).sort()) .toMatchInlineSnapshot(` Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a", "doc 1", "doc 2", "doc 3", @@ -1256,6 +1264,36 @@ describe('migration actions', () => { ); }); + it('returns a left es_response_too_large error when a read batch exceeds the maxResponseSize', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + let readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { match_all: {} }, + batchSize: 1, // small batch size so we don't exceed the maxResponseSize + searchAfter: undefined, + maxResponseSizeBytes: 500, // set a small size to force the error + }); + const rightResponse = (await readWithPitTask()) as Either.Right; + + await expect(Either.isRight(rightResponse)).toBe(true); + + readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { match_all: {} }, + batchSize: 10, // a bigger batch will exceed the maxResponseSize + searchAfter: undefined, + maxResponseSizeBytes: 500, // set a small size to force the error + }); + const leftResponse = (await readWithPitTask()) as Either.Left; + + expect(leftResponse.left.type).toBe('es_response_too_large'); + expect(leftResponse.left.contentLength).toBe(3184); + }); + it('rejects if PIT does not exist', async () => { const readWithPitTask = readWithPit({ client, diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/dot_kibana_split.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/dot_kibana_split.test.ts index 537655cf5450c..a5a10cd05e574 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/dot_kibana_split.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/dot_kibana_split.test.ts @@ -60,6 +60,7 @@ describe('split .kibana index into multiple system indices', () => { beforeAll(async () => { esServer = await startElasticsearch({ dataArchive: Path.join(__dirname, '..', 'archives', '7.3.0_xpack_sample_saved_objects.zip'), + timeout: 60000, }); }); diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/read_batch_size.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/read_batch_size.test.ts new file mode 100644 index 0000000000000..0fce643975c53 --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/read_batch_size.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright 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 Path from 'path'; +import fs from 'fs/promises'; +import { Root } from '@kbn/core-root-server-internal'; +import { + createRootWithCorePlugins, + type TestElasticsearchUtils, +} from '@kbn/core-test-helpers-kbn-server'; +import { delay } from '../test_utils'; +import { startElasticsearch } from '../kibana_migrator_test_kit'; + +const logFilePath = Path.join(__dirname, 'read_batch_size.log'); + +describe('migration v2 - read batch size', () => { + let esServer: TestElasticsearchUtils; + let root: Root; + let logs: string; + + beforeEach(async () => { + esServer = await startElasticsearch({ + dataArchive: Path.join(__dirname, '..', 'archives', '8.4.0_with_sample_data_logs.zip'), + }); + await fs.unlink(logFilePath).catch(() => {}); + }); + + afterEach(async () => { + await root?.shutdown(); + await esServer?.stop(); + await delay(10); + }); + + it('reduces the read batchSize in half if a batch exceeds maxReadBatchSizeBytes', async () => { + root = createRoot({ maxReadBatchSizeBytes: 15000 }); + await root.preboot(); + await root.setup(); + await root.start(); + + // Check for migration steps present in the logs + logs = await fs.readFile(logFilePath, 'utf-8'); + + expect(logs).toMatch( + /Read a batch with a response content length of \d+ bytes which exceeds migrations\.maxReadBatchSizeBytes, retrying by reducing the batch size in half to 15/ + ); + expect(logs).toMatch('[.kibana] Migration completed'); + }); + + it('does not reduce the read batchSize in half if no batches exceeded maxReadBatchSizeBytes', async () => { + root = createRoot({ maxReadBatchSizeBytes: 50000 }); + await root.preboot(); + await root.setup(); + await root.start(); + + // Check for migration steps present in the logs + logs = await fs.readFile(logFilePath, 'utf-8'); + + expect(logs).not.toMatch('retrying by reducing the batch size in half to'); + expect(logs).toMatch('[.kibana] Migration completed'); + }); +}); + +function createRoot({ maxReadBatchSizeBytes }: { maxReadBatchSizeBytes?: number }) { + return createRootWithCorePlugins( + { + migrations: { + maxReadBatchSizeBytes, + }, + logging: { + appenders: { + file: { + type: 'file', + fileName: logFilePath, + layout: { + type: 'json', + }, + }, + }, + loggers: [ + { + name: 'root', + level: 'info', + appenders: ['file'], + }, + ], + }, + }, + { + oss: false, + } + ); +} diff --git a/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts b/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts index f354430261c3d..43d5cc746a7e3 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/kibana_migrator_test_kit.ts @@ -87,12 +87,14 @@ export interface KibanaMigratorTestKit { export const startElasticsearch = async ({ basePath, dataArchive, + timeout, }: { basePath?: string; dataArchive?: string; + timeout?: number; } = {}) => { const { startES } = createTestServers({ - adjustTimeout: (t: number) => jest.setTimeout(t), + adjustTimeout: (t: number) => jest.setTimeout(t + (timeout ?? 0)), settings: { es: { license: 'basic', diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_1/create_index.test.ts b/src/core/server/integration_tests/saved_objects/migrations/zdt_1/create_index.test.ts index 5a23889acfc64..784bd6c6e2699 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/zdt_1/create_index.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_1/create_index.test.ts @@ -34,7 +34,7 @@ describe('ZDT upgrades - running on a fresh cluster', () => { const barType = getBarType(); const { runMigrations, client } = await getKibanaMigratorTestKit({ - ...getBaseMigratorParams(), + ...getBaseMigratorParams({ kibanaVersion: '8.8.0' }), logFilePath, types: [fooType, barType], }); diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_1/mapping_version_conflict.test.ts b/src/core/server/integration_tests/saved_objects/migrations/zdt_1/mapping_version_conflict.test.ts index 33738976b6117..7b0658fbd977e 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/zdt_1/mapping_version_conflict.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_1/mapping_version_conflict.test.ts @@ -24,7 +24,7 @@ export const logFilePath = Path.join(__dirname, 'mapping_version_conflict.test.l describe('ZDT upgrades - mapping model version conflict', () => { let esServer: TestElasticsearchUtils['es']; - const baseMigratorParams = getBaseMigratorParams(); + const baseMigratorParams = getBaseMigratorParams({ kibanaVersion: '8.8.0' }); beforeAll(async () => { await fs.unlink(logFilePath).catch(() => {}); diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_1/update_mappings.test.ts b/src/core/server/integration_tests/saved_objects/migrations/zdt_1/update_mappings.test.ts index c329f3e24c16a..c51c712f34452 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/zdt_1/update_mappings.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_1/update_mappings.test.ts @@ -38,7 +38,7 @@ describe('ZDT upgrades - basic mapping update', () => { const fooType = getFooType(); const barType = getBarType(); const { runMigrations } = await getKibanaMigratorTestKit({ - ...getBaseMigratorParams(), + ...getBaseMigratorParams({ kibanaVersion: '8.8.0' }), types: [fooType, barType], }); await runMigrations(); @@ -70,7 +70,7 @@ describe('ZDT upgrades - basic mapping update', () => { }; const { runMigrations, client } = await getKibanaMigratorTestKit({ - ...getBaseMigratorParams(), + ...getBaseMigratorParams({ kibanaVersion: '8.8.0' }), logFilePath, types: [fooType, barType], }); diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_2/jest.integration.config.js b/src/core/server/integration_tests/saved_objects/migrations/zdt_2/jest.integration.config.js new file mode 100644 index 0000000000000..af0a2bd1ac298 --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_2/jest.integration.config.js @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + // TODO replace the line below with + // preset: '@kbn/test/jest_integration_node + // to do so, we must fix all integration tests first + // see https://github.com/elastic/kibana/pull/130255/ + preset: '@kbn/test/jest_integration', + rootDir: '../../../../../../..', + roots: ['/src/core/server/integration_tests/saved_objects/migrations/zdt_2'], + // must override to match all test given there is no `integration_tests` subfolder + testMatch: ['**/*.test.{js,mjs,ts,tsx}'], +}; diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_2/sor_higher_version_docs.test.ts b/src/core/server/integration_tests/saved_objects/migrations/zdt_2/sor_higher_version_docs.test.ts new file mode 100644 index 0000000000000..9469b191ac9d2 --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_2/sor_higher_version_docs.test.ts @@ -0,0 +1,194 @@ +/* + * Copyright 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 { pick, range } from 'lodash'; +import Path from 'path'; +import fs from 'fs/promises'; +import { type TestElasticsearchUtils } from '@kbn/core-test-helpers-kbn-server'; +import '../jest_matchers'; +import { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; +import { SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { getKibanaMigratorTestKit, startElasticsearch } from '../kibana_migrator_test_kit'; +import { delay, createType } from '../test_utils'; +import { getBaseMigratorParams } from '../fixtures/zdt_base.fixtures'; +import { SavedObjectsBulkCreateObject } from '@kbn/core-saved-objects-api-server'; + +export const logFilePath = Path.join(__dirname, 'sor_higher.test.log'); + +describe('Higher version doc conversion', () => { + let esServer: TestElasticsearchUtils['es']; + let repositoryV1: ISavedObjectsRepository; + let repositoryV2: ISavedObjectsRepository; + + const getTestType = ({ includeVersion2 }: { includeVersion2: boolean }) => { + const modelVersions: SavedObjectsModelVersionMap = { + 1: { + changes: [], + schemas: { + forwardCompatibility: (attrs: any) => { + return pick(attrs, 'text', 'bool'); + }, + }, + }, + }; + + if (includeVersion2) { + modelVersions[2] = { + changes: [ + { + type: 'data_backfill', + transform: (document) => { + document.attributes.newField = 'someValue'; + return { document }; + }, + }, + ], + schemas: { + forwardCompatibility: (attrs: any) => { + return pick(attrs, 'text', 'bool', 'newField'); + }, + }, + }; + } + + return createType({ + name: 'test-type', + switchToModelVersionAt: '8.0.0', + modelVersions, + mappings: { + dynamic: false, + properties: { + text: { type: 'text' }, + bool: { type: 'boolean' }, + }, + }, + }); + }; + + const createBaseline = async () => { + const testTypeV1 = getTestType({ includeVersion2: false }); + const testTypeV2 = getTestType({ includeVersion2: true }); + + const { + runMigrations, + savedObjectsRepository: savedObjectsRepositoryV1, + client, + } = await getKibanaMigratorTestKit({ + ...getBaseMigratorParams(), + logFilePath, + types: [testTypeV1], + }); + await runMigrations(); + + const sampleAObjs = range(5).map((number) => ({ + id: `doc-${number}`, + type: 'test-type', + attributes: { + text: `a_${number}`, + bool: true, + }, + })); + + await savedObjectsRepositoryV1.bulkCreate(sampleAObjs, { refresh: 'wait_for' }); + + const { runMigrations: runMigrationsAgain, savedObjectsRepository: savedObjectsRepositoryV2 } = + await getKibanaMigratorTestKit({ + ...getBaseMigratorParams(), + logFilePath, + types: [testTypeV2], + }); + await runMigrationsAgain(); + + // returns the repository for v1 + return { savedObjectsRepositoryV1, savedObjectsRepositoryV2, client }; + }; + + beforeAll(async () => { + await fs.unlink(logFilePath).catch(() => {}); + esServer = await startElasticsearch(); + + const { savedObjectsRepositoryV1: sorV1, savedObjectsRepositoryV2: sorV2 } = + await createBaseline(); + + repositoryV1 = sorV1; + repositoryV2 = sorV2; + }); + + afterAll(async () => { + await esServer?.stop(); + await delay(10); + }); + + describe('#get', () => { + it('returns the documents with the correct shape', async () => { + const docV1 = await repositoryV1.get('test-type', 'doc-1'); + expect(docV1.attributes).toEqual({ + bool: true, + text: 'a_1', + }); + + const docV2 = await repositoryV2.get('test-type', 'doc-1'); + expect(docV2.attributes).toEqual({ + bool: true, + text: 'a_1', + newField: 'someValue', + }); + }); + }); + + describe('#bulkGet', () => { + it('returns the documents with the correct shape', async () => { + const docsV1 = await repositoryV1.bulkGet([{ type: 'test-type', id: 'doc-1' }]); + expect(docsV1.saved_objects[0].attributes).toEqual({ + bool: true, + text: 'a_1', + }); + + const docV2 = await repositoryV2.bulkGet([{ type: 'test-type', id: 'doc-1' }]); + expect(docV2.saved_objects[0].attributes).toEqual({ + bool: true, + text: 'a_1', + newField: 'someValue', + }); + }); + }); + + describe('#resolve', () => { + it('returns the documents with the correct shape', async () => { + const docV1 = await repositoryV1.resolve('test-type', 'doc-1'); + expect(docV1.saved_object.attributes).toEqual({ + bool: true, + text: 'a_1', + }); + + const docV2 = await repositoryV2.resolve('test-type', 'doc-1'); + expect(docV2.saved_object.attributes).toEqual({ + bool: true, + text: 'a_1', + newField: 'someValue', + }); + }); + }); + + describe('#bulkResolve', () => { + it('returns the documents with the correct shape', async () => { + const docsV1 = await repositoryV1.bulkResolve([{ type: 'test-type', id: 'doc-1' }]); + expect(docsV1.resolved_objects[0].saved_object.attributes).toEqual({ + bool: true, + text: 'a_1', + }); + + const docV2 = await repositoryV2.bulkResolve([{ type: 'test-type', id: 'doc-1' }]); + expect(docV2.resolved_objects[0].saved_object.attributes).toEqual({ + bool: true, + text: 'a_1', + newField: 'someValue', + }); + }); + }); +}); diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_2/v2_to_zdt_switch.test.ts b/src/core/server/integration_tests/saved_objects/migrations/zdt_2/v2_to_zdt_switch.test.ts new file mode 100644 index 0000000000000..4e437a5350cdf --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_2/v2_to_zdt_switch.test.ts @@ -0,0 +1,150 @@ +/* + * Copyright 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 Path from 'path'; +import fs from 'fs/promises'; +import { range } from 'lodash'; +import { type TestElasticsearchUtils } from '@kbn/core-test-helpers-kbn-server'; +import { SavedObjectsBulkCreateObject } from '@kbn/core-saved-objects-api-server'; +import { IndexMappingMeta } from '@kbn/core-saved-objects-base-server-internal'; +import '../jest_matchers'; +import { + getKibanaMigratorTestKit, + startElasticsearch, + currentVersion, +} from '../kibana_migrator_test_kit'; +import { delay, parseLogFile } from '../test_utils'; +import { getBaseMigratorParams, getSampleAType } from '../fixtures/zdt_base.fixtures'; + +export const logFilePath = Path.join(__dirname, 'v2_to_zdt_switch.test.log'); + +const v2IndexName = `.kibana_${currentVersion}_001`; + +describe('ZDT upgrades - switching from v2 algorithm', () => { + let esServer: TestElasticsearchUtils['es']; + + beforeEach(async () => { + await fs.unlink(logFilePath).catch(() => {}); + esServer = await startElasticsearch(); + }); + + afterEach(async () => { + await esServer?.stop(); + await delay(10); + }); + + const createBaseline = async ({ + kibanaVersion = currentVersion, + }: { kibanaVersion?: string } = {}) => { + const { runMigrations, savedObjectsRepository, client } = await getKibanaMigratorTestKit({ + ...getBaseMigratorParams({ migrationAlgorithm: 'v2', kibanaVersion }), + types: [getSampleAType()], + }); + await runMigrations(); + + const sampleAObjs = range(5).map((number) => ({ + id: `a-${number}`, + type: 'sample_a', + attributes: { + keyword: `a_${number}`, + boolean: true, + }, + })); + + await savedObjectsRepository.bulkCreate(sampleAObjs); + + return { client }; + }; + + describe('when switching from a compatible version', () => { + it('it able to re-use a cluster state from the v2 algorithm', async () => { + await createBaseline(); + + const typeA = getSampleAType(); + + const { runMigrations, client, savedObjectsRepository } = await getKibanaMigratorTestKit({ + ...getBaseMigratorParams({ migrationAlgorithm: 'zdt' }), + logFilePath, + types: [typeA], + }); + + await runMigrations(); + + const indices = await client.indices.get({ index: '.kibana*' }); + expect(Object.keys(indices)).toEqual([v2IndexName]); + + const index = indices[v2IndexName]; + const mappings = index.mappings ?? {}; + const mappingMeta = mappings._meta ?? {}; + + expect(mappings.properties).toEqual( + expect.objectContaining({ + sample_a: typeA.mappings, + }) + ); + + expect(mappingMeta).toEqual({ + docVersions: { sample_a: '10.1.0' }, + mappingVersions: { sample_a: '10.1.0' }, + migrationState: expect.any(Object), + }); + + const { saved_objects: sampleADocs } = await savedObjectsRepository.find({ + type: 'sample_a', + }); + + expect(sampleADocs).toHaveLength(5); + + const records = await parseLogFile(logFilePath); + expect(records).toContainLogEntries( + [ + 'INIT: current algo check result: v2-compatible', + 'INIT -> UPDATE_INDEX_MAPPINGS', + 'INDEX_STATE_UPDATE_DONE -> DOCUMENTS_UPDATE_INIT', + 'Migration completed', + ], + { ordered: true } + ); + }); + }); + + describe('when switching from an incompatible version', () => { + it('fails and throws an explicit error', async () => { + const { client } = await createBaseline({ kibanaVersion: '8.7.0' }); + + // even when specifying an older version, the `indexTypeMap` will be present on the index's meta, + // so we have to manually remove it there. + const indices = await client.indices.get({ + index: '.kibana_8.7.0_001', + }); + const meta = indices['.kibana_8.7.0_001'].mappings!._meta! as IndexMappingMeta; + delete meta.indexTypesMap; + await client.indices.putMapping({ + index: '.kibana_8.7.0_001', + _meta: meta, + }); + + const typeA = getSampleAType(); + const { runMigrations } = await getKibanaMigratorTestKit({ + ...getBaseMigratorParams({ migrationAlgorithm: 'zdt' }), + logFilePath, + types: [typeA], + }); + + await expect(runMigrations()).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unable to complete saved object migrations for the [.kibana] index: Index .kibana_8.7.0_001 is using an incompatible version of the v2 algorithm"` + ); + + const records = await parseLogFile(logFilePath); + expect(records).toContainLogEntries( + ['current algo check result: v2-incompatible', 'INIT -> FATAL'], + { ordered: true } + ); + }); + }); +}); diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/create_index.test.ts b/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/create_index.test.ts index f96f0f4b07b62..6c95b9696538e 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/create_index.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/create_index.test.ts @@ -34,7 +34,7 @@ describe('ZDT with v2 compat - running on a fresh cluster', () => { const legacyType = getLegacyType(); const { runMigrations, client } = await getKibanaMigratorTestKit({ - ...getBaseMigratorParams(), + ...getBaseMigratorParams({ kibanaVersion: '8.8.0' }), logFilePath, types: [fooType, legacyType], }); diff --git a/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/update_mappings.test.ts b/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/update_mappings.test.ts index f2db243927d38..0c4956105fc78 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/update_mappings.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/zdt_v2_compat/update_mappings.test.ts @@ -39,7 +39,7 @@ describe('ZDT with v2 compat - basic mapping update', () => { const fooType = getFooType(); const legacyType = getLegacyType(); const { runMigrations } = await getKibanaMigratorTestKit({ - ...getBaseMigratorParams(), + ...getBaseMigratorParams({ kibanaVersion: '8.8.0' }), types: [fooType, legacyType], }); await runMigrations(); @@ -71,7 +71,7 @@ describe('ZDT with v2 compat - basic mapping update', () => { }; const { runMigrations, client } = await getKibanaMigratorTestKit({ - ...getBaseMigratorParams(), + ...getBaseMigratorParams({ kibanaVersion: '8.8.0' }), logFilePath, types: [fooType, legacyType], }); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid.tsx index 35c51ab4c996c..4f72f9550b1a3 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx +++ b/src/plugins/discover/public/components/discover_grid/discover_grid.tsx @@ -9,6 +9,8 @@ import React, { useCallback, useMemo, useState, useRef, useEffect } from 'react'; import classnames from 'classnames'; import { FormattedMessage } from '@kbn/i18n-react'; +import { of } from 'rxjs'; +import useObservable from 'react-use/lib/useObservable'; import './discover_grid.scss'; import { EuiDataGridSorting, @@ -25,7 +27,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { Filter } from '@kbn/es-query'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import { ToastsStart, IUiSettingsClient, HttpStart } from '@kbn/core/public'; +import type { ToastsStart, IUiSettingsClient, HttpStart, CoreStart } from '@kbn/core/public'; import { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; import { DocViewFilterFn } from '../../services/doc_views/doc_views_types'; import { getSchemaDetectors } from './discover_grid_schema'; @@ -52,6 +54,8 @@ import { useRowHeightsOptions } from '../../hooks/use_row_heights_options'; import { convertValueToString } from '../../utils/convert_value_to_string'; import { getRowsPerPageOptions, getDefaultRowsPerPage } from '../../utils/rows_per_page'; +const themeDefault = { darkMode: false }; + interface SortObj { id: string; direction: string; @@ -199,6 +203,7 @@ export interface DiscoverGridProps { * Service dependencies */ services: { + core: CoreStart; fieldFormats: FieldFormatsStart; addBasePath: HttpStart['basePath']['prepend']; uiSettings: IUiSettingsClient; @@ -249,6 +254,7 @@ export const DiscoverGrid = ({ services, }: DiscoverGridProps) => { const { fieldFormats, toastNotifications, dataViewFieldEditor, uiSettings } = services; + const { darkMode } = useObservable(services.core.theme?.theme$ ?? of(themeDefault), themeDefault); const dataGridRef = useRef(null); const [selectedDocs, setSelectedDocs] = useState([]); const [isFilterActive, setIsFilterActive] = useState(false); @@ -571,7 +577,7 @@ export const DiscoverGrid = ({ rows: displayedRows, onFilter, dataView, - isDarkMode: services.uiSettings.get('theme:darkMode'), + isDarkMode: darkMode, selectedDocs: usedSelectedDocs, setSelectedDocs: (newSelectedDocs) => { setSelectedDocs(newSelectedDocs); diff --git a/src/plugins/es_ui_shared/static/forms/components/field.tsx b/src/plugins/es_ui_shared/static/forms/components/field.tsx index a6df98f32453f..56527bd702e78 100644 --- a/src/plugins/es_ui_shared/static/forms/components/field.tsx +++ b/src/plugins/es_ui_shared/static/forms/components/field.tsx @@ -28,6 +28,11 @@ import { SuperSelectField, ToggleField, JsonEditorField, + ButtonGroupField, + MultiButtonGroupField, + DatePickerField, + PasswordField, + HiddenField, } from './fields'; const mapTypeToFieldComponent: { [key: string]: ComponentType } = { @@ -43,6 +48,11 @@ const mapTypeToFieldComponent: { [key: string]: ComponentType } = { [FIELD_TYPES.SUPER_SELECT]: SuperSelectField, [FIELD_TYPES.TOGGLE]: ToggleField, [FIELD_TYPES.JSON]: JsonEditorField, + [FIELD_TYPES.BUTTON_GROUP]: ButtonGroupField, + [FIELD_TYPES.MULTI_BUTTON_GROUP]: MultiButtonGroupField, + [FIELD_TYPES.DATE_PICKER]: DatePickerField, + [FIELD_TYPES.PASSWORD]: PasswordField, + [FIELD_TYPES.HIDDEN]: HiddenField, }; export const Field = (props: Props) => { diff --git a/src/plugins/es_ui_shared/static/forms/components/fields/button_group_field.tsx b/src/plugins/es_ui_shared/static/forms/components/fields/button_group_field.tsx new file mode 100644 index 0000000000000..edd3ddffe45f3 --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/components/fields/button_group_field.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 React from 'react'; +import { EuiButtonGroup, EuiButtonGroupOptionProps, EuiFormRow } from '@elastic/eui'; + +import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib'; + +interface Props { + field: FieldHook; + euiFieldProps: { + options: EuiButtonGroupOptionProps[]; + legend: string; + [key: string]: any; + }; + idAria?: string; + [key: string]: any; +} + +export const ButtonGroupField = ({ field, euiFieldProps, idAria, ...rest }: Props) => { + const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); + + return ( + + { + field.setValue(e); + }} + idSelected={field.value as string} + type="single" + data-test-subj="button-group" + {...euiFieldProps} + /> + + ); +}; diff --git a/src/plugins/es_ui_shared/static/forms/components/fields/date_picker_field.tsx b/src/plugins/es_ui_shared/static/forms/components/fields/date_picker_field.tsx new file mode 100644 index 0000000000000..9295f64d8ae05 --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/components/fields/date_picker_field.tsx @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { Moment } from 'moment'; +import { EuiDatePicker, EuiFormRow } from '@elastic/eui'; + +import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib'; + +interface Props { + field: FieldHook; + euiFieldProps: Record; + idAria?: string; + [key: string]: any; +} + +export const DatePickerField = ({ field, euiFieldProps, idAria, ...rest }: Props) => { + const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); + + return ( + + { + field.setValue(e); + }} + data-test-subj="input" + {...euiFieldProps} + /> + + ); +}; diff --git a/src/plugins/es_ui_shared/static/forms/components/fields/hidden_field.tsx b/src/plugins/es_ui_shared/static/forms/components/fields/hidden_field.tsx new file mode 100644 index 0000000000000..466f027345114 --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/components/fields/hidden_field.tsx @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const HiddenField = () => { + /** + * This is a hidden field. We return null so we do not render + * any field on the form + */ + return null; +}; diff --git a/src/plugins/es_ui_shared/static/forms/components/fields/index.ts b/src/plugins/es_ui_shared/static/forms/components/fields/index.ts index e3ef06888b335..91c4bf3db70fb 100644 --- a/src/plugins/es_ui_shared/static/forms/components/fields/index.ts +++ b/src/plugins/es_ui_shared/static/forms/components/fields/index.ts @@ -18,3 +18,8 @@ export * from './super_select_field'; export * from './toggle_field'; export * from './text_area_field'; export * from './json_editor_field'; +export * from './button_group_field'; +export * from './multi_button_group_field'; +export * from './date_picker_field'; +export * from './password_field'; +export * from './hidden_field'; diff --git a/src/plugins/es_ui_shared/static/forms/components/fields/multi_button_group_field.tsx b/src/plugins/es_ui_shared/static/forms/components/fields/multi_button_group_field.tsx new file mode 100644 index 0000000000000..dc106f57a084e --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/components/fields/multi_button_group_field.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiButtonGroup, EuiButtonGroupOptionProps, EuiFormRow } from '@elastic/eui'; + +import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib'; + +export interface MultiButtonGroupFieldValue { + [id: string]: boolean; +} + +interface Props { + field: FieldHook; + euiFieldProps: { + options: EuiButtonGroupOptionProps[]; + legend: string; + [key: string]: any; + }; + idAria?: string; + [key: string]: any; +} + +export const MultiButtonGroupField = ({ field, euiFieldProps, idAria, ...rest }: Props) => { + const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); + + return ( + + { + const value = field.value as MultiButtonGroupFieldValue; + field.setValue({ ...value, [e]: !value[e] }); + }} + idToSelectedMap={field.value as MultiButtonGroupFieldValue} + type="multi" + data-test-subj="button-group" + {...euiFieldProps} + /> + + ); +}; diff --git a/src/plugins/es_ui_shared/static/forms/components/fields/password_field.tsx b/src/plugins/es_ui_shared/static/forms/components/fields/password_field.tsx new file mode 100644 index 0000000000000..fee6592568bb9 --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/components/fields/password_field.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { EuiFieldPassword, EuiFormRow } from '@elastic/eui'; + +import { FieldHook, getFieldValidityAndErrorMessage } from '../../hook_form_lib'; + +interface Props { + field: FieldHook; + euiFieldProps: Record; + idAria?: string; + [key: string]: any; +} + +export const PasswordField = ({ field, euiFieldProps, idAria, ...rest }: Props) => { + const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); + + return ( + + + + ); +}; diff --git a/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx b/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx index 97ea955aaecb1..ed2b06523af4e 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/helpers/components.mdx @@ -46,6 +46,11 @@ This is the list of component we currently have. This list might grow in the fut * MultiSelectField * RadioGroupField * RangeField +* ButtonGroupField +* MultiButtonGroupField +* DatePickerField +* PasswordField +* HiddenField (*) Currently the `` only support the free form entry of items (e.g a list of "tags" that the user enters). This means that it does not work (yet) **with predefined selections** to chose from. diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/constants.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/constants.ts index 93bcd590749e9..42261430c05c8 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/constants.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/constants.ts @@ -20,6 +20,11 @@ export const FIELD_TYPES = { SUPER_SELECT: 'superSelect', MULTI_SELECT: 'multiSelect', JSON: 'json', + BUTTON_GROUP: 'buttonGroup', + MULTI_BUTTON_GROUP: 'multiButtonGroup', + DATE_PICKER: 'datePicker', + PASSWORD: 'password', + HIDDEN: 'hidden', }; // Validation types diff --git a/src/plugins/vis_types/timelion/public/components/timelion_expression_input.tsx b/src/plugins/vis_types/timelion/public/components/timelion_expression_input.tsx index 8d1d5285e2989..4dff27a1c061d 100644 --- a/src/plugins/vis_types/timelion/public/components/timelion_expression_input.tsx +++ b/src/plugins/vis_types/timelion/public/components/timelion_expression_input.tsx @@ -86,7 +86,9 @@ function TimelionExpressionInput({ value, setValue }: TimelionExpressionInputPro const abortController = new AbortController(); if (kibana.services.http) { kibana.services.http - .get('../api/timelion/functions', { signal: abortController.signal }) + .get('../internal/timelion/functions', { + signal: abortController.signal, + }) .then((data) => { functionList.current = data; }); diff --git a/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts b/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts index a0885d792ad3f..283998460111f 100644 --- a/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts +++ b/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts @@ -105,7 +105,7 @@ export function getTimelionRequestHandler({ const doSearch = async ( searchOptions: ReturnType ): Promise => { - return await http.post('/api/timelion/run', { + return await http.post('/internal/timelion/run', { body: JSON.stringify({ sheet: [expression], extended: { diff --git a/src/plugins/vis_types/timelion/server/routes/functions.ts b/src/plugins/vis_types/timelion/server/routes/functions.ts index 8fadb0d834542..3023508884a1f 100644 --- a/src/plugins/vis_types/timelion/server/routes/functions.ts +++ b/src/plugins/vis_types/timelion/server/routes/functions.ts @@ -13,7 +13,7 @@ import { LoadFunctions } from '../lib/load_functions'; export function functionsRoute(router: IRouter, { functions }: { functions: LoadFunctions }) { router.get( { - path: '/api/timelion/functions', + path: '/internal/timelion/functions', validate: false, }, async (context, request, response) => { diff --git a/src/plugins/vis_types/timelion/server/routes/run.ts b/src/plugins/vis_types/timelion/server/routes/run.ts index e136f1ab5a241..9affe7cc64820 100644 --- a/src/plugins/vis_types/timelion/server/routes/run.ts +++ b/src/plugins/vis_types/timelion/server/routes/run.ts @@ -37,7 +37,7 @@ export function runRoute( ) { router.post( { - path: '/api/timelion/run', + path: '/internal/timelion/run', validate: { body: schema.object({ sheet: schema.arrayOf(schema.string()), diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 47624acd6d250..4a3b06e8e4a1e 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -69,6 +69,7 @@ "xpack.server": "legacy/server", "xpack.serverless": "plugins/serverless", "xpack.serverlessSearch": "plugins/serverless_search", + "xpack.serverlessSecurity": "plugins/serverless_security", "xpack.securitySolution": "plugins/security_solution", "xpack.sessionView": "plugins/session_view", "xpack.snapshotRestore": "plugins/snapshot_restore", diff --git a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.ts b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.ts index 3469384f508d0..ccb237314c125 100644 --- a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.ts +++ b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_item_sets.ts @@ -57,7 +57,7 @@ export function getShouldClauses(significantTerms: SignificantTerm[]) { export function getFrequentItemSetsAggFields(significantTerms: SignificantTerm[]) { return Array.from( group(significantTerms, ({ fieldName }) => fieldName), - ([field, values]) => ({ field, include: values.map((d) => d.fieldValue) }) + ([field, values]) => ({ field, include: values.map((d) => String(d.fieldValue)) }) ); } @@ -100,7 +100,6 @@ export async function fetchFrequentItemSets( const frequentItemSetsAgg: Record = { fi: { - // @ts-expect-error `frequent_item_sets` is not yet part of `AggregationsAggregationContainer` frequent_item_sets: { minimum_set_size: 2, size: 200, diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/fields/button_group_field.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/fields/button_group_field.tsx deleted file mode 100644 index 2c286cb829783..0000000000000 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/fields/button_group_field.tsx +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback } from 'react'; -import { EuiButtonGroup, EuiButtonGroupOptionProps, EuiFormRow } from '@elastic/eui'; -import { - useFormData, - useFormContext, - FieldHook, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { get } from 'lodash'; - -interface ButtonGroupFieldProps { - field: FieldHook; - legend: string; - options: EuiButtonGroupOptionProps[]; - type?: 'single' | 'multi'; - 'data-test-subj'?: string; -} - -export const ButtonGroupField: React.FC = React.memo( - ({ field, legend, options, type = 'single', ...rest }) => { - const { setFieldValue } = useFormContext(); - const [formData] = useFormData({ watch: [field.path] }); - const selected = get(formData, field.path); - - const onChange = useCallback( - (current: string) => { - setFieldValue(field.path, current); - }, - [setFieldValue, field.path] - ); - - const onChangeMulti = useCallback( - (current: string) => { - const newSelectedValue = { ...selected, [current]: !selected[current] }; - // Don't allow the user to deselect all options - if (!Object.values(newSelectedValue).every((v) => v === false)) { - setFieldValue(field.path, newSelectedValue); - } - }, - [setFieldValue, selected, field.path] - ); - - return ( - - {type === 'multi' ? ( - - ) : ( - - )} - - ); - } -); -ButtonGroupField.displayName = 'ButtonGroupField'; diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/fields/date_picker_field.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/fields/date_picker_field.tsx deleted file mode 100644 index c7e4684f3254b..0000000000000 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/fields/date_picker_field.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useState } from 'react'; -import moment, { Moment } from 'moment'; -import { EuiDatePicker, EuiFormRow } from '@elastic/eui'; -import { - useFormData, - useFormContext, - FieldHook, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { getSelectedForDatePicker as getSelected } from '../../helpers/get_selected_for_date_picker'; - -interface DatePickerFieldProps { - field: FieldHook; - showTimeSelect?: boolean; - 'data-test-subj'?: string; -} - -export const DatePickerField: React.FC = React.memo( - ({ field, showTimeSelect = true, ...rest }) => { - const [today] = useState(moment()); - - const { setFieldValue } = useFormContext(); - const [form] = useFormData({ watch: [field.path] }); - - const { selected, utcOffset } = getSelected(form, field.path); - - const onChange = useCallback( - (currentDate: Moment | null) => { - // convert the moment date back into a string if it's not null - setFieldValue(field.path, currentDate ? currentDate.toISOString() : currentDate); - }, - [setFieldValue, field.path] - ); - - return ( - - - - ); - } -); -DatePickerField.displayName = 'DatePickerField'; diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/custom_recurring_schedule.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/custom_recurring_schedule.tsx index 8bf9b7d24eba5..939896271bbac 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/custom_recurring_schedule.tsx +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/custom_recurring_schedule.tsx @@ -7,12 +7,18 @@ import React, { useMemo } from 'react'; import moment from 'moment'; import { css } from '@emotion/react'; -import { getUseField, useFormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { + FIELD_TYPES, + getUseField, + useFormData, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { + Field, + MultiButtonGroupFieldValue, +} from '@kbn/es-ui-shared-plugin/static/forms/components'; import { EuiFlexGroup, EuiFlexItem, EuiFormLabel, EuiSpacer } from '@elastic/eui'; import { CREATE_FORM_CUSTOM_FREQUENCY, Frequency, WEEKDAY_OPTIONS } from '../../constants'; import * as i18n from '../../translations'; -import { ButtonGroupField } from '../fields/button_group_field'; import { getInitialByWeekday } from '../../helpers/get_initial_by_weekday'; import { getWeekdayInfo } from '../../helpers/get_weekday_info'; import { FormProps } from '../schema'; @@ -103,13 +109,30 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => { recurringSchedule?.frequency === Frequency.DAILY ? ( { + if ( + Object.values(value as MultiButtonGroupFieldValue).every((v) => v === false) + ) { + return { + message: i18n.CREATE_FORM_BYWEEKDAY_REQUIRED, + }; + } + }, + }, + ], + defaultValue: defaultByWeekday, + }} componentProps={{ 'data-test-subj': 'byweekday-field', - legend: 'Repeat on weekday', - options: WEEKDAY_OPTIONS, - type: 'multi', + euiFieldProps: { + legend: 'Repeat on weekday', + options: WEEKDAY_OPTIONS, + }, }} /> ) : null} @@ -117,12 +140,12 @@ export const CustomRecurringSchedule: React.FC = React.memo(() => { {recurringSchedule?.customFrequency === Frequency.MONTHLY ? ( ) : null} diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.tsx index ea46cc55be84a..03dbca85d3991 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.tsx +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useMemo } from 'react'; -import moment from 'moment'; +import React, { useMemo, useState } from 'react'; +import moment, { Moment } from 'moment'; import { EuiComboBox, EuiFlexGroup, @@ -15,7 +15,11 @@ import { EuiSpacer, EuiSplitPanel, } from '@elastic/eui'; -import { getUseField, useFormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { + FIELD_TYPES, + getUseField, + useFormData, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { getWeekdayInfo } from '../../helpers/get_weekday_info'; import { @@ -26,8 +30,6 @@ import { RECURRENCE_END_OPTIONS, } from '../../constants'; import * as i18n from '../../translations'; -import { ButtonGroupField } from '../fields/button_group_field'; -import { DatePickerField } from '../fields/date_picker_field'; import { CustomRecurringSchedule } from './custom_recurring_schedule'; import { recurringSummary } from '../../helpers/recurring_summary'; import { getPresets } from '../../helpers/get_presets'; @@ -35,7 +37,12 @@ import { FormProps } from '../schema'; const UseField = getUseField({ component: Field }); +export const toMoment = (value: string): Moment => moment(value); +export const toString = (value: Moment): string => value.toISOString(); + export const RecurringSchedule: React.FC = React.memo(() => { + const [today] = useState(moment()); + const [{ startDate, endDate, timezone, recurringSchedule }] = useFormData({ watch: [ 'startDate', @@ -105,11 +112,12 @@ export const RecurringSchedule: React.FC = React.memo(() => { ) : null} {recurringSchedule?.ends === EndsOptions.ON_DATE ? ( @@ -120,14 +128,19 @@ export const RecurringSchedule: React.FC = React.memo(() => { diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/schema.ts b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/schema.ts index f542d82389dc6..47ed6783b0eae 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/schema.ts +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/schema.ts @@ -69,6 +69,7 @@ export const schema: FormSchema = { ], }, ends: { + type: FIELD_TYPES.BUTTON_GROUP, label: i18n.CREATE_FORM_ENDS, defaultValue: EndsOptions.NEVER, validations: [], @@ -90,6 +91,6 @@ export const schema: FormSchema = { defaultValue: Frequency.WEEKLY, }, byweekday: {}, - bymonth: {}, + bymonth: { type: FIELD_TYPES.BUTTON_GROUP, label: '', validations: [], defaultValue: 'day' }, }, }; diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts b/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts index 3b2e5529ef1ec..fc7ad9d1dbb5b 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts @@ -312,6 +312,13 @@ export const CREATE_FORM_WEEKDAY_SHORT = (dayOfWeek: string) => [ }), ]; +export const CREATE_FORM_BYWEEKDAY_REQUIRED = i18n.translate( + 'xpack.alerting.maintenanceWindows.createForm.byweekdayFieldRequiredError', + { + defaultMessage: 'A week day is required.', + } +); + export const CREATE_FORM_CUSTOM_REPEAT_MONTHLY_ON_DAY = (startDate: Moment) => i18n.translate('xpack.alerting.maintenanceWindows.createForm.repeatOnMonthlyDay', { defaultMessage: 'On day {dayNumber}', diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts index 88d4408d33152..1ade523356987 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts @@ -79,8 +79,8 @@ describe('Storage Explorer', () => { it('has a list of summary stats', () => { cy.contains('Total APM size'); - cy.contains('Disk space used'); - cy.contains('Incremental APM size'); + cy.contains('Relative disk space used'); + cy.contains('Delta in APM size'); cy.contains('Daily data generation'); cy.contains('Traces per minute'); cy.contains('Number of services'); diff --git a/x-pack/plugins/apm/public/application/index.tsx b/x-pack/plugins/apm/public/application/index.tsx index ab717ffed873b..da2fe62b47266 100644 --- a/x-pack/plugins/apm/public/application/index.tsx +++ b/x-pack/plugins/apm/public/application/index.tsx @@ -48,6 +48,7 @@ export const renderApp = ({ plugins: pluginsSetup, data: pluginsStart.data, inspector: pluginsStart.inspector, + infra: pluginsStart.infra, observability: pluginsStart.observability, observabilityShared: pluginsStart.observabilityShared, observabilityRuleTypeRegistry, diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx index 250556ccc359e..4b2f8bb39579e 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx @@ -40,7 +40,10 @@ export function InstanceActionsMenu({ kuery, onClose, }: Props) { - const { core } = useApmPluginContext(); + const { + core, + infra: { locators }, + } = useApmPluginContext(); const { data, status } = useInstanceDetailsFetcher({ serviceName, serviceNodeName, @@ -89,6 +92,7 @@ export function InstanceActionsMenu({ basePath: core.http.basePath, onFilterByInstanceClick: handleFilterByInstanceClick, metricsHref, + infraLocators: locators, }); return ( diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts index decc23e053565..6267592058868 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts @@ -8,6 +8,7 @@ import { i18n } from '@kbn/i18n'; import { IBasePath } from '@kbn/core/public'; import moment from 'moment'; +import type { InfraLocators } from '@kbn/infra-plugin/public/locators'; import { APIReturnType } from '../../../../../services/rest/create_call_apm_api'; import { getInfraHref } from '../../../../shared/links/infra_link'; import { @@ -37,11 +38,13 @@ export function getMenuSections({ basePath, onFilterByInstanceClick, metricsHref, + infraLocators, }: { instanceDetails: InstaceDetails; basePath: IBasePath; onFilterByInstanceClick: () => void; metricsHref: string; + infraLocators: InfraLocators; }) { const podId = instanceDetails.kubernetes?.pod?.uid; const containerId = instanceDetails.container?.id; @@ -49,6 +52,7 @@ export function getMenuSections({ ? new Date(instanceDetails['@timestamp']).valueOf() : undefined; const infraMetricsQuery = getInfraMetricsQuery(instanceDetails['@timestamp']); + const infraNodeLocator = infraLocators.nodeLogsLocator; const podActions: Action[] = [ { @@ -57,11 +61,10 @@ export function getMenuSections({ 'xpack.apm.serviceOverview.instancesTable.actionMenus.podLogs', { defaultMessage: 'Pod logs' } ), - href: getInfraHref({ - app: 'logs', - basePath, - path: `/link-to/pod-logs/${podId}`, - query: { time }, + href: infraNodeLocator.getRedirectUrl({ + nodeId: podId!, + nodeType: 'pod', + time, }), condition: !!podId, }, @@ -88,11 +91,10 @@ export function getMenuSections({ 'xpack.apm.serviceOverview.instancesTable.actionMenus.containerLogs', { defaultMessage: 'Container logs' } ), - href: getInfraHref({ - app: 'logs', - basePath, - path: `/link-to/container-logs/${containerId}`, - query: { time }, + href: infraNodeLocator.getRedirectUrl({ + nodeId: containerId!, + nodeType: 'container', + time, }), condition: !!containerId, }, diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/get_storage_explorer_links.ts b/x-pack/plugins/apm/public/components/app/storage_explorer/get_storage_explorer_links.ts index 1736cd852a417..ce8b12760ab2f 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/get_storage_explorer_links.ts +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/get_storage_explorer_links.ts @@ -7,9 +7,12 @@ import { CoreStart } from '@kbn/core-lifecycle-browser'; -export function getIndexManagementHref(core: CoreStart) { +export function getIndexManagementHref(core: CoreStart, dataStream?: string) { + const indexManagementPath = '/data/index_management/data_streams'; return core.application.getUrlForApp('management', { - path: '/data/index_management/data_streams', + path: dataStream + ? `${indexManagementPath}/${dataStream}?isDeepLink=true` + : indexManagementPath, }); } diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/resources/tips_and_resources.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/resources/tips_and_resources.tsx index 4c1b283f05628..73a79fcc0a020 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/resources/tips_and_resources.tsx +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/resources/tips_and_resources.tsx @@ -164,7 +164,7 @@ export function TipsAndResources() { > {cards.map(({ icon, title, description, href }) => ( - + } title={title} diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/index.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/index.tsx index c16dc5388cc2f..b40102e0429bf 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/index.tsx +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/services_table/index.tsx @@ -16,10 +16,16 @@ import { EuiIcon, EuiProgress, EuiPanel, + EuiFlexGroup, + EuiFlexItem, + EuiButton, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { apmServiceInventoryOptimizedSorting } from '@kbn/observability-plugin/common'; +import moment from 'moment'; +import { isEmpty } from 'lodash'; +import { downloadJson } from '../../../../utils/download_json'; import { AgentName } from '../../../../../typings/es_schemas/ui/fields/agent'; import { EnvironmentBadge } from '../../../shared/environment_badge'; import { asPercent } from '../../../../../common/utils/formatters'; @@ -218,7 +224,7 @@ export function ServicesTable() { {i18n.translate( 'xpack.apm.storageExplorer.table.samplingColumnName', { - defaultMessage: 'Sample rate', + defaultMessage: 'Sampling rate', } )}{' '} {loading && } + + + + downloadJson({ + fileName: `storage-explorefpr-${moment(Date.now()).format( + 'YYYYMMDDHHmmss' + )}.json`, + data: { + filters: { + rangeFrom, + rangeTo, + environment, + kuery, + indexLifecyclePhase, + }, + services: serviceStatisticsItems.map((item) => ({ + ...item, + sampling: asPercent(item?.sampling, 1), + size: item?.size + ? asDynamicBytes(item?.size) + : NOT_AVAILABLE_LABEL, + })), + }, + }) + } + fill + > + {i18n.translate('xpack.apm.storageExplorer.downloadReport', { + defaultMessage: 'Download report', + })} + + + + ['indicesStats']; @@ -33,6 +36,8 @@ interface Props { } export function IndexStatsPerService({ indicesStats, status }: Props) { + const { core } = useApmPluginContext(); + const columns: Array< EuiBasicTableColumn> > = [ @@ -84,7 +89,15 @@ export function IndexStatsPerService({ indicesStats, status }: Props) { defaultMessage: 'Data stream', } ), - render: (_, { dataStream }) => dataStream ?? NOT_AVAILABLE_LABEL, + render: (_, { dataStream }) => + ( + + {dataStream} + + ) ?? NOT_AVAILABLE_LABEL, sortable: true, }, { diff --git a/x-pack/plugins/apm/public/components/app/storage_explorer/summary_stats.tsx b/x-pack/plugins/apm/public/components/app/storage_explorer/summary_stats.tsx index 860a9b251b71e..0021af524b3b7 100644 --- a/x-pack/plugins/apm/public/components/app/storage_explorer/summary_stats.tsx +++ b/x-pack/plugins/apm/public/components/app/storage_explorer/summary_stats.tsx @@ -104,7 +104,7 @@ export function SummaryStats() { 'xpack.apm.storageExplorer.summary.totalSize.tooltip', { defaultMessage: - 'Total storage size of all the APM indices currently, ignoring all filters.', + 'Total storage size of all APM indices including replicas, ignoring the filter settings.', } )} value={asDynamicBytes(data?.totalSize)} @@ -115,7 +115,7 @@ export function SummaryStats() { label={i18n.translate( 'xpack.apm.storageExplorer.summary.diskSpaceUsedPct', { - defaultMessage: 'Disk space used', + defaultMessage: 'Relative disk space used', } )} tooltipContent={i18n.translate( @@ -131,13 +131,13 @@ export function SummaryStats() { /> {isLabsButtonEnabled && } - {isStorageExplorerAvailable && ( - - - - {i18n.translate('xpack.apm.storageExplorerLinkLabel', { - defaultMessage: 'Storage Explorer', - })} - - - - )} - {canCreateMlJobs && } {isAlertingAvailable && ( - - -

- {i18n.translate('xpack.apm.views.storageExplorer.title', { - defaultMessage: 'Storage explorer', - })} -

-
-
- - - -
- ), + pageTitle: i18n.translate('xpack.apm.views.storageExplorer.title', { + defaultMessage: 'Storage explorer', + }), rightSideItems: [ { + expect(infraLocators.nodeLogsLocator.getRedirectUrl).toBeCalledTimes(3); + expect(infraLocators.logsLocator.getRedirectUrl).toBeCalledTimes(1); +}; + describe('Transaction action menu', () => { const basePath = { prepend: (url: string) => { @@ -35,6 +43,10 @@ describe('Transaction action menu', () => { ); const location = history.location; + afterEach(() => { + jest.clearAllMocks(); + }); + it('shows required sections only', () => { const transaction = { timestamp, @@ -48,6 +60,7 @@ describe('Transaction action menu', () => { basePath, location, apmRouter, + infraLocators, infraLinksAvailable: false, }) ).toEqual([ @@ -60,7 +73,6 @@ describe('Transaction action menu', () => { { key: 'traceLogs', label: 'Trace logs', - href: 'some-basepath/app/logs/link-to/logs?time=1580986800&filter=trace.id:%22123%22%20OR%20(not%20trace.id:*%20AND%20%22123%22)', condition: true, }, ], @@ -93,6 +105,7 @@ describe('Transaction action menu', () => { }, ], ]); + expectInfraLocatorsToBeCalled(); }); it('shows pod and required sections only', () => { @@ -109,6 +122,7 @@ describe('Transaction action menu', () => { basePath, location, apmRouter, + infraLocators, infraLinksAvailable: true, }) ).toEqual([ @@ -122,7 +136,6 @@ describe('Transaction action menu', () => { { key: 'podLogs', label: 'Pod logs', - href: 'some-basepath/app/logs/link-to/pod-logs/123?time=1580986800', condition: true, }, { @@ -141,7 +154,6 @@ describe('Transaction action menu', () => { { key: 'traceLogs', label: 'Trace logs', - href: 'some-basepath/app/logs/link-to/logs?time=1580986800&filter=trace.id:%22123%22%20OR%20(not%20trace.id:*%20AND%20%22123%22)', condition: true, }, ], @@ -174,6 +186,7 @@ describe('Transaction action menu', () => { }, ], ]); + expectInfraLocatorsToBeCalled(); }); it('shows host and required sections only', () => { @@ -190,6 +203,7 @@ describe('Transaction action menu', () => { basePath, location, apmRouter, + infraLocators, infraLinksAvailable: true, }) ).toEqual([ @@ -202,7 +216,6 @@ describe('Transaction action menu', () => { { key: 'hostLogs', label: 'Host logs', - href: 'some-basepath/app/logs/link-to/host-logs/foo?time=1580986800', condition: true, }, { @@ -221,7 +234,6 @@ describe('Transaction action menu', () => { { key: 'traceLogs', label: 'Trace logs', - href: 'some-basepath/app/logs/link-to/logs?time=1580986800&filter=trace.id:%22123%22%20OR%20(not%20trace.id:*%20AND%20%22123%22)', condition: true, }, ], @@ -254,5 +266,6 @@ describe('Transaction action menu', () => { }, ], ]); + expectInfraLocatorsToBeCalled(); }); }); diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts index 769a96002d5ef..e0df994ac15c0 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts @@ -11,6 +11,7 @@ import { IBasePath } from '@kbn/core/public'; import { isEmpty, pickBy } from 'lodash'; import moment from 'moment'; import url from 'url'; +import type { InfraLocators } from '@kbn/infra-plugin/public/locators'; import type { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { getDiscoverHref } from '../links/discover_links/discover_link'; import { getDiscoverQuery } from '../links/discover_links/discover_transaction_link'; @@ -35,18 +36,21 @@ export const getSections = ({ basePath, location, apmRouter, + infraLocators, infraLinksAvailable, }: { transaction?: Transaction; basePath: IBasePath; location: Location; apmRouter: ApmRouter; + infraLocators: InfraLocators; infraLinksAvailable: boolean; }) => { if (!transaction) return []; const hostName = transaction.host?.hostname; const podId = transaction.kubernetes?.pod?.uid; const containerId = transaction.container?.id; + const { nodeLogsLocator, logsLocator } = infraLocators; const time = Math.round(transaction.timestamp.us / 1000); const infraMetricsQuery = getInfraMetricsQuery(transaction); @@ -78,11 +82,10 @@ export const getSections = ({ 'xpack.apm.transactionActionMenu.showPodLogsLinkLabel', { defaultMessage: 'Pod logs' } ), - href: getInfraHref({ - app: 'logs', - basePath, - path: `/link-to/pod-logs/${podId}`, - query: { time }, + href: nodeLogsLocator.getRedirectUrl({ + nodeId: podId!, + nodeType: 'pod', + time, }), condition: !!podId, }, @@ -109,11 +112,10 @@ export const getSections = ({ 'xpack.apm.transactionActionMenu.showContainerLogsLinkLabel', { defaultMessage: 'Container logs' } ), - href: getInfraHref({ - app: 'logs', - basePath, - path: `/link-to/container-logs/${containerId}`, - query: { time }, + href: nodeLogsLocator.getRedirectUrl({ + nodeId: containerId!, + nodeType: 'container', + time, }), condition: !!containerId, }, @@ -140,11 +142,10 @@ export const getSections = ({ 'xpack.apm.transactionActionMenu.showHostLogsLinkLabel', { defaultMessage: 'Host logs' } ), - href: getInfraHref({ - app: 'logs', - basePath, - path: `/link-to/host-logs/${hostName}`, - query: { time }, + href: nodeLogsLocator.getRedirectUrl({ + nodeId: hostName!, + nodeType: 'host', + time, }), condition: !!hostName, }, @@ -171,14 +172,9 @@ export const getSections = ({ 'xpack.apm.transactionActionMenu.showTraceLogsLinkLabel', { defaultMessage: 'Trace logs' } ), - href: getInfraHref({ - app: 'logs', - basePath, - path: `/link-to/logs`, - query: { - time, - filter: `trace.id:"${transaction.trace.id}" OR (not trace.id:* AND "${transaction.trace.id}")`, - }, + href: logsLocator.getRedirectUrl({ + filter: `trace.id:"${transaction.trace.id}" OR (not trace.id:* AND "${transaction.trace.id}")`, + time, }), condition: true, }, diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx index 3de7ed3374c56..039d248f419ac 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx @@ -28,15 +28,13 @@ import { TransactionActionMenu } from './transaction_action_menu'; import * as Transactions from './__fixtures__/mock_data'; import { apmRouter } from '../../routing/apm_route_config'; -function getMockAPMContext({ canSave }: { canSave: boolean }) { - return { - ...mockApmPluginContextValue, - core: { - ...mockApmPluginContextValue.core, - application: { capabilities: { apm: { save: canSave }, ml: {} } }, - }, - } as unknown as ApmPluginContextValue; -} +const apmContextMock = { + ...mockApmPluginContextValue, + core: { + ...mockApmPluginContextValue.core, + application: { capabilities: { apm: { save: true }, ml: {} } }, + }, +} as unknown as ApmPluginContextValue; const history = createMemoryHistory(); history.replace( @@ -46,7 +44,7 @@ history.replace( function Wrapper({ children }: { children?: React.ReactNode }) { return ( - + {children} @@ -73,6 +71,13 @@ const renderTransaction = async (transaction: Record) => { return rendered; }; +const expectInfraLocatorsToBeCalled = () => { + expect( + apmContextMock.infra.locators.nodeLogsLocator.getRedirectUrl + ).toBeCalled(); + expect(apmContextMock.infra.locators.logsLocator.getRedirectUrl).toBeCalled(); +}; + describe('TransactionActionMenu component', () => { beforeAll(() => { jest.spyOn(hooks, 'useFetcher').mockReturnValue({ @@ -81,7 +86,7 @@ describe('TransactionActionMenu component', () => { refetch: jest.fn(), }); }); - afterAll(() => { + afterEach(() => { jest.clearAllMocks(); }); it('should always render the discover link', async () => { @@ -92,16 +97,10 @@ describe('TransactionActionMenu component', () => { expect(queryByText('View transaction in Discover')).not.toBeNull(); }); - it('always renders the trace logs link', async () => { - const { getByText } = await renderTransaction( - Transactions.transactionWithMinimalData - ); + it('should call infra locators getRedirectUrl function', async () => { + await renderTransaction(Transactions.transactionWithMinimalData); - expect( - (getByText('Trace logs').parentElement as HTMLAnchorElement).href - ).toEqual( - 'http://localhost/basepath/app/logs/link-to/logs?time=1545092070952&filter=trace.id:%228b60bd32ecc6e1506735a8b6cfcf175c%22%20OR%20(not%20trace.id:*%20AND%20%228b60bd32ecc6e1506735a8b6cfcf175c%22)' - ); + expectInfraLocatorsToBeCalled(); }); describe('when there is no pod id', () => { @@ -123,16 +122,10 @@ describe('TransactionActionMenu component', () => { }); describe('when there is a pod id', () => { - it('renders the pod logs link', async () => { - const { getByText } = await renderTransaction( - Transactions.transactionWithKubernetesData - ); + it('should call infra locators getRedirectUrl function', async () => { + await renderTransaction(Transactions.transactionWithKubernetesData); - expect( - (getByText('Pod logs').parentElement as HTMLAnchorElement).href - ).toEqual( - 'http://localhost/basepath/app/logs/link-to/pod-logs/pod123456abcdef?time=1545092070952' - ); + expectInfraLocatorsToBeCalled(); }); it('renders the pod metrics link', async () => { @@ -166,17 +159,11 @@ describe('TransactionActionMenu component', () => { }); }); - describe('when there is a container id', () => { + describe('should call infra locators getRedirectUrl function', () => { it('renders the Container logs link', async () => { - const { getByText } = await renderTransaction( - Transactions.transactionWithContainerData - ); + await renderTransaction(Transactions.transactionWithContainerData); - expect( - (getByText('Container logs').parentElement as HTMLAnchorElement).href - ).toEqual( - 'http://localhost/basepath/app/logs/link-to/container-logs/container123456abcdef?time=1545092070952' - ); + expectInfraLocatorsToBeCalled(); }); it('renders the Container metrics link', async () => { @@ -211,16 +198,10 @@ describe('TransactionActionMenu component', () => { }); describe('when there is a hostname', () => { - it('renders the Host logs link', async () => { - const { getByText } = await renderTransaction( - Transactions.transactionWithHostData - ); + it('should call infra locators getRedirectUrl function', async () => { + await renderTransaction(Transactions.transactionWithHostData); - expect( - (getByText('Host logs').parentElement as HTMLAnchorElement).href - ).toEqual( - 'http://localhost/basepath/app/logs/link-to/host-logs/227453131a17?time=1545092070952' - ); + expectInfraLocatorsToBeCalled(); }); it('renders the Host metrics link', async () => { diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx index 2d3c3d62d2f97..30b4bf4bc669d 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx @@ -89,7 +89,11 @@ export function TransactionActionMenu({ transaction, isLoading }: Props) { } function ActionMenuSections({ transaction }: { transaction?: Transaction }) { - const { core, uiActions } = useApmPluginContext(); + const { + core, + uiActions, + infra: { locators }, + } = useApmPluginContext(); const location = useLocation(); const apmRouter = useApmRouter(); @@ -102,6 +106,7 @@ function ActionMenuSections({ transaction }: { transaction?: Transaction }) { basePath: core.http.basePath, location, apmRouter, + infraLocators: locators, infraLinksAvailable, }); diff --git a/x-pack/plugins/apm/public/context/apm_plugin/apm_plugin_context.tsx b/x-pack/plugins/apm/public/context/apm_plugin/apm_plugin_context.tsx index fe1a640ea5a34..32084c66b289b 100644 --- a/x-pack/plugins/apm/public/context/apm_plugin/apm_plugin_context.tsx +++ b/x-pack/plugins/apm/public/context/apm_plugin/apm_plugin_context.tsx @@ -15,6 +15,7 @@ import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import type { InfraClientStartExports } from '@kbn/infra-plugin/public'; import { ApmPluginSetupDeps } from '../../plugin'; import { ConfigSchema } from '../..'; @@ -26,6 +27,7 @@ export interface ApmPluginContextValue { plugins: ApmPluginSetupDeps & { maps?: MapsStartApi }; observabilityRuleTypeRegistry: ObservabilityRuleTypeRegistry; observability: ObservabilityPublicStart; + infra: InfraClientStartExports; dataViews: DataViewsPublicPluginStart; data: DataPublicPluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; 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 3d245e30418e4..f4d5dad5c4a74 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 @@ -16,6 +16,8 @@ import { createObservabilityRuleTypeRegistryMock } from '@kbn/observability-plug import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { MlLocatorDefinition } from '@kbn/ml-plugin/public'; import { enableComparisonByDefault } from '@kbn/observability-plugin/public'; +import type { InfraLocators } from '@kbn/infra-plugin/public/locators'; +import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; import { ApmPluginContext, ApmPluginContextValue } from './apm_plugin_context'; import { ConfigSchema } from '../..'; import { createCallApmApi } from '../../services/rest/create_call_apm_api'; @@ -89,6 +91,11 @@ const mockPlugin = { }, }; +export const infraLocatorsMock: InfraLocators = { + logsLocator: sharePluginMock.createLocator(), + nodeLogsLocator: sharePluginMock.createLocator(), +}; + const mockCorePlugins = { embeddable: {}, inspector: {}, @@ -111,6 +118,9 @@ export const mockApmPluginContextValue = { plugins: mockPlugin, observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(), corePlugins: mockCorePlugins, + infra: { + locators: infraLocatorsMock, + }, deps: {}, unifiedSearch: mockUnifiedSearch, uiActions: { diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index e9703c7429709..f59f0b89e1773 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -109,7 +109,7 @@ export interface ApmPluginStartDeps { fieldFormats?: FieldFormatsStart; security?: SecurityPluginStart; spaces?: SpacesPluginStart; - infra?: InfraClientStartExports; + infra: InfraClientStartExports; dataViews: DataViewsPublicPluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; storage: IStorageWrapper; @@ -214,6 +214,11 @@ export class ApmPlugin implements Plugin { } }, }, + { + label: apmStorageExplorerTitle, + app: 'apm', + path: '/storage-explorer', + }, ], }, ]; diff --git a/x-pack/plugins/apm/public/utils/download_json.ts b/x-pack/plugins/apm/public/utils/download_json.ts new file mode 100644 index 0000000000000..2ce9b08f25038 --- /dev/null +++ b/x-pack/plugins/apm/public/utils/download_json.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. + */ + +export function downloadJson({ + fileName, + data = {}, +}: { + fileName: string; + data?: Record; +}) { + const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( + JSON.stringify(data) + )}`; + const link = document.createElement('a'); + link.href = jsonString; + link.download = fileName; + link.click(); +} diff --git a/x-pack/plugins/canvas/public/functions/timelion.ts b/x-pack/plugins/canvas/public/functions/timelion.ts index ee3a9ca7c0351..7ab272911389d 100644 --- a/x-pack/plugins/canvas/public/functions/timelion.ts +++ b/x-pack/plugins/canvas/public/functions/timelion.ts @@ -132,7 +132,7 @@ export function timelionFunctionFactory(initialize: InitializeArguments): () => let result: any; try { - result = await fetch(initialize.prependBasePath(`/api/timelion/run`), { + result = await fetch(initialize.prependBasePath(`/internal/timelion/run`), { method: 'POST', responseType: 'json', data: body, diff --git a/x-pack/plugins/cases/common/api/cases/comment/index.test.ts b/x-pack/plugins/cases/common/api/cases/comment/index.test.ts index 5e3a56fc1b077..b0f99125226c3 100644 --- a/x-pack/plugins/cases/common/api/cases/comment/index.test.ts +++ b/x-pack/plugins/cases/common/api/cases/comment/index.test.ts @@ -28,7 +28,6 @@ import { BulkCreateCommentRequestRt, BulkGetAttachmentsRequestRt, BulkGetAttachmentsResponseRt, - FindCommentsArgsRt, } from '.'; describe('Comments', () => { @@ -750,35 +749,6 @@ describe('Comments', () => { }); }); - describe('FindCommentsArgsRt', () => { - const defaultRequest = { - caseID: 'basic-case-id', - queryParams: { - page: 1, - perPage: 10, - sortOrder: 'asc', - }, - }; - - it('has expected attributes in request', () => { - const query = FindCommentsArgsRt.decode(defaultRequest); - - expect(query).toStrictEqual({ - _tag: 'Right', - right: defaultRequest, - }); - }); - - it('removes foo:bar attributes from request', () => { - const query = FindCommentsArgsRt.decode({ ...defaultRequest, foo: 'bar' }); - - expect(query).toStrictEqual({ - _tag: 'Right', - right: defaultRequest, - }); - }); - }); - describe('BulkCreateCommentRequestRt', () => { const defaultRequest = [ { diff --git a/x-pack/plugins/cases/common/api/cases/comment/index.ts b/x-pack/plugins/cases/common/api/cases/comment/index.ts index 1cbe92ae70784..573f36bd0f963 100644 --- a/x-pack/plugins/cases/common/api/cases/comment/index.ts +++ b/x-pack/plugins/cases/common/api/cases/comment/index.ts @@ -298,13 +298,6 @@ export const FindCommentsQueryParamsRt = rt.exact( }) ); -export const FindCommentsArgsRt = rt.intersection([ - rt.strict({ - caseID: rt.string, - }), - rt.strict({ queryParams: rt.union([FindCommentsQueryParamsRt, rt.undefined]) }), -]); - export const BulkCreateCommentRequestRt = rt.array(CommentRequestRt); export const BulkGetAttachmentsRequestRt = rt.strict({ diff --git a/x-pack/plugins/cases/common/api/cases/user_actions/response.ts b/x-pack/plugins/cases/common/api/cases/user_actions/response.ts index af9b15ddf44fe..5fe505a7fa015 100644 --- a/x-pack/plugins/cases/common/api/cases/user_actions/response.ts +++ b/x-pack/plugins/cases/common/api/cases/user_actions/response.ts @@ -61,7 +61,7 @@ const CaseUserActionBasicWithoutConnectorIdRt = rt.intersection([ UserActionCommonAttributesRt, ]); -const CaseUserActionDeprecatedResponseRt = rt.intersection([ +export const CaseUserActionDeprecatedResponseRt = rt.intersection([ CaseUserActionBasicRt, CaseUserActionInjectedDeprecatedIdsRt, ]); diff --git a/x-pack/plugins/cases/common/api/metrics/case.test.ts b/x-pack/plugins/cases/common/api/metrics/case.test.ts index 931970d90bcf5..073aac4899fb9 100644 --- a/x-pack/plugins/cases/common/api/metrics/case.test.ts +++ b/x-pack/plugins/cases/common/api/metrics/case.test.ts @@ -15,7 +15,6 @@ import { describe('Metrics case', () => { describe('SingleCaseMetricsRequestRt', () => { const defaultRequest = { - caseId: 'basic-case-id', features: ['alerts.count', 'lifespan'], }; diff --git a/x-pack/plugins/cases/common/api/metrics/case.ts b/x-pack/plugins/cases/common/api/metrics/case.ts index 7e7fb6a3f4a4c..0e470a74bc4fa 100644 --- a/x-pack/plugins/cases/common/api/metrics/case.ts +++ b/x-pack/plugins/cases/common/api/metrics/case.ts @@ -73,10 +73,6 @@ const AlertUsersMetricsRt = rt.strict({ }); export const SingleCaseMetricsRequestRt = rt.strict({ - /** - * The ID of the case. - */ - caseId: rt.string, /** * The metrics to retrieve. */ diff --git a/x-pack/plugins/cases/server/client/attachments/add.ts b/x-pack/plugins/cases/server/client/attachments/add.ts index d3b4a088f8d4a..9e41d7e832461 100644 --- a/x-pack/plugins/cases/server/client/attachments/add.ts +++ b/x-pack/plugins/cases/server/client/attachments/add.ts @@ -27,8 +27,6 @@ import { validateRegisteredAttachments } from './validators'; export const addComment = async (addArgs: AddArgs, clientArgs: CasesClientArgs): Promise => { const { comment, caseId } = addArgs; - const query = decodeWithExcessOrThrow(CommentRequestRt)(comment); - const { logger, authorization, @@ -36,8 +34,11 @@ export const addComment = async (addArgs: AddArgs, clientArgs: CasesClientArgs): externalReferenceAttachmentTypeRegistry, } = clientArgs; - decodeCommentRequest(comment, externalReferenceAttachmentTypeRegistry); try { + const query = decodeWithExcessOrThrow(CommentRequestRt)(comment); + + decodeCommentRequest(comment, externalReferenceAttachmentTypeRegistry); + const savedObjectID = SavedObjectsUtils.generateId(); await authorization.ensureAuthorized({ diff --git a/x-pack/plugins/cases/server/client/attachments/bulk_create.ts b/x-pack/plugins/cases/server/client/attachments/bulk_create.ts index 7dc6fc8fc54cf..b8986b950008d 100644 --- a/x-pack/plugins/cases/server/client/attachments/bulk_create.ts +++ b/x-pack/plugins/cases/server/client/attachments/bulk_create.ts @@ -20,19 +20,12 @@ import { Operations } from '../../authorization'; import type { BulkCreateArgs } from './types'; import { validateRegisteredAttachments } from './validators'; -/** - * Bulk create attachments to a case. - * - * @ignore - */ export const bulkCreate = async ( args: BulkCreateArgs, clientArgs: CasesClientArgs ): Promise => { const { attachments, caseId } = args; - decodeWithExcessOrThrow(BulkCreateCommentRequestRt)(attachments); - const { logger, authorization, @@ -40,16 +33,18 @@ export const bulkCreate = async ( persistableStateAttachmentTypeRegistry, } = clientArgs; - attachments.forEach((attachment) => { - decodeCommentRequest(attachment, externalReferenceAttachmentTypeRegistry); - validateRegisteredAttachments({ - query: attachment, - persistableStateAttachmentTypeRegistry, - externalReferenceAttachmentTypeRegistry, + try { + decodeWithExcessOrThrow(BulkCreateCommentRequestRt)(attachments); + + attachments.forEach((attachment) => { + decodeCommentRequest(attachment, externalReferenceAttachmentTypeRegistry); + validateRegisteredAttachments({ + query: attachment, + persistableStateAttachmentTypeRegistry, + externalReferenceAttachmentTypeRegistry, + }); }); - }); - try { const [attachmentsWithIds, entities]: [Array<{ id: string } & CommentRequest>, OwnerEntity[]] = attachments.reduce<[Array<{ id: string } & CommentRequest>, OwnerEntity[]]>( ([a, e], attachment) => { diff --git a/x-pack/plugins/cases/server/client/attachments/get.test.tsx b/x-pack/plugins/cases/server/client/attachments/get.test.ts similarity index 59% rename from x-pack/plugins/cases/server/client/attachments/get.test.tsx rename to x-pack/plugins/cases/server/client/attachments/get.test.ts index c289b4b8f6edb..250cfa9f0b252 100644 --- a/x-pack/plugins/cases/server/client/attachments/get.test.tsx +++ b/x-pack/plugins/cases/server/client/attachments/get.test.ts @@ -18,9 +18,9 @@ describe('get', () => { it('Invalid total items results in error', async () => { await expect(() => - findComment({ caseID: 'mock-id', queryParams: { page: 2, perPage: 9001 } }, clientArgs) - ).rejects.toThrow( - 'The number of documents is too high. Paginating through more than 10,000 documents is not possible.' + findComment({ caseID: 'mock-id', findQueryParams: { page: 2, perPage: 9001 } }, clientArgs) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Failed to find comments case id: mock-id: Error: The number of documents is too high. Paginating through more than 10,000 documents is not possible."` ); }); @@ -28,10 +28,12 @@ describe('get', () => { await expect( findComment( // @ts-expect-error: excess attribute - { caseID: 'mock-id', queryParams: { page: 2, perPage: 9001 }, foo: 'bar' }, + { caseID: 'mock-id', findQueryParams: { page: 2, perPage: 9001, foo: 'bar' } }, clientArgs ) - ).rejects.toThrow('invalid keys "foo"'); + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Failed to find comments case id: mock-id: Error: invalid keys \\"foo\\""` + ); }); }); }); diff --git a/x-pack/plugins/cases/server/client/attachments/get.ts b/x-pack/plugins/cases/server/client/attachments/get.ts index 522ed5804f0d7..62f647434e890 100644 --- a/x-pack/plugins/cases/server/client/attachments/get.ts +++ b/x-pack/plugins/cases/server/client/attachments/get.ts @@ -20,7 +20,7 @@ import type { FindCommentsArgs, GetAllAlertsAttachToCase, GetAllArgs, GetArgs } import { CASE_COMMENT_SAVED_OBJECT, CASE_SAVED_OBJECT } from '../../../common/constants'; import { - FindCommentsArgsRt, + FindCommentsQueryParamsRt, CommentType, CommentsRt, CommentRt, @@ -112,7 +112,7 @@ export const getAllAlertsAttachToCase = async ( * Retrieves the attachments for a case entity. This support pagination. */ export async function find( - data: FindCommentsArgs, + { caseID, findQueryParams }: FindCommentsArgs, clientArgs: CasesClientArgs ): Promise { const { @@ -121,11 +121,11 @@ export async function find( authorization, } = clientArgs; - const { caseID, queryParams } = decodeWithExcessOrThrow(FindCommentsArgsRt)(data); + try { + const queryParams = decodeWithExcessOrThrow(FindCommentsQueryParamsRt)(findQueryParams); - validateFindCommentsPagination(queryParams); + validateFindCommentsPagination(queryParams); - try { const { filter: authorizationFilter, ensureSavedObjectsAreAuthorized } = await authorization.getAuthorizationFilter(Operations.findComments); diff --git a/x-pack/plugins/cases/server/client/attachments/types.ts b/x-pack/plugins/cases/server/client/attachments/types.ts index 5260bb7d37b84..75099cdd9f645 100644 --- a/x-pack/plugins/cases/server/client/attachments/types.ts +++ b/x-pack/plugins/cases/server/client/attachments/types.ts @@ -80,7 +80,7 @@ export interface FindCommentsArgs { /** * Optional parameters for filtering the returned attachments */ - queryParams?: FindCommentsQueryParams; + findQueryParams?: FindCommentsQueryParams; } /** diff --git a/x-pack/plugins/cases/server/client/attachments/update.ts b/x-pack/plugins/cases/server/client/attachments/update.ts index 213d4a86ea242..670e6fccfe66b 100644 --- a/x-pack/plugins/cases/server/client/attachments/update.ts +++ b/x-pack/plugins/cases/server/client/attachments/update.ts @@ -11,6 +11,7 @@ import { CaseCommentModel } from '../../common/models'; import { createCaseError } from '../../common/error'; import { isCommentRequestTypeExternalReference } from '../../../common/utils/attachments'; import type { Case } from '../../../common/api'; +import { CommentPatchRequestRt, decodeWithExcessOrThrow } from '../../../common/api'; import { CASE_SAVED_OBJECT } from '../../../common/constants'; import type { CasesClientArgs } from '..'; import { decodeCommentRequest } from '../utils'; @@ -38,7 +39,7 @@ export async function update( id: queryCommentId, version: queryCommentVersion, ...queryRestAttributes - } = queryParams; + } = decodeWithExcessOrThrow(CommentPatchRequestRt)(queryParams); decodeCommentRequest(queryRestAttributes, externalReferenceAttachmentTypeRegistry); diff --git a/x-pack/plugins/cases/server/client/attachments/validators.test.tsx b/x-pack/plugins/cases/server/client/attachments/validators.test.ts similarity index 100% rename from x-pack/plugins/cases/server/client/attachments/validators.test.tsx rename to x-pack/plugins/cases/server/client/attachments/validators.test.ts diff --git a/x-pack/plugins/cases/server/client/cases/create.test.ts b/x-pack/plugins/cases/server/client/cases/create.test.ts index 648f2bb4c2b05..6bca80528a47a 100644 --- a/x-pack/plugins/cases/server/client/cases/create.test.ts +++ b/x-pack/plugins/cases/server/client/cases/create.test.ts @@ -90,7 +90,9 @@ describe('create', () => { await expect( // @ts-expect-error foo is an invalid field create({ ...theCase, foo: 'bar' }, clientArgs) - ).rejects.toThrowErrorMatchingInlineSnapshot(`"invalid keys \\"foo\\""`); + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Failed to create case: Error: invalid keys \\"foo\\""` + ); }); }); }); diff --git a/x-pack/plugins/cases/server/client/cases/create.ts b/x-pack/plugins/cases/server/client/cases/create.ts index 5320b79e6547b..040e5720cbbbb 100644 --- a/x-pack/plugins/cases/server/client/cases/create.ts +++ b/x-pack/plugins/cases/server/client/cases/create.ts @@ -40,19 +40,19 @@ export const create = async (data: CasePostRequest, clientArgs: CasesClientArgs) authorization: auth, } = clientArgs; - const query = decodeWithExcessOrThrow(CasePostRequestRt)(data); + try { + const query = decodeWithExcessOrThrow(CasePostRequestRt)(data); - if (query.title.length > MAX_TITLE_LENGTH) { - throw Boom.badRequest( - `The length of the title is too long. The maximum length is ${MAX_TITLE_LENGTH}.` - ); - } + if (query.title.length > MAX_TITLE_LENGTH) { + throw Boom.badRequest( + `The length of the title is too long. The maximum length is ${MAX_TITLE_LENGTH}.` + ); + } - if (query.tags.some(isInvalidTag)) { - throw Boom.badRequest('A tag must contain at least one non-space character'); - } + if (query.tags.some(isInvalidTag)) { + throw Boom.badRequest('A tag must contain at least one non-space character'); + } - try { const savedObjectID = SavedObjectsUtils.generateId(); await auth.ensureAuthorized({ diff --git a/x-pack/plugins/cases/server/client/cases/delete.ts b/x-pack/plugins/cases/server/client/cases/delete.ts index a9479e2ab171a..5fbefa1b4405b 100644 --- a/x-pack/plugins/cases/server/client/cases/delete.ts +++ b/x-pack/plugins/cases/server/client/cases/delete.ts @@ -33,6 +33,7 @@ export async function deleteCases(ids: string[], clientArgs: CasesClientArgs): P authorization, fileService, } = clientArgs; + try { const cases = await caseService.getCases({ caseIds: ids }); const entities = new Map(); diff --git a/x-pack/plugins/cases/server/client/cases/update.test.ts b/x-pack/plugins/cases/server/client/cases/update.test.ts index db463b6f22e2b..e51ccab4ca9b9 100644 --- a/x-pack/plugins/cases/server/client/cases/update.test.ts +++ b/x-pack/plugins/cases/server/client/cases/update.test.ts @@ -266,7 +266,9 @@ describe('update', () => { }, clientArgs ) - ).rejects.toThrowErrorMatchingInlineSnapshot(`"invalid keys \\"foo\\""`); + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Failed to update case, ids: [{\\"id\\":\\"mock-id-1\\",\\"version\\":\\"WzAsMV0=\\"}]: Error: invalid keys \\"foo\\""` + ); }); }); }); diff --git a/x-pack/plugins/cases/server/client/cases/update.ts b/x-pack/plugins/cases/server/client/cases/update.ts index b3c725cfcae3d..18564787dedac 100644 --- a/x-pack/plugins/cases/server/client/cases/update.ts +++ b/x-pack/plugins/cases/server/client/cases/update.ts @@ -314,9 +314,9 @@ export const update = async ( authorization, } = clientArgs; - const query = decodeWithExcessOrThrow(CasesPatchRequestRt)(cases); - try { + const query = decodeWithExcessOrThrow(CasesPatchRequestRt)(cases); + const myCases = await caseService.getCases({ caseIds: query.cases.map((q) => q.id), }); diff --git a/x-pack/plugins/cases/server/client/configure/client.ts b/x-pack/plugins/cases/server/client/configure/client.ts index df33ee5c595e6..222407fedecf5 100644 --- a/x-pack/plugins/cases/server/client/configure/client.ts +++ b/x-pack/plugins/cases/server/client/configure/client.ts @@ -30,6 +30,7 @@ import { ConfigurationRt, FindActionConnectorResponseRt, decodeWithExcessOrThrow, + ConfigurationRequestRt, } from '../../../common/api'; import { MAX_CONCURRENT_SEARCHES } from '../../../common/constants'; import { createCaseError } from '../../common/error'; @@ -138,6 +139,7 @@ export async function get( logger, authorization, } = clientArgs; + try { const queryParams = decodeWithExcessOrThrow(GetConfigurationFindRequestRt)(params); @@ -339,7 +341,7 @@ export async function update( } async function create( - configuration: ConfigurationRequest, + configRequest: ConfigurationRequest, clientArgs: CasesClientArgs, casesClientInternal: CasesClientInternal ): Promise { @@ -350,7 +352,11 @@ async function create( user, authorization, } = clientArgs; + try { + const validatedConfigurationRequest = + decodeWithExcessOrThrow(ConfigurationRequestRt)(configRequest); + let error = null; const { filter: authorizationFilter, ensureSavedObjectsAreAuthorized } = @@ -364,7 +370,7 @@ async function create( ); const filter = combineAuthorizedAndOwnerFilter( - configuration.owner, + validatedConfigurationRequest.owner, authorizationFilter, Operations.createConfiguration.savedObjectType ); @@ -399,7 +405,7 @@ async function create( await authorization.ensureAuthorized({ operation: Operations.createConfiguration, - entities: [{ owner: configuration.owner, id: savedObjectID }], + entities: [{ owner: validatedConfigurationRequest.owner, id: savedObjectID }], }); const creationDate = new Date().toISOString(); @@ -408,22 +414,22 @@ async function create( try { mappings = ( await casesClientInternal.configuration.createMappings({ - connector: configuration.connector, - owner: configuration.owner, + connector: validatedConfigurationRequest.connector, + owner: validatedConfigurationRequest.owner, refresh: false, }) ).mappings; } catch (e) { error = e.isBoom ? e.output.payload.message - : `Error creating mapping for ${configuration.connector.name}`; + : `Error creating mapping for ${validatedConfigurationRequest.connector.name}`; } const post = await caseConfigureService.post({ unsecuredSavedObjectsClient, attributes: { - ...configuration, - connector: configuration.connector, + ...validatedConfigurationRequest, + connector: validatedConfigurationRequest.connector, created_at: creationDate, created_by: user, updated_at: null, diff --git a/x-pack/plugins/cases/server/client/metrics/client.ts b/x-pack/plugins/cases/server/client/metrics/client.ts index bbf85cc2a0184..6744bb99c9c52 100644 --- a/x-pack/plugins/cases/server/client/metrics/client.ts +++ b/x-pack/plugins/cases/server/client/metrics/client.ts @@ -10,7 +10,6 @@ import type { CasesMetricsRequest, CasesStatusRequest, CasesStatusResponse, - SingleCaseMetricsRequest, CasesMetricsResponse, } from '../../../common/api'; import type { CasesClient } from '../client'; @@ -19,12 +18,13 @@ import type { CasesClientArgs } from '../types'; import { getStatusTotalsByType } from './get_status_totals'; import { getCaseMetrics } from './get_case_metrics'; import { getCasesMetrics } from './get_cases_metrics'; +import type { GetCaseMetricsParams } from './types'; /** * API for interacting with the metrics. */ export interface MetricsSubClient { - getCaseMetrics(params: SingleCaseMetricsRequest): Promise; + getCaseMetrics(params: GetCaseMetricsParams): Promise; getCasesMetrics(params: CasesMetricsRequest): Promise; /** * Retrieves the total number of open, closed, and in-progress cases. @@ -42,7 +42,7 @@ export const createMetricsSubClient = ( casesClient: CasesClient ): MetricsSubClient => { const casesSubClient: MetricsSubClient = { - getCaseMetrics: (params: SingleCaseMetricsRequest) => + getCaseMetrics: (params: GetCaseMetricsParams) => getCaseMetrics(params, casesClient, clientArgs), getCasesMetrics: (params: CasesMetricsRequest) => getCasesMetrics(params, casesClient, clientArgs), diff --git a/x-pack/plugins/cases/server/client/metrics/get_case_metrics.ts b/x-pack/plugins/cases/server/client/metrics/get_case_metrics.ts index 0337c076e13c7..bde457ce4e8af 100644 --- a/x-pack/plugins/cases/server/client/metrics/get_case_metrics.ts +++ b/x-pack/plugins/cases/server/client/metrics/get_case_metrics.ts @@ -6,25 +6,36 @@ */ import { merge } from 'lodash'; -import type { SingleCaseMetricsRequest, SingleCaseMetricsResponse } from '../../../common/api'; -import { SingleCaseMetricsResponseRt } from '../../../common/api'; +import type { SingleCaseMetricsResponse } from '../../../common/api'; +import { + SingleCaseMetricsResponseRt, + SingleCaseMetricsRequestRt, + decodeWithExcessOrThrow, +} from '../../../common/api'; import { Operations } from '../../authorization'; import { createCaseError } from '../../common/error'; import type { CasesClient } from '../client'; import type { CasesClientArgs } from '../types'; +import type { GetCaseMetricsParams } from './types'; import { buildHandlers } from './utils'; import { decodeOrThrow } from '../../../common/api/runtime_types'; export const getCaseMetrics = async ( - params: SingleCaseMetricsRequest, + { caseId, features }: GetCaseMetricsParams, casesClient: CasesClient, clientArgs: CasesClientArgs ): Promise => { const { logger } = clientArgs; try { - await checkAuthorization(params, clientArgs); - const handlers = buildHandlers(params, casesClient, clientArgs); + const queryParams = decodeWithExcessOrThrow(SingleCaseMetricsRequestRt)({ features }); + + await checkAuthorization(caseId, clientArgs); + const handlers = buildHandlers( + { caseId, features: queryParams.features }, + casesClient, + clientArgs + ); const computedMetrics = await Promise.all( Array.from(handlers).map(async (handler) => { @@ -40,23 +51,20 @@ export const getCaseMetrics = async ( } catch (error) { throw createCaseError({ logger, - message: `Failed to retrieve metrics within client for case id: ${params.caseId}: ${error}`, + message: `Failed to retrieve metrics within client for case id: ${caseId}: ${error}`, error, }); } }; -const checkAuthorization = async ( - params: SingleCaseMetricsRequest, - clientArgs: CasesClientArgs -) => { +const checkAuthorization = async (caseId: string, clientArgs: CasesClientArgs) => { const { services: { caseService }, authorization, } = clientArgs; const caseInfo = await caseService.getCase({ - id: params.caseId, + id: caseId, }); await authorization.ensureAuthorized({ diff --git a/x-pack/plugins/cases/server/client/metrics/get_cases_metrics.ts b/x-pack/plugins/cases/server/client/metrics/get_cases_metrics.ts index 68986d8294cdf..0222c692b0637 100644 --- a/x-pack/plugins/cases/server/client/metrics/get_cases_metrics.ts +++ b/x-pack/plugins/cases/server/client/metrics/get_cases_metrics.ts @@ -26,9 +26,9 @@ export const getCasesMetrics = async ( ): Promise => { const { logger } = clientArgs; - const queryParams = decodeWithExcessOrThrow(CasesMetricsRequestRt)(params); - try { + const queryParams = decodeWithExcessOrThrow(CasesMetricsRequestRt)(params); + const handlers = buildHandlers(queryParams, casesClient, clientArgs); const computedMetrics = await Promise.all( diff --git a/x-pack/plugins/cases/server/client/metrics/types.ts b/x-pack/plugins/cases/server/client/metrics/types.ts index 829d736919558..a28b3294cccfb 100644 --- a/x-pack/plugins/cases/server/client/metrics/types.ts +++ b/x-pack/plugins/cases/server/client/metrics/types.ts @@ -37,3 +37,8 @@ export interface AllCasesBaseHandlerCommonOptions extends BaseHandlerCommonOptio to?: string; owner?: string | string[]; } + +export interface GetCaseMetricsParams { + caseId: string; + features: string[]; +} diff --git a/x-pack/plugins/cases/server/client/metrics/utils.ts b/x-pack/plugins/cases/server/client/metrics/utils.ts index 90d7b40658456..8fb84c2481297 100644 --- a/x-pack/plugins/cases/server/client/metrics/utils.ts +++ b/x-pack/plugins/cases/server/client/metrics/utils.ts @@ -14,15 +14,15 @@ import { AlertDetails } from './alerts/details'; import { Actions } from './actions'; import { Connectors } from './connectors'; import { Lifespan } from './lifespan'; -import type { MetricsHandler } from './types'; +import type { GetCaseMetricsParams, MetricsHandler } from './types'; import { MTTR } from './all_cases/mttr'; const isSingleCaseMetrics = ( - params: SingleCaseMetricsRequest | CasesMetricsRequest -): params is SingleCaseMetricsRequest => (params as SingleCaseMetricsRequest).caseId != null; + params: GetCaseMetricsParams | CasesMetricsRequest +): params is GetCaseMetricsParams => (params as GetCaseMetricsParams).caseId != null; export const buildHandlers = ( - params: SingleCaseMetricsRequest | CasesMetricsRequest, + params: GetCaseMetricsParams | CasesMetricsRequest, casesClient: CasesClient, clientArgs: CasesClientArgs ): Set> => { diff --git a/x-pack/plugins/cases/server/common/types/case.test.ts b/x-pack/plugins/cases/server/common/types/case.test.ts index 2216b9515425b..e5135d7bd1cd6 100644 --- a/x-pack/plugins/cases/server/common/types/case.test.ts +++ b/x-pack/plugins/cases/server/common/types/case.test.ts @@ -8,64 +8,93 @@ import { omit } from 'lodash'; import { CaseStatuses } from '@kbn/cases-components'; import { ConnectorTypes, CaseSeverity, SECURITY_SOLUTION_OWNER } from '../../../common'; -import { CaseTransformedAttributesRt, getPartialCaseTransformedAttributesRt } from './case'; +import { + CaseTransformedAttributesRt, + getPartialCaseTransformedAttributesRt, + OwnerRt, +} from './case'; +import { decodeOrThrow } from '../../../common/api'; -describe('getPartialCaseTransformedAttributesRt', () => { - const theCaseAttributes = { - closed_at: null, - closed_by: null, - connector: { - id: 'none', - name: 'none', - type: ConnectorTypes.none, - fields: null, - }, - created_at: '2019-11-25T21:54:48.952Z', - created_by: { - full_name: 'elastic', - email: 'testemail@elastic.co', - username: 'elastic', - }, - severity: CaseSeverity.LOW, - duration: null, - description: 'This is a brand new case of a bad meanie defacing data', - external_service: null, - title: 'Super Bad Security Issue', - status: CaseStatuses.open, - tags: ['defacement'], - updated_at: '2019-11-25T21:54:48.952Z', - updated_by: { - full_name: 'elastic', - email: 'testemail@elastic.co', - username: 'elastic', - }, - settings: { - syncAlerts: true, - }, - owner: SECURITY_SOLUTION_OWNER, - assignees: [], - }; - const caseTransformedAttributesProps = CaseTransformedAttributesRt.types.reduce( - (acc, type) => ({ ...acc, ...type.type.props }), - {} - ); +describe('case types', () => { + describe('getPartialCaseTransformedAttributesRt', () => { + const theCaseAttributes = { + closed_at: null, + closed_by: null, + connector: { + id: 'none', + name: 'none', + type: ConnectorTypes.none, + fields: null, + }, + created_at: '2019-11-25T21:54:48.952Z', + created_by: { + full_name: 'elastic', + email: 'testemail@elastic.co', + username: 'elastic', + }, + severity: CaseSeverity.LOW, + duration: null, + description: 'This is a brand new case of a bad meanie defacing data', + external_service: null, + title: 'Super Bad Security Issue', + status: CaseStatuses.open, + tags: ['defacement'], + updated_at: '2019-11-25T21:54:48.952Z', + updated_by: { + full_name: 'elastic', + email: 'testemail@elastic.co', + username: 'elastic', + }, + settings: { + syncAlerts: true, + }, + owner: SECURITY_SOLUTION_OWNER, + assignees: [], + }; + const caseTransformedAttributesProps = CaseTransformedAttributesRt.types.reduce( + (acc, type) => ({ ...acc, ...type.type.props }), + {} + ); - const type = getPartialCaseTransformedAttributesRt(); + const type = getPartialCaseTransformedAttributesRt(); - it.each(Object.keys(caseTransformedAttributesProps))('does not throw if %s is omitted', (key) => { - const theCase = omit(theCaseAttributes, key); - const decodedRes = type.decode(theCase); + it.each(Object.keys(caseTransformedAttributesProps))( + 'does not throw if %s is omitted', + (key) => { + const theCase = omit(theCaseAttributes, key); + const decodedRes = type.decode(theCase); - expect(decodedRes._tag).toEqual('Right'); - // @ts-expect-error: the check above ensures that right exists - expect(decodedRes.right).toEqual(theCase); + expect(decodedRes._tag).toEqual('Right'); + // @ts-expect-error: the check above ensures that right exists + expect(decodedRes.right).toEqual(theCase); + } + ); + + it('removes excess properties', () => { + const decodedRes = type.decode({ description: 'test', 'not-exists': 'excess' }); + + expect(decodedRes._tag).toEqual('Right'); + // @ts-expect-error: the check above ensures that right exists + expect(decodedRes.right).toEqual({ description: 'test' }); + }); }); - it('removes excess properties', () => { - const decodedRes = type.decode({ description: 'test', 'not-exists': 'excess' }); + describe('OwnerRt', () => { + it('strips excess fields from the result', () => { + const res = decodeOrThrow(OwnerRt)({ + owner: 'yes', + created_at: '123', + }); + + expect(res).toStrictEqual({ + owner: 'yes', + }); + }); - expect(decodedRes._tag).toEqual('Right'); - // @ts-expect-error: the check above ensures that right exists - expect(decodedRes.right).toEqual({ description: 'test' }); + it('throws an error when owner is not present', () => { + expect(() => decodeOrThrow(OwnerRt)({})).toThrowErrorMatchingInlineSnapshot( + `"Invalid value \\"undefined\\" supplied to \\"owner\\""` + ); + }); }); }); diff --git a/x-pack/plugins/cases/server/common/types/case.ts b/x-pack/plugins/cases/server/common/types/case.ts index 7de3b51576fd4..fb1f3bf0e971e 100644 --- a/x-pack/plugins/cases/server/common/types/case.ts +++ b/x-pack/plugins/cases/server/common/types/case.ts @@ -7,7 +7,7 @@ import type { SavedObject } from '@kbn/core-saved-objects-server'; import type { Type } from 'io-ts'; -import { exact, partial } from 'io-ts'; +import { exact, partial, strict, string } from 'io-ts'; import type { CaseAttributes } from '../../../common/api'; import { CaseAttributesRt } from '../../../common/api'; import type { ConnectorPersisted } from './connectors'; @@ -64,3 +64,5 @@ export const getPartialCaseTransformedAttributesRt = (): Type; export type CaseSavedObjectTransformed = SavedObject; + +export const OwnerRt = strict({ owner: string }); diff --git a/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts b/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts index d732b0af71e37..005d1b76f54fc 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/find_comments.ts @@ -29,7 +29,7 @@ export const findCommentsRoute = createCasesRoute({ return response.ok({ body: await client.attachments.find({ caseID: request.params.case_id, - queryParams: query, + findQueryParams: query, }), }); } catch (error) { diff --git a/x-pack/plugins/cases/server/routes/api/internal/bulk_delete_file_attachments.ts b/x-pack/plugins/cases/server/routes/api/internal/bulk_delete_file_attachments.ts index a5c6844159968..09b84ee604afc 100644 --- a/x-pack/plugins/cases/server/routes/api/internal/bulk_delete_file_attachments.ts +++ b/x-pack/plugins/cases/server/routes/api/internal/bulk_delete_file_attachments.ts @@ -11,7 +11,10 @@ import { INTERNAL_DELETE_FILE_ATTACHMENTS_URL } from '../../../../common/constan import { createCasesRoute } from '../create_cases_route'; import { createCaseError } from '../../../common/error'; import { escapeHatch } from '../utils'; -import type { BulkDeleteFileAttachmentsRequest } from '../../../../common/api'; +import { + BulkDeleteFileAttachmentsRequestRt, + decodeWithExcessOrThrow, +} from '../../../../common/api'; export const bulkDeleteFileAttachments = createCasesRoute({ method: 'post', @@ -27,7 +30,7 @@ export const bulkDeleteFileAttachments = createCasesRoute({ const caseContext = await context.cases; const client = await caseContext.getCasesClient(); - const requestBody = request.body as BulkDeleteFileAttachmentsRequest; + const requestBody = decodeWithExcessOrThrow(BulkDeleteFileAttachmentsRequestRt)(request.body); await client.attachments.bulkDeleteFileAttachments({ caseId: request.params.case_id, diff --git a/x-pack/plugins/cases/server/routes/api/internal/bulk_get_attachments.ts b/x-pack/plugins/cases/server/routes/api/internal/bulk_get_attachments.ts index 8f72a42b91b41..3465d25960762 100644 --- a/x-pack/plugins/cases/server/routes/api/internal/bulk_get_attachments.ts +++ b/x-pack/plugins/cases/server/routes/api/internal/bulk_get_attachments.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { BulkGetAttachmentsRequest } from '../../../../common/api'; +import { BulkGetAttachmentsRequestRt, decodeWithExcessOrThrow } from '../../../../common/api'; import { INTERNAL_BULK_GET_ATTACHMENTS_URL } from '../../../../common/constants'; import { createCaseError } from '../../../common/error'; @@ -26,12 +26,13 @@ export const bulkGetAttachmentsRoute = createCasesRoute({ try { const caseContext = await context.cases; const client = await caseContext.getCasesClient(); - const body = request.body as BulkGetAttachmentsRequest; + + const requestBody = decodeWithExcessOrThrow(BulkGetAttachmentsRequestRt)(request.body); return response.ok({ body: await client.attachments.bulkGet({ caseID: request.params.case_id, - attachmentIDs: body.ids, + attachmentIDs: requestBody.ids, }), }); } catch (error) { diff --git a/x-pack/plugins/cases/server/services/cases/index.test.ts b/x-pack/plugins/cases/server/services/cases/index.test.ts index 5679c532502d7..47649adf75a8a 100644 --- a/x-pack/plugins/cases/server/services/cases/index.test.ts +++ b/x-pack/plugins/cases/server/services/cases/index.test.ts @@ -13,10 +13,10 @@ * connector.id. */ -import { omit } from 'lodash'; +import { omit, unset } from 'lodash'; import type { CaseAttributes, CaseConnector, CaseFullExternalService } from '../../../common/api'; import { CaseSeverity, CaseStatuses } from '../../../common/api'; -import { CASE_SAVED_OBJECT } from '../../../common/constants'; +import { CASE_SAVED_OBJECT, SECURITY_SOLUTION_OWNER } from '../../../common/constants'; import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import type { SavedObject, @@ -1882,6 +1882,48 @@ describe('CasesService', () => { 'external_service' ); + describe('getCaseIdsByAlertId', () => { + it('strips excess fields', async () => { + const findMockReturn = createSOFindResponse([createFindSO({ caseId: '2' })]); + unsecuredSavedObjectsClient.find.mockResolvedValue(findMockReturn); + + const res = await service.getCaseIdsByAlertId({ alertId: '1' }); + expect(res).toStrictEqual({ + saved_objects: [ + { + id: '2', + score: 0, + references: [], + type: CASE_SAVED_OBJECT, + attributes: { owner: SECURITY_SOLUTION_OWNER }, + }, + ], + total: 1, + per_page: 1, + page: 1, + }); + }); + + it('throws an error when the owner field is not present', async () => { + const findMockReturn = createSOFindResponse([createFindSO({ caseId: '2' })]); + unset(findMockReturn, 'saved_objects[0].attributes.owner'); + unsecuredSavedObjectsClient.find.mockResolvedValue(findMockReturn); + + await expect( + service.getCaseIdsByAlertId({ alertId: '1' }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid value \\"undefined\\" supplied to \\"owner\\""` + ); + }); + + it('does not throw an error when the owner field exists', async () => { + const findMockReturn = createSOFindResponse([createFindSO({ caseId: '2' })]); + unsecuredSavedObjectsClient.find.mockResolvedValue(findMockReturn); + + await expect(service.getCaseIdsByAlertId({ alertId: '1' })).resolves.not.toThrow(); + }); + }); + describe('getCase', () => { it('decodes correctly', async () => { unsecuredSavedObjectsClient.get.mockResolvedValue(createCaseSavedObjectResponse()); @@ -1902,13 +1944,67 @@ describe('CasesService', () => { } ); - // TODO: Unskip when all types are converted to strict - it.skip('strips out excess attributes', async () => { - const theCase = createCaseSavedObjectResponse(); + it('strips out excess attributes', async () => { + const theCase = createCaseSavedObjectResponse({ + connector: createESJiraConnector(), + externalService: null, + }); const attributes = { ...theCase.attributes, 'not-exists': 'not-exists' }; unsecuredSavedObjectsClient.get.mockResolvedValue({ ...theCase, attributes }); - await expect(service.getCase({ id: 'a' })).resolves.toEqual({ attributes }); + await expect(service.getCase({ id: 'a' })).resolves.toMatchInlineSnapshot(` + Object { + "attributes": Object { + "assignees": Array [], + "closed_at": null, + "closed_by": null, + "connector": Object { + "fields": Object { + "issueType": "bug", + "parent": "2", + "priority": "high", + }, + "id": "1", + "name": ".jira", + "type": ".jira", + }, + "created_at": "2019-11-25T21:54:48.952Z", + "created_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + "description": "This is a brand new case of a bad meanie defacing data", + "duration": null, + "external_service": null, + "owner": "securitySolution", + "settings": Object { + "syncAlerts": true, + }, + "severity": "low", + "status": "open", + "tags": Array [ + "defacement", + ], + "title": "Super Bad Security Issue", + "updated_at": "2019-11-25T21:54:48.952Z", + "updated_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "id": "1", + "references": Array [ + Object { + "id": "1", + "name": "connectorId", + "type": "action", + }, + ], + "type": "cases", + } + `); }); }); @@ -1938,8 +2034,7 @@ describe('CasesService', () => { } ); - // TODO: Unskip when all types are converted to strict - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const theCase = createCaseSavedObjectResponse(); const attributes = { ...theCase.attributes, 'not-exists': 'not-exists' }; unsecuredSavedObjectsClient.resolve.mockResolvedValue({ @@ -1947,7 +2042,64 @@ describe('CasesService', () => { outcome: 'exactMatch', }); - await expect(service.getResolveCase({ id: 'a' })).resolves.toEqual({ attributes }); + await expect(service.getResolveCase({ id: 'a' })).resolves.toMatchInlineSnapshot(` + Object { + "outcome": "exactMatch", + "saved_object": Object { + "attributes": Object { + "assignees": Array [], + "closed_at": null, + "closed_by": null, + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "created_at": "2019-11-25T21:54:48.952Z", + "created_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + "description": "This is a brand new case of a bad meanie defacing data", + "duration": null, + "external_service": Object { + "connector_id": "none", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "owner": "securitySolution", + "settings": Object { + "syncAlerts": true, + }, + "severity": "low", + "status": "open", + "tags": Array [ + "defacement", + ], + "title": "Super Bad Security Issue", + "updated_at": "2019-11-25T21:54:48.952Z", + "updated_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "id": "1", + "references": Array [], + "type": "cases", + }, + } + `); }); }); @@ -2065,15 +2217,72 @@ describe('CasesService', () => { } ); - // TODO: Unskip when all types are converted to strict - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const theCase = createCaseSavedObjectResponse(); const attributes = { ...theCase.attributes, 'not-exists': 'not-exists' }; unsecuredSavedObjectsClient.bulkGet.mockResolvedValue({ saved_objects: [{ ...theCase, attributes }], }); - await expect(service.getCases({ caseIds: ['a', 'b'] })).resolves.toEqual({ attributes }); + await expect(service.getCases({ caseIds: ['a', 'b'] })).resolves.toMatchInlineSnapshot(` + Object { + "saved_objects": Array [ + Object { + "attributes": Object { + "assignees": Array [], + "closed_at": null, + "closed_by": null, + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "created_at": "2019-11-25T21:54:48.952Z", + "created_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + "description": "This is a brand new case of a bad meanie defacing data", + "duration": null, + "external_service": Object { + "connector_id": "none", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "owner": "securitySolution", + "settings": Object { + "syncAlerts": true, + }, + "severity": "low", + "status": "open", + "tags": Array [ + "defacement", + ], + "title": "Super Bad Security Issue", + "updated_at": "2019-11-25T21:54:48.952Z", + "updated_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "id": "1", + "references": Array [], + "type": "cases", + }, + ], + } + `); }); }); @@ -2107,8 +2316,7 @@ describe('CasesService', () => { } ); - // TODO: Unskip when all types are converted to strict - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const theCase = createCaseSavedObjectResponse(); const attributes = { ...theCase.attributes, 'not-exists': 'not-exists' }; const findMockReturn = createSOFindResponse([ @@ -2118,7 +2326,123 @@ describe('CasesService', () => { unsecuredSavedObjectsClient.find.mockResolvedValue(findMockReturn); - await expect(service.findCases()).resolves.toEqual({ attributes }); + await expect(service.findCases()).resolves.toMatchInlineSnapshot(` + Object { + "page": 1, + "per_page": 2, + "saved_objects": Array [ + Object { + "attributes": Object { + "assignees": Array [], + "closed_at": null, + "closed_by": null, + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "created_at": "2019-11-25T21:54:48.952Z", + "created_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + "description": "This is a brand new case of a bad meanie defacing data", + "duration": null, + "external_service": Object { + "connector_id": "none", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "owner": "securitySolution", + "settings": Object { + "syncAlerts": true, + }, + "severity": "low", + "status": "open", + "tags": Array [ + "defacement", + ], + "title": "Super Bad Security Issue", + "updated_at": "2019-11-25T21:54:48.952Z", + "updated_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "id": "1", + "references": Array [], + "score": 0, + "type": "cases", + }, + Object { + "attributes": Object { + "assignees": Array [], + "closed_at": null, + "closed_by": null, + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "created_at": "2019-11-25T21:54:48.952Z", + "created_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + "description": "This is a brand new case of a bad meanie defacing data", + "duration": null, + "external_service": Object { + "connector_id": "none", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "owner": "securitySolution", + "settings": Object { + "syncAlerts": true, + }, + "severity": "low", + "status": "open", + "tags": Array [ + "defacement", + ], + "title": "Super Bad Security Issue", + "updated_at": "2019-11-25T21:54:48.952Z", + "updated_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "id": "1", + "references": Array [], + "score": 0, + "type": "cases", + }, + ], + "total": 2, + } + `); }); }); @@ -2150,8 +2474,7 @@ describe('CasesService', () => { } ); - // TODO: Unskip when all types are converted to strict - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const theCase = createCaseSavedObjectResponse(); const attributes = { ...theCase.attributes, 'not-exists': 'not-exists' }; unsecuredSavedObjectsClient.create.mockResolvedValue({ ...theCase, attributes }); @@ -2161,7 +2484,61 @@ describe('CasesService', () => { attributes: createCasePostParams({ connector: createJiraConnector() }), id: '1', }) - ).resolves.toEqual({ attributes }); + ).resolves.toMatchInlineSnapshot(` + Object { + "attributes": Object { + "assignees": Array [], + "closed_at": null, + "closed_by": null, + "connector": Object { + "fields": null, + "id": "none", + "name": "none", + "type": ".none", + }, + "created_at": "2019-11-25T21:54:48.952Z", + "created_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + "description": "This is a brand new case of a bad meanie defacing data", + "duration": null, + "external_service": Object { + "connector_id": "none", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "owner": "securitySolution", + "settings": Object { + "syncAlerts": true, + }, + "severity": "low", + "status": "open", + "tags": Array [ + "defacement", + ], + "title": "Super Bad Security Issue", + "updated_at": "2019-11-25T21:54:48.952Z", + "updated_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + "id": "1", + "references": Array [], + "type": "cases", + } + `); }); }); diff --git a/x-pack/plugins/cases/server/services/cases/index.ts b/x-pack/plugins/cases/server/services/cases/index.ts index 9236a5c68554d..0c1f91f53a075 100644 --- a/x-pack/plugins/cases/server/services/cases/index.ts +++ b/x-pack/plugins/cases/server/services/cases/index.ts @@ -53,6 +53,7 @@ import { CaseTransformedAttributesRt, CasePersistedStatus, getPartialCaseTransformedAttributesRt, + OwnerRt, } from '../../common/types/case'; import type { GetCaseIdsByAlertIdArgs, @@ -134,7 +135,15 @@ export class CasesService { aggs: this.buildCaseIdsAggs(MAX_DOCS_PER_PAGE), filter: combinedFilter, }); - return response; + + const owners: Array> = []; + for (const so of response.saved_objects) { + const validatedAttributes = decodeOrThrow(OwnerRt)(so.attributes); + + owners.push(Object.assign(so, { attributes: validatedAttributes })); + } + + return Object.assign(response, { saved_objects: owners }); } catch (error) { this.log.error(`Error on GET all cases for alert id ${alertId}: ${error}`); throw error; @@ -199,7 +208,7 @@ export class CasesService { [status in CaseStatuses]: number; }> { const cases = await this.unsecuredSavedObjectsClient.find< - CasePersistedAttributes, + unknown, { statuses: { buckets: Array<{ @@ -459,7 +468,7 @@ export class CasesService { this.log.debug(`Attempting to GET all reporters`); const results = await this.unsecuredSavedObjectsClient.find< - CasePersistedAttributes, + unknown, { reporters: { buckets: Array<{ @@ -521,7 +530,7 @@ export class CasesService { this.log.debug(`Attempting to GET all cases`); const results = await this.unsecuredSavedObjectsClient.find< - CasePersistedAttributes, + unknown, { tags: { buckets: Array<{ key: string }> } } >({ type: CASE_SAVED_OBJECT, diff --git a/x-pack/plugins/cases/server/services/user_actions/index.test.ts b/x-pack/plugins/cases/server/services/user_actions/index.test.ts index e9b1d155f5234..0f991a135c5ce 100644 --- a/x-pack/plugins/cases/server/services/user_actions/index.test.ts +++ b/x-pack/plugins/cases/server/services/user_actions/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { set, omit } from 'lodash'; +import { set, omit, unset } from 'lodash'; import { loggerMock } from '@kbn/logging-mocks'; import { savedObjectsClientMock } from '@kbn/core/server/mocks'; import type { @@ -1599,6 +1599,60 @@ describe('CaseUserActionService', () => { const pushes = [{ date: new Date(), connectorId: '123' }]; + describe('getAll', () => { + it('does not throw when the required fields are present', async () => { + unsecuredSavedObjectsClient.find.mockResolvedValue( + createSOFindResponse([{ ...createUserActionSO(), score: 0 }]) + ); + + await expect(service.getAll('1')).resolves.not.toThrow(); + }); + + it('throws when payload does not exist', async () => { + const findMockReturn = createSOFindResponse([{ ...createUserActionSO(), score: 0 }]); + unset(findMockReturn, 'saved_objects[0].attributes.payload'); + + unsecuredSavedObjectsClient.find.mockResolvedValue(findMockReturn); + + await expect(service.getAll('1')).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid value \\"undefined\\" supplied to \\"payload\\""` + ); + }); + + it('strips excess fields', async () => { + unsecuredSavedObjectsClient.find.mockResolvedValue( + createSOFindResponse([ + { + ...createUserActionSO({ + attributesOverrides: { + // @ts-expect-error foo is not a valid field for attributesOverrides + foo: 'bar', + }, + }), + score: 0, + }, + ]) + ); + + const res = await service.getAll('1'); + expect(res).toStrictEqual( + createSOFindResponse([ + { + ...createUserActionSO({ + attributesOverrides: { + // @ts-expect-error these fields are populated by the legacy transformation logic but aren't valid for the override type + action_id: '100', + case_id: '1', + comment_id: null, + }, + }), + score: 0, + }, + ]) + ); + }); + }); + describe('getConnectorFieldsBeforeLatestPush', () => { const getAggregations = ( userAction: SavedObject @@ -1677,7 +1731,7 @@ describe('CaseUserActionService', () => { ); }); - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const userAction = createUserActionSO(); const attributes = { ...userAction.attributes, 'not-exists': 'not-exists' }; const userActionWithExtraAttributes = { ...userAction, attributes, score: 0 }; @@ -1687,9 +1741,38 @@ describe('CaseUserActionService', () => { unsecuredSavedObjectsClient.find.mockResolvedValue({ ...soFindRes, aggregations }); soSerializerMock.rawToSavedObject.mockReturnValue(userActionWithExtraAttributes); - await expect(service.getConnectorFieldsBeforeLatestPush('1', pushes)).resolves.toEqual({ - attributes: userAction.attributes, - }); + await expect(service.getConnectorFieldsBeforeLatestPush('1', pushes)).resolves + .toMatchInlineSnapshot(` + Map { + "servicenow" => Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + } + `); }); }); @@ -1738,16 +1821,41 @@ describe('CaseUserActionService', () => { ); }); - // TODO: Unskip when all types are converted to strict - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const userAction = createUserActionSO(); const attributes = { ...userAction.attributes, 'not-exists': 'not-exists' }; const soFindRes = createSOFindResponse([{ ...userAction, attributes, score: 0 }]); unsecuredSavedObjectsClient.find.mockResolvedValue(soFindRes); - await expect(service.getMostRecentUserAction('123')).resolves.toEqual({ - attributes: userAction.attributes, - }); + await expect(service.getMostRecentUserAction('123')).resolves.toMatchInlineSnapshot(` + Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "score": 0, + "type": "cases-user-actions", + } + `); }); }); @@ -1840,7 +1948,7 @@ describe('CaseUserActionService', () => { ); }); - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const userAction = createUserActionSO(); const pushUserAction = pushConnectorUserAction(); const attributes = { ...userAction.attributes, 'not-exists': 'not-exists' }; @@ -1851,9 +1959,97 @@ describe('CaseUserActionService', () => { unsecuredSavedObjectsClient.find.mockResolvedValue({ ...soFindRes, aggregations }); soSerializerMock.rawToSavedObject.mockReturnValue(userActionWithExtraAttributes); - await expect(service.getCaseConnectorInformation('1')).resolves.toEqual({ - attributes: userAction.attributes, - }); + await expect(service.getCaseConnectorInformation('1')).resolves + .toMatchInlineSnapshot(` + Array [ + Object { + "connectorId": undefined, + "fields": Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + "push": Object { + "mostRecent": Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + "oldest": Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + }, + }, + ] + `); }); }); @@ -1945,21 +2141,143 @@ describe('CaseUserActionService', () => { ); }); - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const userAction = createUserActionSO(); const pushUserAction = pushConnectorUserAction(); const attributes = { ...pushUserAction.attributes, 'not-exists': 'not-exists' }; - const pushActionWithExtraAttributes = { ...userAction, attributes, score: 0 }; + const pushActionWithExtraAttributes = { ...pushUserAction, attributes, score: 0 }; const aggregations = getAggregations(userAction, pushActionWithExtraAttributes); const soFindRes = createSOFindResponse([{ ...userAction, score: 0 }]); unsecuredSavedObjectsClient.find.mockResolvedValue({ ...soFindRes, aggregations }); soSerializerMock.rawToSavedObject.mockReturnValueOnce(userAction); soSerializerMock.rawToSavedObject.mockReturnValueOnce(pushActionWithExtraAttributes); + soSerializerMock.rawToSavedObject.mockReturnValueOnce(pushActionWithExtraAttributes); - await expect(service.getCaseConnectorInformation('1')).resolves.toEqual({ - attributes: userAction.attributes, - }); + await expect(service.getCaseConnectorInformation('1')).resolves + .toMatchInlineSnapshot(` + Array [ + Object { + "connectorId": undefined, + "fields": Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "type": "cases-user-actions", + }, + "push": Object { + "mostRecent": Object { + "attributes": Object { + "action": "push_to_service", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "externalService": Object { + "connector_id": "100", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + }, + "type": "pushed", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + "oldest": Object { + "attributes": Object { + "action": "push_to_service", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "externalService": Object { + "connector_id": "100", + "connector_name": ".jira", + "external_id": "100", + "external_title": "awesome", + "external_url": "http://www.google.com", + "pushed_at": "2019-11-25T21:54:48.952Z", + "pushed_by": Object { + "email": "testemail@elastic.co", + "full_name": "elastic", + "username": "elastic", + }, + }, + }, + "type": "pushed", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + Object { + "id": "100", + "name": "pushConnectorId", + "type": "action", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + }, + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/cases/server/services/user_actions/index.ts b/x-pack/plugins/cases/server/services/user_actions/index.ts index 15e797df5374f..950e8efcf8e8a 100644 --- a/x-pack/plugins/cases/server/services/user_actions/index.ts +++ b/x-pack/plugins/cases/server/services/user_actions/index.ts @@ -5,12 +5,20 @@ * 2.0. */ -import type { SavedObjectsFindResponse, SavedObjectsRawDoc } from '@kbn/core/server'; +import type { + SavedObjectsFindResponse, + SavedObjectsFindResult, + SavedObjectsRawDoc, +} from '@kbn/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { KueryNode } from '@kbn/es-query'; import type { CaseUserActionDeprecatedResponse } from '../../../common/api'; -import { decodeOrThrow, ActionTypes } from '../../../common/api'; +import { + decodeOrThrow, + ActionTypes, + CaseUserActionDeprecatedResponseRt, +} from '../../../common/api'; import { CASE_SAVED_OBJECT, CASE_USER_ACTION_SAVED_OBJECT, @@ -515,10 +523,22 @@ export class CaseUserActionService { sortOrder: 'asc', }); - return legacyTransformFindResponseToExternalModel( + const transformedUserActions = legacyTransformFindResponseToExternalModel( userActions, this.context.persistableStateAttachmentTypeRegistry ); + + const validatedUserActions: Array> = + []; + for (const so of transformedUserActions.saved_objects) { + const validatedAttributes = decodeOrThrow(CaseUserActionDeprecatedResponseRt)( + so.attributes + ); + + validatedUserActions.push(Object.assign(so, { attributes: validatedAttributes })); + } + + return Object.assign(transformedUserActions, { saved_objects: validatedUserActions }); } catch (error) { this.context.log.error(`Error on GET case user action case id: ${caseId}: ${error}`); throw error; @@ -636,7 +656,7 @@ export class CaseUserActionService { public async getCaseUserActionStats({ caseId }: { caseId: string }) { const response = await this.context.unsecuredSavedObjectsClient.find< - UserActionPersistedAttributes, + unknown, UserActionsStatsAggsResult >({ type: CASE_USER_ACTION_SAVED_OBJECT, @@ -680,7 +700,7 @@ export class CaseUserActionService { public async getUsers({ caseId }: { caseId: string }): Promise { const response = await this.context.unsecuredSavedObjectsClient.find< - UserActionPersistedAttributes, + unknown, ParticipantsAggsResult >({ type: CASE_USER_ACTION_SAVED_OBJECT, diff --git a/x-pack/plugins/cases/server/services/user_actions/operations/__snapshots__/find.test.ts.snap b/x-pack/plugins/cases/server/services/user_actions/operations/__snapshots__/find.test.ts.snap new file mode 100644 index 0000000000000..bc070a00dd4ac --- /dev/null +++ b/x-pack/plugins/cases/server/services/user_actions/operations/__snapshots__/find.test.ts.snap @@ -0,0 +1,70 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UserActionsService: Finder Decoding: find strips out excess attributes 1`] = ` +Object { + "page": 1, + "per_page": 1, + "saved_objects": Array [ + Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, + ], + "total": 1, +} +`; + +exports[`UserActionsService: Finder Decoding: findStatusChanges strips out excess attributes 1`] = ` +Array [ + Object { + "attributes": Object { + "action": "create", + "comment_id": null, + "created_at": "abc", + "created_by": Object { + "email": "a", + "full_name": "abc", + "username": "b", + }, + "owner": "securitySolution", + "payload": Object { + "title": "a new title", + }, + "type": "title", + }, + "id": "100", + "references": Array [ + Object { + "id": "1", + "name": "associated-cases", + "type": "cases", + }, + ], + "score": 0, + "type": "cases-user-actions", + }, +] +`; diff --git a/x-pack/plugins/cases/server/services/user_actions/operations/find.test.ts b/x-pack/plugins/cases/server/services/user_actions/operations/find.test.ts index 3a7c5e4c14939..64c07bae741d1 100644 --- a/x-pack/plugins/cases/server/services/user_actions/operations/find.test.ts +++ b/x-pack/plugins/cases/server/services/user_actions/operations/find.test.ts @@ -135,16 +135,13 @@ describe('UserActionsService: Finder', () => { ); }); - // TODO: Unskip when all types are converted to strict - it.skip('strips out excess attributes', async () => { + it('strips out excess attributes', async () => { const userAction = createUserActionSO(); const attributes = { ...userAction.attributes, 'not-exists': 'not-exists' }; const soFindRes = createSOFindResponse([{ ...userAction, attributes, score: 0 }]); method(soFindRes); - await expect(finder[soMethodName]({ caseId: '1' })).resolves.toEqual({ - attributes: userAction.attributes, - }); + await expect(finder[soMethodName]({ caseId: '1' })).resolves.toMatchSnapshot(); }); }); }); diff --git a/x-pack/plugins/cases/server/services/user_profiles/index.ts b/x-pack/plugins/cases/server/services/user_profiles/index.ts index 46400e906d1f6..d01d15f6fce48 100644 --- a/x-pack/plugins/cases/server/services/user_profiles/index.ts +++ b/x-pack/plugins/cases/server/services/user_profiles/index.ts @@ -70,11 +70,11 @@ export class UserProfileService { } public async suggest(request: KibanaRequest): Promise { - const params = decodeWithExcessOrThrow(SuggestUserProfilesRequestRt)(request.body); + try { + const params = decodeWithExcessOrThrow(SuggestUserProfilesRequestRt)(request.body); - const { name, size, owners } = params; + const { name, size, owners } = params; - try { this.validateInitialization(); const licensingService = new LicensingService( @@ -110,7 +110,7 @@ export class UserProfileService { } catch (error) { throw createCaseError({ logger: this.logger, - message: `Failed to retrieve suggested user profiles in service for name: ${name} owners: [${owners}]: ${error}`, + message: `Failed to retrieve suggested user profiles in service: ${error}`, error, }); } diff --git a/x-pack/plugins/cloud_security_posture/public/application/csp_router.test.tsx b/x-pack/plugins/cloud_security_posture/public/application/csp_router.test.tsx index 36499b4d72baa..b4f804b5d20f0 100644 --- a/x-pack/plugins/cloud_security_posture/public/application/csp_router.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/application/csp_router.test.tsx @@ -17,6 +17,9 @@ import { QueryClientProviderProps } from '@tanstack/react-query'; jest.mock('../pages', () => ({ Findings: () =>
Findings
, ComplianceDashboard: () =>
ComplianceDashboard
, + VulnerabilityDashboard: () => ( +
VulnerabilityDashboard
+ ), Rules: () =>
Rules
, Benchmarks: () =>
Benchmarks
, })); @@ -57,6 +60,7 @@ describe('CspRouter', () => { expect(result.queryByTestId('Findings')).toBeInTheDocument(); expect(result.queryByTestId('ComplianceDashboard')).not.toBeInTheDocument(); + expect(result.queryByTestId('VulnerabilityDashboard')).not.toBeInTheDocument(); expect(result.queryByTestId('Benchmarks')).not.toBeInTheDocument(); expect(result.queryByTestId('Rules')).not.toBeInTheDocument(); }); @@ -66,6 +70,18 @@ describe('CspRouter', () => { const result = renderCspRouter(); expect(result.queryByTestId('ComplianceDashboard')).toBeInTheDocument(); + expect(result.queryByTestId('VulnerabilityDashboard')).not.toBeInTheDocument(); + expect(result.queryByTestId('Findings')).not.toBeInTheDocument(); + expect(result.queryByTestId('Benchmarks')).not.toBeInTheDocument(); + expect(result.queryByTestId('Rules')).not.toBeInTheDocument(); + }); + + it('should render the Vulnerability Dashboard', () => { + history.push('/cloud_security_posture/vulnerability_dashboard'); + const result = renderCspRouter(); + + expect(result.queryByTestId('VulnerabilityDashboard')).toBeInTheDocument(); + expect(result.queryByTestId('ComplianceDashboard')).not.toBeInTheDocument(); expect(result.queryByTestId('Findings')).not.toBeInTheDocument(); expect(result.queryByTestId('Benchmarks')).not.toBeInTheDocument(); expect(result.queryByTestId('Rules')).not.toBeInTheDocument(); @@ -78,6 +94,7 @@ describe('CspRouter', () => { expect(result.queryByTestId('Benchmarks')).toBeInTheDocument(); expect(result.queryByTestId('Findings')).not.toBeInTheDocument(); expect(result.queryByTestId('ComplianceDashboard')).not.toBeInTheDocument(); + expect(result.queryByTestId('VulnerabilityDashboard')).not.toBeInTheDocument(); expect(result.queryByTestId('Rules')).not.toBeInTheDocument(); }); @@ -88,6 +105,7 @@ describe('CspRouter', () => { expect(result.queryByTestId('Rules')).toBeInTheDocument(); expect(result.queryByTestId('Findings')).not.toBeInTheDocument(); expect(result.queryByTestId('ComplianceDashboard')).not.toBeInTheDocument(); + expect(result.queryByTestId('VulnerabilityDashboard')).not.toBeInTheDocument(); expect(result.queryByTestId('Benchmarks')).not.toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/cloud_security_posture/public/application/csp_router.tsx b/x-pack/plugins/cloud_security_posture/public/application/csp_router.tsx index 094425707ae8e..75f294215dfb5 100644 --- a/x-pack/plugins/cloud_security_posture/public/application/csp_router.tsx +++ b/x-pack/plugins/cloud_security_posture/public/application/csp_router.tsx @@ -30,6 +30,10 @@ export const CspRouter = ({ securitySolutionContext }: CspRouterProps) => { + diff --git a/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts index fe29c49594acb..1e89c88b1c9e3 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts @@ -19,6 +19,10 @@ const NAV_ITEMS_NAMES = { DASHBOARD: i18n.translate('xpack.csp.navigation.dashboardNavItemLabel', { defaultMessage: 'Cloud Security Posture', }), + VULNERABILITY_DASHBOARD: i18n.translate( + 'xpack.csp.navigation.vulnerabilityDashboardNavItemLabel', + { defaultMessage: 'Cloud Native Vulnerability Management' } + ), FINDINGS: i18n.translate('xpack.csp.navigation.findingsNavItemLabel', { defaultMessage: 'Findings', }), @@ -39,6 +43,11 @@ export const cloudPosturePages: Record = { path: `${CLOUD_SECURITY_POSTURE_BASE_PATH}/dashboard`, id: 'cloud_security_posture-dashboard', }, + vulnerability_dashboard: { + name: NAV_ITEMS_NAMES.VULNERABILITY_DASHBOARD, + path: `${CLOUD_SECURITY_POSTURE_BASE_PATH}/vulnerability_dashboard`, + id: 'cloud_security_posture-vulnerability_dashboard', + }, findings: { name: NAV_ITEMS_NAMES.FINDINGS, path: `${CLOUD_SECURITY_POSTURE_BASE_PATH}/findings`, diff --git a/x-pack/plugins/cloud_security_posture/public/common/navigation/security_solution_links.test.ts b/x-pack/plugins/cloud_security_posture/public/common/navigation/security_solution_links.test.ts index 072776cde5a0c..ae542ba885ec9 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/navigation/security_solution_links.test.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/navigation/security_solution_links.test.ts @@ -14,7 +14,12 @@ const chance = new Chance(); describe('getSecuritySolutionLink', () => { it('gets the correct link properties', () => { - const cspPage = chance.pickone(['dashboard', 'findings', 'benchmarks']); + const cspPage = chance.pickone([ + 'dashboard', + 'findings', + 'benchmarks', + 'vulnerability_dashboard', + ]); const link = getSecuritySolutionLink(cspPage); @@ -26,7 +31,12 @@ describe('getSecuritySolutionLink', () => { describe('getSecuritySolutionNavTab', () => { it('gets the correct nav tab properties', () => { - const cspPage = chance.pickone(['dashboard', 'findings', 'benchmarks']); + const cspPage = chance.pickone([ + 'dashboard', + 'findings', + 'benchmarks', + 'vulnerability_dashboard', + ]); const basePath = chance.word(); const navTab = getSecuritySolutionNavTab(cspPage, basePath); diff --git a/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts b/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts index 8bc47e489e552..b7b1723a16066 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts @@ -14,7 +14,7 @@ export interface CspPageNavigationItem extends CspNavigationItem { id: CloudSecurityPosturePageId; } -export type CspPage = 'dashboard' | 'findings' | 'benchmarks'; +export type CspPage = 'dashboard' | 'vulnerability_dashboard' | 'findings' | 'benchmarks'; export type CspBenchmarksPage = 'rules'; /** @@ -23,6 +23,7 @@ export type CspBenchmarksPage = 'rules'; */ export type CloudSecurityPosturePageId = | 'cloud_security_posture-dashboard' + | 'cloud_security_posture-vulnerability_dashboard' | 'cloud_security_posture-findings' | 'cloud_security_posture-benchmarks' | 'cloud_security_posture-benchmarks-rules'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page_title.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page_title.tsx index 2000ccef578b8..3db7affc2d879 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page_title.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_posture_page_title.tsx @@ -6,14 +6,29 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; -export const CloudPosturePageTitle = ({ title }: { title: string }) => ( +export const CloudPosturePageTitle = ({ title, isBeta }: { title: string; isBeta?: boolean }) => (

{title}

+ {isBeta && ( + + + } + tooltipPosition="bottom" + /> + + )}
); diff --git a/x-pack/plugins/cloud_security_posture/public/components/csp_inline_description_list.tsx b/x-pack/plugins/cloud_security_posture/public/components/csp_inline_description_list.tsx index a14cb92cf5270..e573ff0225274 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/csp_inline_description_list.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/csp_inline_description_list.tsx @@ -17,8 +17,10 @@ const getModifiedTitlesListItems = (listItems: EuiDescriptionListProps['listItem const fontSize = '1rem'; export const CspInlineDescriptionList = ({ + testId, listItems, }: { + testId?: string; listItems: EuiDescriptionListProps['listItems']; }) => { const { euiTheme } = useEuiTheme(); @@ -26,6 +28,7 @@ export const CspInlineDescriptionList = ({ return ( ', () => { }); }); - describe('Resource Tab', () => { + describe('Table Tab', () => { it('displays resource name and id', () => { const { getAllByText } = render(); - userEvent.click(screen.getByTestId('findings_flyout_tab_resource')); + userEvent.click(screen.getByTestId('findings_flyout_tab_table')); getAllByText(mockFindingsHit.resource.name); getAllByText(mockFindingsHit.resource.id); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx index b1b58a107a5e4..e15cc05f0e077 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx @@ -28,7 +28,7 @@ import { i18n } from '@kbn/i18n'; import cisLogoIcon from '../../../assets/icons/cis_logo.svg'; import { CspFinding } from '../../../../common/schemas/csp_finding'; import { CspEvaluationBadge } from '../../../components/csp_evaluation_badge'; -import { ResourceTab } from './resource_tab'; +import { TableTab } from './table_tab'; import { JsonTab } from './json_tab'; import { OverviewTab } from './overview_tab'; import { RuleTab } from './rule_tab'; @@ -51,9 +51,9 @@ const tabs = [ }), }, { - id: 'resource', - title: i18n.translate('xpack.csp.findings.findingsFlyout.resourceTabTitle', { - defaultMessage: 'Resource', + id: 'table', + title: i18n.translate('xpack.csp.findings.findingsFlyout.tableTabTitle', { + defaultMessage: 'Table', }), }, { @@ -109,8 +109,8 @@ const FindingsTab = ({ tab, findings }: { findings: CspFinding; tab: FindingsTab return ; case 'rule': return ; - case 'resource': - return ; + case 'table': + return ; case 'json': return ; default: diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/resource_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/table_tab.tsx similarity index 73% rename from x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/resource_tab.tsx rename to x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/table_tab.tsx index f4e0a5842231f..075291c434592 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/resource_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/table_tab.tsx @@ -17,8 +17,8 @@ import { getFlattenedObject } from '@kbn/std'; import { i18n } from '@kbn/i18n'; import { CspFinding } from '../../../../common/schemas/csp_finding'; -interface ResourceItem { - key: string; // flattened dot notation object path for CspFinding['resource']; +interface FlattenedItem { + key: string; // flattened dot notation object path for CspFinding; value: unknown; } @@ -39,43 +39,43 @@ const getDescriptionDisplay = (value: unknown) => { return {value as string}; }; -const search: EuiInMemoryTableProps['search'] = { +const search: EuiInMemoryTableProps['search'] = { box: { incremental: true, }, }; -const sorting: EuiInMemoryTableProps['sorting'] = { +const sorting: EuiInMemoryTableProps['sorting'] = { sort: { field: 'key', direction: 'asc', }, }; -const pagination: EuiInMemoryTableProps['pagination'] = { +const pagination: EuiInMemoryTableProps['pagination'] = { initialPageSize: 100, showPerPageOptions: false, }; -const columns: EuiInMemoryTableProps['columns'] = [ +const columns: EuiInMemoryTableProps['columns'] = [ { field: 'key', - name: i18n.translate('xpack.csp.flyout.resource.fieldLabel', { defaultMessage: 'Field' }), + name: i18n.translate('xpack.csp.flyout.tableTab.fieldLabel', { defaultMessage: 'Field' }), width: '25%', }, { field: 'value', - name: i18n.translate('xpack.csp.flyout.resource.fieldValueLabel', { defaultMessage: 'Value' }), + name: i18n.translate('xpack.csp.flyout.tableTab.fieldValueLabel', { defaultMessage: 'Value' }), render: (value, record) =>
{getDescriptionDisplay(value)}
, }, ]; -const getFlattenedItems = (resource: CspFinding['resource']) => +const getFlattenedItems = (resource: CspFinding) => Object.entries(getFlattenedObject(resource)).map(([key, value]) => ({ key, value })); -export const ResourceTab = ({ data }: { data: CspFinding }) => ( +export const TableTab = ({ data }: { data: CspFinding }) => ( { }} loading={resourceFindings.isFetching} /> - - - + + + + + } /> - } - /> - + + + + + + + {resourceFindings.data && ( (key: T, value: Serializable, negate export const PageTitle: React.FC = ({ children }) => ( -
- {children} - -
+
{children}
); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/index.ts b/x-pack/plugins/cloud_security_posture/public/pages/index.ts index 6e7ce20953d0c..cc8fcae0a59a0 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/index.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/index.ts @@ -7,6 +7,7 @@ export { Findings } from './findings'; export { Configurations } from './configurations'; -export * from './compliance_dashboard'; +export { ComplianceDashboard } from './compliance_dashboard'; export { Benchmarks } from './benchmarks'; export { Rules } from './rules'; +export { VulnerabilityDashboard } from './vulnerability_dashboard/vulnerability_dashboard'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx index 131380ac5b157..4a068e9aa64eb 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx @@ -12,7 +12,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { LATEST_VULNERABILITIES_INDEX_PATTERN } from '../../../../common/constants'; import { useKibana } from '../../../common/hooks/use_kibana'; import { showErrorToast } from '../../../common/utils/show_error_toast'; -import { MAX_FINDINGS_TO_LOAD } from '../../../common/constants'; import { FindingsBaseEsQuery } from '../../../common/types'; type LatestFindingsRequest = IKibanaSearchRequest; type LatestFindingsResponse = IKibanaSearchResponse>; @@ -24,9 +23,11 @@ interface FindingsAggs { interface VulnerabilitiesQuery extends FindingsBaseEsQuery { sort: estypes.Sort; enabled: boolean; + pageIndex: number; + pageSize: number; } -export const getFindingsQuery = ({ query, sort }: VulnerabilitiesQuery) => ({ +export const getFindingsQuery = ({ query, sort, pageIndex, pageSize }: VulnerabilitiesQuery) => ({ index: LATEST_VULNERABILITIES_INDEX_PATTERN, query: { ...query, @@ -46,7 +47,8 @@ export const getFindingsQuery = ({ query, sort }: VulnerabilitiesQuery) => ({ ], }, }, - size: MAX_FINDINGS_TO_LOAD, + from: pageIndex * pageSize, + size: pageSize, sort, }); @@ -56,7 +58,7 @@ export const useLatestVulnerabilities = (options: VulnerabilitiesQuery) => { notifications: { toasts }, } = useKibana().services; return useQuery( - [LATEST_VULNERABILITIES_INDEX_PATTERN, { params: options }], + [LATEST_VULNERABILITIES_INDEX_PATTERN, options], async () => { const { rawResponse: { hits }, @@ -72,8 +74,9 @@ export const useLatestVulnerabilities = (options: VulnerabilitiesQuery) => { }; }, { - enabled: options.enabled, + staleTime: 5000, keepPreviousData: true, + enabled: options.enabled, onError: (err: Error) => showErrorToast(toasts, err), } ); 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 new file mode 100644 index 0000000000000..cb635dbee52b4 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_styles.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 { useEuiTheme } from '@elastic/eui'; +import { css, keyframes } from '@emotion/css'; + +export const useStyles = () => { + const { euiTheme } = useEuiTheme(); + + const highlight = keyframes` + 0% { background-color: ${euiTheme.colors.warning};} + 50% { background-color: ${euiTheme.colors.emptyShade};} + 75% { background-color: ${euiTheme.colors.warning};} + 100% { background-color: ${euiTheme.colors.emptyShade};} + `; + + const gridStyle = css` + & .euiDataGridHeaderCell__icon { + display: none; + } + & .euiDataGrid__controls { + border-bottom: none; + } + & .euiButtonIcon { + color: ${euiTheme.colors.primary}; + } + & .euiDataGridRowCell { + font-size: ${euiTheme.size.m}; + } + & .euiDataGridRowCell__expandActions > [data-test-subj='euiDataGridCellExpandButton'] { + display: none; + } + & .euiDataGridRowCell__expandFlex { + align-items: center; + } + `; + + const highlightStyle = css` + & [data-test-subj='dataGridColumnSortingButton'] .euiButtonEmpty__text { + animation: ${highlight} 1s ease-out infinite; + color: ${euiTheme.colors.darkestShade}; + } + `; + + return { + highlightStyle, + gridStyle, + }; +}; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts index 6a2e2a22d506d..72211cc778431 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/test_subjects.ts @@ -6,6 +6,8 @@ */ export const FINDINGS_VULNERABILITY_FLYOUT = 'vulnerability_findings_flyout'; +export const FINDINGS_VULNERABILITY_FLYOUT_DESCRIPTION_LIST = + 'vulnerability-flyout-description-list'; export const JSON_TAB_VULNERABILITY_FLYOUT = 'vulnerability_json_tab_flyout'; export const OVERVIEW_TAB_VULNERABILITY_FLYOUT = 'vulnerability_overview_tab_flyout'; export const SEVERITY_STATUS_VULNERABILITY_FLYOUT = 'vulnerability_severity_status_flyout'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/custom_sort_script.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/custom_sort_script.ts index bfec4d965c6b3..bd1cb1df46221 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/custom_sort_script.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/utils/custom_sort_script.ts @@ -5,7 +5,6 @@ * 2.0. */ -export const VULNERABILITY_SEVERITY_FIELD = 'vulnerability.severity'; import { i18n } from '@kbn/i18n'; export const severitySchemaConfig = { @@ -42,3 +41,19 @@ export const severitySortScript = (direction: string) => ({ order: direction, }, }); + +/** + * Generates Painless sorting in case-insensitive manner + */ +export const getCaseInsensitiveSortScript = (field: string, direction: string) => { + return { + _script: { + type: 'string', + order: direction, + script: { + source: `doc["${field}"].value.toLowerCase()`, + lang: 'painless', + }, + }, + }; +}; 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 e7d12968bcadb..f57d1309212b0 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 @@ -15,9 +15,9 @@ import { EuiToolTip, useEuiTheme, } from '@elastic/eui'; -import { css } from '@emotion/react'; +import { cx } from '@emotion/css'; import { DataView } from '@kbn/data-views-plugin/common'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { LOCAL_STORAGE_PAGE_SIZE_FINDINGS_KEY } from '../../common/constants'; import { useCloudPostureTable } from '../../common/hooks/use_cloud_posture_table'; @@ -44,14 +44,17 @@ import { FILTER_IN, FILTER_OUT, SEARCH_BAR_PLACEHOLDER, VULNERABILITIES } from ' import { severitySchemaConfig, severitySortScript, - VULNERABILITY_SEVERITY_FIELD, + getCaseInsensitiveSortScript, } from './utils/custom_sort_script'; -import { usePageSlice } from '../../common/hooks/use_page_slice'; +import { useStyles } from './hooks/use_styles'; const getDefaultQuery = ({ query, filters }: any): any => ({ query, filters, - sort: [{ id: vulnerabilitiesColumns.cvss, direction: 'desc' }], + sort: [ + { id: vulnerabilitiesColumns.severity, direction: 'desc' }, + { id: vulnerabilitiesColumns.cvss, direction: 'desc' }, + ], pageIndex: 0, }); @@ -94,12 +97,31 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { 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 (VULNERABILITY_SEVERITY_FIELD === id) { + if (id === vulnerabilitiesColumns.severity) { return severitySortScript(direction); } + if (id === vulnerabilitiesColumns.package) { + return getCaseInsensitiveSortScript(id, direction); + } return { [id]: direction, @@ -111,15 +133,15 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { query, sort: multiFieldsSort, enabled: !queryError, + pageIndex, + pageSize, }); - const slicedPage = usePageSlice(data?.page, pageIndex, pageSize); - const invalidIndex = -1; const selectedVulnerability = useMemo(() => { - return slicedPage[urlQuery.vulnerabilityIndex]; - }, [slicedPage, urlQuery.vulnerabilityIndex]); + return data?.page[urlQuery.vulnerabilityIndex]; + }, [data?.page, urlQuery.vulnerabilityIndex]); const onCloseFlyout = () => { setUrlQuery({ @@ -129,7 +151,7 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { const onOpenFlyout = useCallback( (vulnerabilityRow: VulnerabilityRecord) => { - const vulnerabilityIndex = slicedPage.findIndex( + const vulnerabilityIndex = data?.page.findIndex( (vulnerabilityRecord: VulnerabilityRecord) => vulnerabilityRecord.vulnerability?.id === vulnerabilityRow.vulnerability?.id && vulnerabilityRecord.resource?.id === vulnerabilityRow.resource?.id && @@ -142,7 +164,7 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { vulnerabilityIndex, }); }, - [setUrlQuery, slicedPage] + [setUrlQuery, data?.page] ); const { isLastLimitedPage, limitedTotalItemCount } = useLimitProperties({ @@ -154,6 +176,8 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { 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; } @@ -166,9 +190,12 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { if (columnId === vulnerabilitiesColumns.severity) { return vulnerabilityRow.vulnerability.severity; } - if (columnId === vulnerabilitiesColumns.package_version) { + 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; } @@ -176,7 +203,9 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { const cellActions: EuiDataGridColumnCellAction[] = [ ({ Component, rowIndex, columnId }) => { - const value = getColumnIdValue(rowIndex, columnId); + const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; + + const value = getColumnIdValue(rowIndexFromPage, columnId); if (!value) return null; return ( @@ -218,7 +247,9 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { ); }, ({ Component, rowIndex, columnId }) => { - const value = getColumnIdValue(rowIndex, columnId); + const rowIndexFromPage = rowIndex > pageSize - 1 ? rowIndex % pageSize : rowIndex; + + const value = getColumnIdValue(rowIndexFromPage, columnId); if (!value) return null; return ( @@ -248,7 +279,7 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { filters: urlQuery.filters, dataView, field: columnId, - value: getColumnIdValue(rowIndex, columnId), + value, negate: true, }), }); @@ -262,12 +293,39 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { ]; return getVulnerabilitiesColumnsGrid(cellActions); - }, [data?.page, dataView, setUrlQuery, urlQuery.filters]); + }, [data?.page, dataView, pageSize, setUrlQuery, urlQuery.filters]); + + const flyoutVulnerabilityIndex = urlQuery?.vulnerabilityIndex; + + const selectedVulnerabilityIndex = flyoutVulnerabilityIndex + pageIndex * pageSize; const renderCellValue = useMemo(() => { - return ({ rowIndex, columnId }: EuiDataGridCellValueElementProps) => { - const vulnerabilityRow = data?.page[rowIndex] as VulnerabilityRecord; + 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; @@ -283,10 +341,13 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { ); } if (columnId === vulnerabilitiesColumns.vulnerability) { - return vulnerabilityRow.vulnerability.id || ''; + return <>{vulnerabilityRow.vulnerability?.id}; } if (columnId === vulnerabilitiesColumns.cvss) { - if (!vulnerabilityRow.vulnerability.score?.base) { + if ( + !vulnerabilityRow.vulnerability.score?.base || + !vulnerabilityRow.vulnerability.score?.version + ) { return null; } return ( @@ -297,7 +358,7 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { ); } if (columnId === vulnerabilitiesColumns.resource) { - return vulnerabilityRow.resource?.name || null; + return <>{vulnerabilityRow.resource?.name}; } if (columnId === vulnerabilitiesColumns.severity) { if (!vulnerabilityRow.vulnerability.severity) { @@ -305,27 +366,29 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { } return ; } - if (columnId === vulnerabilitiesColumns.package_version) { - return ( - <> - {vulnerabilityRow.vulnerability?.package?.name}{' '} - {vulnerabilityRow.vulnerability?.package?.version} - - ); + + if (columnId === vulnerabilitiesColumns.package) { + return <>{vulnerabilityRow.vulnerability?.package?.name}; + } + if (columnId === vulnerabilitiesColumns.version) { + return <>{vulnerabilityRow.vulnerability?.package?.version}; } if (columnId === vulnerabilitiesColumns.fix_version) { - if (!vulnerabilityRow.vulnerability.package?.fixed_version) { - return null; - } - return ( - <> - {vulnerabilityRow.vulnerability.package?.name}{' '} - {vulnerabilityRow.vulnerability.package.fixed_version} - - ); + return <>{vulnerabilityRow.vulnerability?.package?.fixed_version}; } + + return null; }; - }, [data?.page, onOpenFlyout]); + + return Cell; + }, [ + data?.page, + euiTheme.colors.highlight, + onOpenFlyout, + pageSize, + selectedVulnerabilityIndex, + isFetching, + ]); const onPaginateFlyout = useCallback( (nextVulnerabilityIndex: number) => { @@ -343,7 +406,6 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { [pageSize, setUrlQuery] ); - const flyoutVulnerabilityIndex = urlQuery?.vulnerabilityIndex; const error = queryError || null; if (error) { @@ -374,38 +436,15 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { ) : ( <> - {isFetching ? ( - - ) : ( - - )} + [data-test-subj='euiDataGridCellExpandButton'] { - display: none; - } - & .euiDataGridRowCell__expandFlex { - align-items: center; - } - `} + className={cx({ [styles.gridStyle]: true }, { [styles.highlightStyle]: showHighlight })} aria-label={VULNERABILITIES} columns={columns} columnVisibility={{ @@ -421,13 +460,15 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { additionalControls: { left: { prepend: ( - - {i18n.translate('xpack.csp.vulnerabilities.totalVulnerabilities', { - defaultMessage: - '{total, plural, one {# Vulnerability} other {# Vulnerabilities}}', - values: { total: data?.total }, - })} - + <> + + {i18n.translate('xpack.csp.vulnerabilities.totalVulnerabilities', { + defaultMessage: + '{total, plural, one {# Vulnerability} other {# Vulnerabilities}}', + values: { total: data?.total }, + })} + + ), }, }, @@ -440,8 +481,8 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { header: 'underline', }} renderCellValue={renderCellValue} - inMemory={{ level: 'pagination' }} - sorting={{ columns: sort, onSort }} + inMemory={{ level: 'enhancements' }} + sorting={{ columns: sort, onSort: onSortHandler }} pagination={{ pageIndex, pageSize, @@ -453,11 +494,12 @@ const VulnerabilitiesContent = ({ dataView }: { dataView: DataView }) => { {isLastLimitedPage && } {showVulnerabilityFlyout && ( )} diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx index 7cb370ced7197..8d4e4eb3ea34a 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_finding_flyout.test.tsx @@ -12,6 +12,7 @@ import { VulnerabilityFindingFlyout } from './vulnerability_finding_flyout'; import { mockVulnerabilityHit } from '../_mocks_/vulnerability.mock'; import { VulnerabilityOverviewTab } from './vulnerability_overview_tab'; import moment from 'moment'; +import { FINDINGS_VULNERABILITY_FLYOUT_DESCRIPTION_LIST } from '../test_subjects'; const onPaginate = jest.fn(); @@ -23,6 +24,7 @@ const TestComponent = ({ ...overrideProps }) => ( totalVulnerabilitiesCount={2} onPaginate={onPaginate} vulnerabilityRecord={mockVulnerabilityHit} + isLoading={false} {...overrideProps} /> @@ -31,12 +33,13 @@ const TestComponent = ({ ...overrideProps }) => ( describe('', () => { describe('Header Info', () => { it('displays text details flyout header info', () => { - const { getAllByText, getByText } = render(); + const { getAllByText, getByText, getByTestId } = render(); getAllByText(mockVulnerabilityHit.vulnerability.id); getByText(mockVulnerabilityHit.vulnerability.description); - getByText( - `${mockVulnerabilityHit.resource?.name} | ${mockVulnerabilityHit.vulnerability.package.name} ${mockVulnerabilityHit.vulnerability.package.version}` + const descriptionList = getByTestId(FINDINGS_VULNERABILITY_FLYOUT_DESCRIPTION_LIST); + expect(descriptionList.textContent).toEqual( + `Resource:${mockVulnerabilityHit.resource?.name}Package:${mockVulnerabilityHit.vulnerability.package.name}Version:${mockVulnerabilityHit.vulnerability.package.version}` ); getByText(mockVulnerabilityHit.vulnerability.severity); }); @@ -46,7 +49,7 @@ describe('', () => { it('show display Vulnerability JSON Tab', () => { const { getAllByText } = render(); - userEvent.click(screen.getByTestId(`vulnerability-finding-flyout-tab-json`)); + userEvent.click(screen.getByTestId(`vulnerability-finding-flyout-tab-vuln-flyout-json-tab`)); getAllByText('JSON'); }); 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 195c74c803241..0434a6c36677c 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 @@ -7,6 +7,7 @@ import React, { useMemo, useState } from 'react'; import { + EuiDescriptionListProps, EuiFlexGroup, EuiFlexItem, EuiFlyout, @@ -15,22 +16,57 @@ import { EuiFlyoutHeader, EuiLink, EuiPagination, + EuiSkeletonText, EuiTab, EuiTabs, EuiTitle, } from '@elastic/eui'; - +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { euiThemeVars } from '@kbn/ui-theme'; import { css } from '@emotion/react'; +import { truthy } from '../../../../common/utils/helpers'; +import { CspInlineDescriptionList } from '../../../components/csp_inline_description_list'; import { VulnerabilityOverviewTab } from './vulnerability_overview_tab'; import { VulnerabilityJsonTab } from './vulnerability_json_tab'; import { SeverityStatusBadge } from '../../../components/vulnerability_badges'; import { VulnerabilityRecord } from '../types'; -import { TAB_ID_VULNERABILITY_FLYOUT } from '../test_subjects'; +import { + FINDINGS_VULNERABILITY_FLYOUT_DESCRIPTION_LIST, + TAB_ID_VULNERABILITY_FLYOUT, +} from '../test_subjects'; +import { VulnerabilityTableTab } from './vulnerability_table_tab'; -const overviewTabId = 'overview'; -const jsonTabId = 'json'; +const overviewTabId = 'vuln-flyout-overview-tab'; +const tableTabId = 'vuln-flyout-table-tab'; +const jsonTabId = 'vuln-flyout-json-tab'; + +const getFlyoutDescriptionList = ( + vulnerabilityRecord: VulnerabilityRecord +): EuiDescriptionListProps['listItems'] => + [ + vulnerabilityRecord.resource?.name && { + title: i18n.translate( + 'xpack.csp.vulnerabilities.vulnerabilitiesFindingFlyout.flyoutDescriptionList.resourceTitle', + { defaultMessage: 'Resource' } + ), + description: vulnerabilityRecord.resource.name, + }, + { + title: i18n.translate( + 'xpack.csp.vulnerabilities.vulnerabilitiesFindingFlyout.flyoutDescriptionList.packageTitle', + { defaultMessage: 'Package' } + ), + description: vulnerabilityRecord.vulnerability.package.name, + }, + { + title: i18n.translate( + 'xpack.csp.vulnerabilities.vulnerabilitiesFindingFlyout.flyoutDescriptionList.versionTitle', + { defaultMessage: 'Version' } + ), + description: vulnerabilityRecord.vulnerability.package.version, + }, + ].filter(truthy); export const VulnerabilityFindingFlyout = ({ closeFlyout, @@ -38,16 +74,17 @@ export const VulnerabilityFindingFlyout = ({ totalVulnerabilitiesCount, flyoutIndex, vulnerabilityRecord, + isLoading, }: { closeFlyout: () => void; onPaginate: (pageIndex: number) => void; totalVulnerabilitiesCount: number; flyoutIndex?: number; vulnerabilityRecord: VulnerabilityRecord; + isLoading: boolean; }) => { const [selectedTabId, setSelectedTabId] = useState(overviewTabId); const vulnerability = vulnerabilityRecord?.vulnerability; - const resourceName = vulnerabilityRecord?.resource?.name; const tabs = useMemo( () => [ @@ -61,6 +98,16 @@ export const VulnerabilityFindingFlyout = ({ ), content: , }, + { + id: tableTabId, + name: ( + + ), + content: , + }, { id: jsonTabId, name: ( @@ -98,56 +145,80 @@ export const VulnerabilityFindingFlyout = ({ const vulnerabilityReference = vulnerability?.cvss?.nvd ? nvdWebsite : vulnerability?.reference; + const LOADING_ARIA_LABEL = i18n.translate( + 'xpack.csp.vulnerabilities.vulnerabilityFindingFlyout.loadingAriaLabel', + { defaultMessage: 'Loading' } + ); + return ( - - - - - - - - - - {vulnerability?.id} - - - - -

- {`${resourceName} | ${vulnerability?.package?.name} ${vulnerability?.package?.version}`} -

-
-
-
- - {renderTabs()} - -
+ + + + + + + + + + {vulnerability?.id} + + + + +

+ +

+
+
+
+ + {renderTabs()} + +
+
- {selectedTabContent} + + + {selectedTabContent} + + diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_table_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_table_tab.tsx new file mode 100644 index 0000000000000..a8f5999928d43 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_finding_flyout/vulnerability_table_tab.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 { + EuiCode, + EuiCodeBlock, + EuiInMemoryTable, + EuiInMemoryTableProps, + EuiText, +} from '@elastic/eui'; +import React from 'react'; +import { getFlattenedObject } from '@kbn/std'; +import { i18n } from '@kbn/i18n'; +import { VulnerabilityRecord } from '../types'; + +interface FlattenedItem { + key: string; // flattened dot notation object path for Vulnerability; + value: unknown; +} + +const getDescriptionDisplay = (value: unknown) => { + if (value === undefined) return 'undefined'; + if (typeof value === 'boolean' || value === null) { + return {JSON.stringify(value)}; + } + + if (typeof value === 'object') { + return ( + + {JSON.stringify(value, null, 2)} + + ); + } + + return {value as string}; +}; + +const search: EuiInMemoryTableProps['search'] = { + box: { + incremental: true, + }, +}; + +const sorting: EuiInMemoryTableProps['sorting'] = { + sort: { + field: 'key', + direction: 'asc', + }, +}; + +const pagination: EuiInMemoryTableProps['pagination'] = { + initialPageSize: 100, + showPerPageOptions: false, +}; + +const columns: EuiInMemoryTableProps['columns'] = [ + { + field: 'key', + name: i18n.translate('xpack.csp.vulnerabilities.flyoutTabs.fieldLabel', { + defaultMessage: 'Field', + }), + width: '25%', + }, + { + field: 'value', + name: i18n.translate('xpack.csp.vulnerabilities.flyoutTabs.fieldValueLabel', { + defaultMessage: 'Value', + }), + render: (value: unknown) =>
{getDescriptionDisplay(value)}
, + }, +]; + +const getFlattenedItems = (vulnerabilityRecord: VulnerabilityRecord) => + Object.entries(getFlattenedObject(vulnerabilityRecord)).map(([key, value]) => ({ key, value })); + +export const VulnerabilityTableTab = ({ + vulnerabilityRecord, +}: { + vulnerabilityRecord: VulnerabilityRecord; +}) => ( + +); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_columns.ts b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_columns.ts index bd6a783bd3cc9..ce0b78df31709 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_columns.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/vulnerabilities_table_columns.ts @@ -15,7 +15,8 @@ export const vulnerabilitiesColumns = { cvss: 'vulnerability.score.base', resource: 'resource.name', severity: 'vulnerability.severity', - package_version: 'vulnerability.package.name', + package: 'vulnerability.package.name', + version: 'vulnerability.package.version', fix_version: 'vulnerability.package.fixed_version', }; @@ -78,9 +79,17 @@ export const getVulnerabilitiesColumnsGrid = ( }, { ...defaultColumnProps(), - id: vulnerabilitiesColumns.package_version, - displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.packageAndVersion', { - defaultMessage: 'Package and Version', + id: vulnerabilitiesColumns.package, + displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.package', { + defaultMessage: 'Package', + }), + cellActions, + }, + { + ...defaultColumnProps(), + id: vulnerabilitiesColumns.version, + displayAsText: i18n.translate('xpack.csp.vulnerabilityTable.column.version', { + defaultMessage: 'Version', }), cellActions, }, 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 new file mode 100644 index 0000000000000..a1cc1b39a2b88 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerability_dashboard/vulnerability_dashboard.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiPageHeader } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { VULNERABILITY_DASHBOARD_PAGE_HEADER } from '../compliance_dashboard/test_subjects'; +import { CloudPosturePageTitle } from '../../components/cloud_posture_page_title'; +import { CloudPosturePage } from '../../components/cloud_posture_page'; + +export const VulnerabilityDashboard = () => { + return ( + + + + + } + /> + + ); +}; diff --git a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts index c7b141d6c3878..66e31cbc479b9 100644 --- a/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts +++ b/x-pack/plugins/enterprise_search/common/ml_inference_pipeline/index.ts @@ -57,7 +57,7 @@ export const generateMlInferencePipelineBody = ({ model, pipelineName, }: MlInferencePipelineParams): MlInferencePipeline => { - const inferenceType = Object.keys(model.inference_config)[0]; + const inferenceType = Object.keys(model.inference_config || {})[0]; const pipelineDefinition: MlInferencePipeline = { description: description ?? '', processors: [], diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts index a41ddaa2726fb..c635e6c785319 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/shared/ml_inference/utils.ts @@ -53,7 +53,7 @@ export const NLP_DISPLAY_TITLES: Record = { export const isSupportedMLModel = (model: TrainedModelConfigResponse): boolean => { return ( - Object.keys(model.inference_config).some((key) => NLP_CONFIG_KEYS.includes(key)) || + Object.keys(model.inference_config || {}).some((key) => NLP_CONFIG_KEYS.includes(key)) || model.model_type === TRAINED_MODEL_TYPE.LANG_IDENT ); }; @@ -83,7 +83,8 @@ export const getMLType = (modelTypes: string[]): string => { export const getModelDisplayTitle = (type: string): string | undefined => NLP_DISPLAY_TITLES[type]; -export const isTextExpansionModel = (model: TrainedModel) => model.inference_config.text_expansion; +export const isTextExpansionModel = (model: TrainedModel): boolean => + Boolean(model.inference_config?.text_expansion); /** * Sort function for displaying a list of models. Promotes text_expansion models and sorts the rest by model ID. diff --git a/x-pack/plugins/enterprise_search/server/index_management/setup_indices.test.ts b/x-pack/plugins/enterprise_search/server/index_management/setup_indices.test.ts index 525434e326a3b..48212784aa83e 100644 --- a/x-pack/plugins/enterprise_search/server/index_management/setup_indices.test.ts +++ b/x-pack/plugins/enterprise_search/server/index_management/setup_indices.test.ts @@ -127,6 +127,7 @@ describe('Setup Indices', () => { is_native: { type: 'boolean' }, language: { type: 'keyword' }, last_deleted_document_count: { type: 'long' }, + last_incremental_sync_scheduled_at: { type: 'date' }, last_indexed_document_count: { type: 'long' }, last_seen: { type: 'date' }, last_sync_error: { type: 'keyword' }, @@ -150,6 +151,7 @@ describe('Setup Indices', () => { }, service_type: { type: 'keyword' }, status: { type: 'keyword' }, + sync_cursor: { type: 'object' }, sync_now: { type: 'boolean' }, }, }; @@ -208,6 +210,7 @@ describe('Setup Indices', () => { }, }, service_type: { type: 'keyword' }, + sync_cursor: { type: 'object' }, }, }, created_at: { type: 'date' }, @@ -215,6 +218,7 @@ describe('Setup Indices', () => { error: { type: 'keyword' }, indexed_document_count: { type: 'integer' }, indexed_document_volume: { type: 'integer' }, + job_type: { type: 'keyword' }, last_seen: { type: 'date' }, metadata: { type: 'object' }, started_at: { type: 'date' }, diff --git a/x-pack/plugins/enterprise_search/server/index_management/setup_indices.ts b/x-pack/plugins/enterprise_search/server/index_management/setup_indices.ts index 050b85a872c01..181ffcbeae6fb 100644 --- a/x-pack/plugins/enterprise_search/server/index_management/setup_indices.ts +++ b/x-pack/plugins/enterprise_search/server/index_management/setup_indices.ts @@ -116,6 +116,7 @@ const connectorMappingsProperties: Record = { is_native: { type: 'boolean' }, language: { type: 'keyword' }, last_deleted_document_count: { type: 'long' }, + last_incremental_sync_scheduled_at: { type: 'date' }, last_indexed_document_count: { type: 'long' }, last_seen: { type: 'date' }, last_sync_error: { type: 'keyword' }, @@ -139,6 +140,7 @@ const connectorMappingsProperties: Record = { }, service_type: { type: 'keyword' }, status: { type: 'keyword' }, + sync_cursor: { type: 'object' }, sync_now: { type: 'boolean' }, }; @@ -232,6 +234,7 @@ const indices: IndexDefinition[] = [ }, }, service_type: { type: 'keyword' }, + sync_cursor: { type: 'object' }, }, }, created_at: { type: 'date' }, @@ -239,6 +242,7 @@ const indices: IndexDefinition[] = [ error: { type: 'keyword' }, indexed_document_count: { type: 'integer' }, indexed_document_volume: { type: 'integer' }, + job_type: { type: 'keyword' }, last_seen: { type: 'date' }, metadata: { type: 'object' }, started_at: { type: 'date' }, diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.test.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.test.ts index ed6aa16b26a35..3d68cf81f9e70 100644 --- a/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.test.ts @@ -18,8 +18,8 @@ jest.mock('./fetch_analytics_collection', () => ({ fetchAnalyticsCollections: je describe('add analytics collection lib function', () => { const mockClient = { asCurrentUser: { - transport: { - request: jest.fn(), + searchApplication: { + putBehavioralAnalytics: jest.fn(), }, }, asInternalUser: {}, @@ -34,7 +34,7 @@ describe('add analytics collection lib function', () => { }); it('should add analytics collection', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => ({ + mockClient.asCurrentUser.searchApplication.putBehavioralAnalytics.mockImplementation(() => ({ acknowledged: true, name: `example`, })); @@ -57,9 +57,8 @@ describe('add analytics collection lib function', () => { name: 'example', }); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - method: 'PUT', - path: '/_application/analytics/example', + expect(mockClient.asCurrentUser.searchApplication.putBehavioralAnalytics).toHaveBeenCalledWith({ + name: 'example', }); expect(mockDataViewsService.createAndSave).toHaveBeenCalledWith( @@ -74,7 +73,7 @@ describe('add analytics collection lib function', () => { }); it('should reject if analytics collection already exists', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => + mockClient.asCurrentUser.searchApplication.putBehavioralAnalytics.mockImplementation(() => Promise.reject({ meta: { body: { diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.ts index f85732136d454..49a6903bde4e4 100644 --- a/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.ts +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/add_analytics_collection.ts @@ -22,14 +22,10 @@ interface CollectionsPutResponse { const createAnalyticsCollection = async ( client: IScopedClusterClient, name: string -): Promise => { - const response = await client.asCurrentUser.transport.request({ - method: 'PUT', - path: `/_application/analytics/${name}`, - }); - - return response; -}; +): Promise => + (await client.asCurrentUser.searchApplication.putBehavioralAnalytics({ + name, + })) as CollectionsPutResponse; const createDataView = async ( dataViewsService: DataViewsService, diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.test.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.test.ts index 06a08f1cc8848..0e34e39684906 100644 --- a/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.test.ts @@ -14,8 +14,8 @@ import { deleteAnalyticsCollectionById } from './delete_analytics_collection'; describe('delete analytics collection lib function', () => { const mockClient = { asCurrentUser: { - transport: { - request: jest.fn(), + searchApplication: { + deleteBehavioralAnalytics: jest.fn(), }, }, asInternalUser: {}, @@ -31,14 +31,15 @@ describe('delete analytics collection lib function', () => { deleteAnalyticsCollectionById(mockClient as unknown as IScopedClusterClient, 'example') ).resolves.toBeUndefined(); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - method: 'DELETE', - path: '/_application/analytics/example', + expect( + mockClient.asCurrentUser.searchApplication.deleteBehavioralAnalytics + ).toHaveBeenCalledWith({ + name: 'example', }); }); it('should throw an exception when analytics collection does not exist', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => + mockClient.asCurrentUser.searchApplication.deleteBehavioralAnalytics.mockImplementation(() => Promise.reject({ meta: { body: { diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.ts index c305d1a4b1031..24bdaae91d776 100644 --- a/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.ts +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/delete_analytics_collection.ts @@ -10,16 +10,9 @@ import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import { ErrorCode } from '../../../common/types/error_codes'; import { isResourceNotFoundException } from '../../utils/identify_exceptions'; -interface CollectionsDeleteResponse { - acknowledged: boolean; -} - export const deleteAnalyticsCollectionById = async (client: IScopedClusterClient, name: string) => { try { - await client.asCurrentUser.transport.request({ - method: 'DELETE', - path: `/_application/analytics/${name}`, - }); + await client.asCurrentUser.searchApplication.deleteBehavioralAnalytics({ name }); } catch (error) { if (isResourceNotFoundException(error)) { throw new Error(ErrorCode.ANALYTICS_COLLECTION_NOT_FOUND); diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.test.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.test.ts index 83ef91599f554..bc565971bb38f 100644 --- a/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.test.ts @@ -12,8 +12,8 @@ import { fetchAnalyticsCollections } from './fetch_analytics_collection'; describe('fetch analytics collection lib function', () => { const mockClient = { asCurrentUser: { - transport: { - request: jest.fn(), + searchApplication: { + getBehavioralAnalytics: jest.fn(), }, }, asInternalUser: {}, @@ -25,7 +25,7 @@ describe('fetch analytics collection lib function', () => { describe('fetch collections', () => { it('should return a list of analytics collections', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => + mockClient.asCurrentUser.searchApplication.getBehavioralAnalytics.mockImplementation(() => Promise.resolve({ example: { event_data_stream: { @@ -50,7 +50,7 @@ describe('fetch analytics collection lib function', () => { describe('fetch collection by Id', () => { it('should fetch analytics collection by Id', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => + mockClient.asCurrentUser.searchApplication.getBehavioralAnalytics.mockImplementation(() => Promise.resolve({ example: { event_data_stream: { diff --git a/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.ts b/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.ts index 8baff2c85de44..09d04caee0281 100644 --- a/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.ts +++ b/x-pack/plugins/enterprise_search/server/lib/analytics/fetch_analytics_collection.ts @@ -12,22 +12,13 @@ import { ErrorCode } from '../../../common/types/error_codes'; import { isResourceNotFoundException } from '../../utils/identify_exceptions'; -interface CollectionsListResponse { - [name: string]: { - event_data_stream: { - name: string; - }; - }; -} - export const fetchAnalyticsCollections = async ( client: IScopedClusterClient, query: string = '' ): Promise => { try { - const collections = await client.asCurrentUser.transport.request({ - method: 'GET', - path: `/_application/analytics/${query}`, + const collections = await client.asCurrentUser.searchApplication.getBehavioralAnalytics({ + name: query, }); return Object.keys(collections).map((value) => { diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/get_ml_model_deployment_status.ts b/x-pack/plugins/enterprise_search/server/lib/ml/get_ml_model_deployment_status.ts index 069395baec777..69c8a5895e37a 100644 --- a/x-pack/plugins/enterprise_search/server/lib/ml/get_ml_model_deployment_status.ts +++ b/x-pack/plugins/enterprise_search/server/lib/ml/get_ml_model_deployment_status.ts @@ -27,10 +27,7 @@ export const getMlModelDeploymentStatus = async ( throw new Error('Machine Learning is not enabled'); } - // TODO: the ts-expect-error below should be removed once the correct typings are - // available in Kibana const modelDetailsRequest: MlGetTrainedModelsRequest = { - // @ts-expect-error @elastic-elasticsearch getTrainedModels types incorrect include: 'definition_status', model_id: modelName, }; @@ -43,8 +40,6 @@ export const getMlModelDeploymentStatus = async ( return getDefaultStatusReturn(MlModelDeploymentState.NotDeployed, modelName); } - // TODO - we can remove this cast to the extension once the new types are available - // in kibana that includes the fully_defined field const firstTrainedModelConfig = modelDetailsResponse.trained_model_configs ? (modelDetailsResponse.trained_model_configs[0] as MlTrainedModelConfigWithDefined) : (undefined as unknown as MlTrainedModelConfigWithDefined); diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.test.ts index f637e5ac9901f..cc59fcf32c2ee 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.test.ts @@ -26,8 +26,8 @@ describe('engines routes', () => { const mockClient = { asCurrentUser: { - transport: { - request: jest.fn(), + searchApplication: { + list: jest.fn(), }, }, }; @@ -49,14 +49,10 @@ describe('engines routes', () => { }); it('GET search applications API creates request', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => ({})); + mockClient.asCurrentUser.searchApplication.list.mockImplementation(() => ({})); const request = { query: {} }; await mockRouter.callRoute({}); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - method: 'GET', - path: '/_application/search_application', - querystring: request.query, - }); + expect(mockClient.asCurrentUser.searchApplication.list).toHaveBeenCalledWith(request.query); expect(mockRouter.response.ok).toHaveBeenCalledWith({ body: {}, }); @@ -85,8 +81,8 @@ describe('engines routes', () => { let mockRouter: MockRouter; const mockClient = { asCurrentUser: { - transport: { - request: jest.fn(), + searchApplication: { + get: jest.fn(), }, }, }; @@ -109,14 +105,13 @@ describe('engines routes', () => { }); it('GET search application API creates request', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => ({})); + mockClient.asCurrentUser.searchApplication.get.mockImplementation(() => ({})); await mockRouter.callRoute({ params: { engine_name: 'engine-name' }, }); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - method: 'GET', - path: '/_application/search_application/engine-name', + expect(mockClient.asCurrentUser.searchApplication.get).toHaveBeenCalledWith({ + name: 'engine-name', }); const mock = jest.fn(); @@ -156,8 +151,8 @@ describe('engines routes', () => { let mockRouter: MockRouter; const mockClient = { asCurrentUser: { - transport: { - request: jest.fn(), + searchApplication: { + put: jest.fn(), }, }, }; @@ -180,7 +175,7 @@ describe('engines routes', () => { }); it('PUT - Upsert API creates request - create', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => ({ + mockClient.asCurrentUser.searchApplication.put.mockImplementation(() => ({ acknowledged: true, })); @@ -193,13 +188,14 @@ describe('engines routes', () => { }, query: { create: true }, }); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - body: { + expect(mockClient.asCurrentUser.searchApplication.put).toHaveBeenCalledWith({ + create: true, + name: 'engine-name', + search_application: { indices: ['test-indices-1'], + name: 'engine-name', + updated_at_millis: expect.any(Number), }, - method: 'PUT', - path: '/_application/search_application/engine-name', - querystring: { create: true }, }); const mock = jest.fn(); const mockResponse = mock({ result: 'created' }); @@ -211,7 +207,7 @@ describe('engines routes', () => { }); }); it('PUT - Upsert API creates request - update', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => ({ + mockClient.asCurrentUser.searchApplication.put.mockImplementation(() => ({ acknowledged: true, })); @@ -223,13 +219,13 @@ describe('engines routes', () => { engine_name: 'engine-name', }, }); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - body: { + expect(mockClient.asCurrentUser.searchApplication.put).toHaveBeenCalledWith({ + name: 'engine-name', + search_application: { indices: ['test-indices-1'], + name: 'engine-name', + updated_at_millis: expect.any(Number), }, - method: 'PUT', - path: '/_application/search_application/engine-name', - querystring: {}, }); const mock = jest.fn(); const mockResponse = mock({ result: 'updated' }); @@ -268,7 +264,7 @@ describe('engines routes', () => { }); it('returns 409 when upsert create search application throws error', async () => { - (mockClient.asCurrentUser.transport.request as jest.Mock).mockRejectedValueOnce({ + (mockClient.asCurrentUser.searchApplication.put as jest.Mock).mockRejectedValueOnce({ meta: { body: { error: { @@ -298,8 +294,8 @@ describe('engines routes', () => { let mockRouter: MockRouter; const mockClient = { asCurrentUser: { - transport: { - request: jest.fn(), + searchApplication: { + delete: jest.fn(), }, }, }; @@ -322,7 +318,7 @@ describe('engines routes', () => { }); it('Delete API creates request', async () => { - mockClient.asCurrentUser.transport.request.mockImplementation(() => ({ + mockClient.asCurrentUser.searchApplication.delete.mockImplementation(() => ({ acknowledged: true, })); @@ -331,9 +327,8 @@ describe('engines routes', () => { engine_name: 'engine-name', }, }); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - method: 'DELETE', - path: '_application/search_application/engine-name', + expect(mockClient.asCurrentUser.searchApplication.delete).toHaveBeenCalledWith({ + name: 'engine-name', }); expect(mockRouter.response.ok).toHaveBeenCalledWith({ body: { @@ -448,7 +443,7 @@ describe('engines routes', () => { describe('GET /internal/enterprise_search/engines/{engine_name}/field_capabilities', () => { let mockRouter: MockRouter; const mockClient = { - asCurrentUser: { transport: { request: jest.fn() } }, + asCurrentUser: { searchApplication: { get: jest.fn() } }, }; const mockCore = { elasticsearch: { client: mockClient }, @@ -485,16 +480,17 @@ describe('engines routes', () => { name: 'unit-test', }; - (mockClient.asCurrentUser.transport.request as jest.Mock).mockResolvedValueOnce(engineResult); + (mockClient.asCurrentUser.searchApplication.get as jest.Mock).mockResolvedValueOnce( + engineResult + ); (fetchEngineFieldCapabilities as jest.Mock).mockResolvedValueOnce(fieldCapabilitiesResult); await mockRouter.callRoute({ params: { engine_name: 'unit-test' }, }); - expect(mockClient.asCurrentUser.transport.request).toHaveBeenCalledWith({ - method: 'GET', - path: '/_application/search_application/unit-test', + expect(mockClient.asCurrentUser.searchApplication.get).toHaveBeenCalledWith({ + name: 'unit-test', }); expect(fetchEngineFieldCapabilities).toHaveBeenCalledWith(mockClient, engineResult); expect(mockRouter.response.ok).toHaveBeenCalledWith({ @@ -503,7 +499,7 @@ describe('engines routes', () => { }); }); it('returns 404 when fetch engine throws a not found exception', async () => { - (mockClient.asCurrentUser.transport.request as jest.Mock).mockRejectedValueOnce({ + (mockClient.asCurrentUser.searchApplication.get as jest.Mock).mockRejectedValueOnce({ meta: { body: { error: { @@ -529,7 +525,7 @@ describe('engines routes', () => { }); }); it('returns error when fetch engine returns an unknown error', async () => { - (mockClient.asCurrentUser.transport.request as jest.Mock).mockRejectedValueOnce({ + (mockClient.asCurrentUser.searchApplication.get as jest.Mock).mockRejectedValueOnce({ body: { attributes: { error_code: 'unknown_error', diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.ts index 7d49f5b879a26..64290b3988c88 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/engines.ts @@ -41,13 +41,9 @@ export function registerEnginesRoutes({ log, router }: RouteDependencies) { }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - const engines = await client.asCurrentUser.transport.request( - { - method: 'GET', - path: `/_application/search_application`, - querystring: request.query, - } - ); + const engines = (await client.asCurrentUser.searchApplication.list( + request.query + )) as EnterpriseSearchEnginesResponse; return response.ok({ body: engines }); }) @@ -64,10 +60,9 @@ export function registerEnginesRoutes({ log, router }: RouteDependencies) { }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - const engine = await client.asCurrentUser.transport.request({ - method: 'GET', - path: `/_application/search_application/${request.params.engine_name}`, - }); + const engine = (await client.asCurrentUser.searchApplication.get({ + name: request.params.engine_name, + })) as EnterpriseSearchEngine; const indicesStats = await fetchIndicesStats(client, engine.indices); return response.ok({ body: { ...engine, indices: indicesStats } }); @@ -93,13 +88,16 @@ export function registerEnginesRoutes({ log, router }: RouteDependencies) { elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; try { - const engine = - await client.asCurrentUser.transport.request({ - body: { indices: request.body.indices }, - method: 'PUT', - path: `/_application/search_application/${request.params.engine_name}`, - querystring: request.query, - }); + const engine = (await client.asCurrentUser.searchApplication.put({ + ...request.query, + name: request.params.engine_name, + search_application: { + indices: request.body.indices, + name: request.params.engine_name, + updated_at_millis: Date.now(), + }, + })) as EnterpriseSearchEngineUpsertResponse; + return response.ok({ body: engine }); } catch (error) { if (isVersionConflictEngineException(error)) { @@ -132,10 +130,10 @@ export function registerEnginesRoutes({ log, router }: RouteDependencies) { }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - const engine = await client.asCurrentUser.transport.request({ - method: 'DELETE', - path: `_application/search_application/${request.params.engine_name}`, - }); + const engine = (await client.asCurrentUser.searchApplication.delete({ + name: request.params.engine_name, + })) as AcknowledgedResponseBase; + return response.ok({ body: engine }); }) ); @@ -155,8 +153,8 @@ export function registerEnginesRoutes({ log, router }: RouteDependencies) { elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; const engines = await client.asCurrentUser.search({ - index: request.params.engine_name, ...request.body, + index: request.params.engine_name, }); return response.ok({ body: engines }); }) @@ -193,13 +191,11 @@ export function registerEnginesRoutes({ log, router }: RouteDependencies) { }, elasticsearchErrorHandler(log, async (context, request, response) => { try { - const engineName = decodeURIComponent(request.params.engine_name); const { client } = (await context.core).elasticsearch; - const engine = await client.asCurrentUser.transport.request({ - method: 'GET', - path: `/_application/search_application/${engineName}`, - }); + const engine = (await client.asCurrentUser.searchApplication.get({ + name: request.params.engine_name, + })) as EnterpriseSearchEngine; const data = await fetchEngineFieldCapabilities(client, engine); return response.ok({ diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index 4573b5ef7f21b..1192e59b8af98 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -703,11 +703,7 @@ const updateExistingDataStream = async ({ } // Trigger a rollover if the index mode or source type has changed - if ( - currentIndexMode !== settings?.index?.mode || - // @ts-expect-error Property 'mode' does not exist on type 'MappingSourceField' - currentSourceType !== mappings?._source?.mode - ) { + if (currentIndexMode !== settings?.index?.mode || currentSourceType !== mappings?._source?.mode) { logger.info( `Index mode or source type has changed for ${dataStreamName}, triggering a rollover` ); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts index 6f4724642e9f3..deb8c0a313f30 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts @@ -767,11 +767,13 @@ async function handleTransformInstall({ { logger, additionalResponseStatuses: [400] } ); if (Array.isArray(transformStats.transforms) && transformStats.transforms.length === 1) { - // @ts-expect-error TransformGetTransformStatsTransformStats should have 'health' const transformHealth = transformStats.transforms[0].health; if ( + transformHealth && transformHealth.status === 'red' && + // @ts-expect-error TransformGetTransformStatsTransformStatsHealth should have 'issues' Array.isArray(transformHealth.issues) && + // @ts-expect-error TransformGetTransformStatsTransformStatsHealth should have 'issues' transformHealth.issues.find( (i: { issue: string }) => i.issue === 'Privileges check failed' ) diff --git a/x-pack/plugins/graph/common/content_management/cm_services.ts b/x-pack/plugins/graph/common/content_management/cm_services.ts new file mode 100644 index 0000000000000..74cb11396c764 --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/cm_services.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + ContentManagementServicesDefinition as ServicesDefinition, + Version, +} from '@kbn/object-versioning'; + +// We export the versioned service definition from this file and not the barrel to avoid adding +// the schemas in the "public" js bundle + +import { serviceDefinition as v1 } from './v1/cm_services'; + +export const cmServicesDefinition: { [version: Version]: ServicesDefinition } = { + 1: v1, +}; diff --git a/x-pack/plugins/graph/common/content_management/constants.ts b/x-pack/plugins/graph/common/content_management/constants.ts new file mode 100644 index 0000000000000..415b4860836ae --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/constants.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const LATEST_VERSION = 1; + +export const CONTENT_ID = 'graph'; diff --git a/x-pack/plugins/graph/common/content_management/index.ts b/x-pack/plugins/graph/common/content_management/index.ts new file mode 100644 index 0000000000000..c848adbce1747 --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/index.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { LATEST_VERSION, CONTENT_ID } from './constants'; + +export type { GraphContentType } from './types'; + +export type { + GraphSavedObject, + PartialGraphSavedObject, + GraphSavedObjectAttributes, + GraphGetIn, + GraphGetOut, + GraphCreateIn, + GraphCreateOut, + CreateOptions, + GraphUpdateIn, + GraphUpdateOut, + UpdateOptions, + GraphDeleteIn, + GraphDeleteOut, + GraphSearchIn, + GraphSearchOut, + GraphSearchQuery, +} from './latest'; + +export * as GraphV1 from './v1'; diff --git a/x-pack/plugins/graph/common/content_management/latest.ts b/x-pack/plugins/graph/common/content_management/latest.ts new file mode 100644 index 0000000000000..25300c97a6d2e --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/latest.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 * from './v1'; diff --git a/x-pack/plugins/graph/common/content_management/types.ts b/x-pack/plugins/graph/common/content_management/types.ts new file mode 100644 index 0000000000000..cbb782d35e86a --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/types.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 type GraphContentType = 'graph'; diff --git a/x-pack/plugins/graph/common/content_management/v1/cm_services.ts b/x-pack/plugins/graph/common/content_management/v1/cm_services.ts new file mode 100644 index 0000000000000..68ba43d5a56e3 --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/v1/cm_services.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { schema } from '@kbn/config-schema'; +import type { ContentManagementServicesDefinition as ServicesDefinition } from '@kbn/object-versioning'; + +const apiError = schema.object({ + error: schema.string(), + message: schema.string(), + statusCode: schema.number(), + metadata: schema.object({}, { unknowns: 'allow' }), +}); + +const referenceSchema = schema.object( + { + name: schema.maybe(schema.string()), + type: schema.string(), + id: schema.string(), + }, + { unknowns: 'forbid' } +); + +const referencesSchema = schema.arrayOf(referenceSchema); + +const graphAttributesSchema = schema.object( + { + title: schema.string(), + description: schema.maybe(schema.string()), + version: schema.maybe(schema.number()), + numLinks: schema.number(), + numVertices: schema.number(), + kibanaSavedObjectMeta: schema.maybe(schema.any()), + wsState: schema.maybe(schema.string()), + legacyIndexPatternRef: schema.maybe(schema.string()), + }, + { unknowns: 'forbid' } +); + +const graphSavedObjectSchema = schema.object( + { + id: schema.string(), + type: schema.string(), + version: schema.maybe(schema.string()), + createdAt: schema.maybe(schema.string()), + updatedAt: schema.maybe(schema.string()), + error: schema.maybe(apiError), + attributes: graphAttributesSchema, + references: referencesSchema, + namespaces: schema.maybe(schema.arrayOf(schema.string())), + originId: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } +); + +const getResultSchema = schema.object( + { + item: graphSavedObjectSchema, + meta: schema.object( + { + outcome: schema.oneOf([ + schema.literal('exactMatch'), + schema.literal('aliasMatch'), + schema.literal('conflict'), + ]), + aliasTargetId: schema.maybe(schema.string()), + aliasPurpose: schema.maybe( + schema.oneOf([ + schema.literal('savedObjectConversion'), + schema.literal('savedObjectImport'), + ]) + ), + }, + { unknowns: 'forbid' } + ), + }, + { unknowns: 'forbid' } +); + +const createOptionsSchema = schema.object({ + overwrite: schema.maybe(schema.boolean()), + references: schema.maybe(referencesSchema), +}); + +// Content management service definition. +// We need it for BWC support between different versions of the content +export const serviceDefinition: ServicesDefinition = { + get: { + out: { + result: { + schema: getResultSchema, + }, + }, + }, + create: { + in: { + options: { + schema: createOptionsSchema, + }, + data: { + schema: graphAttributesSchema, + }, + }, + out: { + result: { + schema: schema.object( + { + item: graphSavedObjectSchema, + }, + { unknowns: 'forbid' } + ), + }, + }, + }, + update: { + in: { + options: { + schema: createOptionsSchema, // same schema as "create" + }, + data: { + schema: graphAttributesSchema, + }, + }, + }, + search: { + in: { + options: { + schema: schema.maybe( + schema.object( + { + searchFields: schema.maybe(schema.arrayOf(schema.string())), + types: schema.maybe(schema.arrayOf(schema.string())), + }, + { unknowns: 'forbid' } + ) + ), + }, + }, + }, +}; diff --git a/x-pack/plugins/graph/common/content_management/v1/index.ts b/x-pack/plugins/graph/common/content_management/v1/index.ts new file mode 100644 index 0000000000000..3ce273575aca7 --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/v1/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. + */ + +export type { + GraphSavedObject, + PartialGraphSavedObject, + GraphSavedObjectAttributes, + GraphGetIn, + GraphGetOut, + GraphCreateIn, + GraphCreateOut, + CreateOptions, + GraphUpdateIn, + GraphUpdateOut, + UpdateOptions, + GraphDeleteIn, + GraphDeleteOut, + GraphSearchIn, + GraphSearchOut, + GraphSearchQuery, + Reference, +} from './types'; diff --git a/x-pack/plugins/graph/common/content_management/v1/types.ts b/x-pack/plugins/graph/common/content_management/v1/types.ts new file mode 100644 index 0000000000000..51bb9017c38a9 --- /dev/null +++ b/x-pack/plugins/graph/common/content_management/v1/types.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + GetIn, + CreateIn, + SearchIn, + UpdateIn, + DeleteIn, + DeleteResult, + SearchResult, + GetResult, + CreateResult, + UpdateResult, +} from '@kbn/content-management-plugin/common'; + +import { GraphContentType } from '../types'; + +export interface Reference { + type: string; + id: string; + name: string; +} + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type GraphSavedObjectAttributes = { + title: string; + description?: string; + version?: number; + numVertices: number; + numLinks: number; + wsState?: string; + kibanaSavedObjectMeta?: unknown; + legacyIndexPatternRef: string; +}; + +export interface GraphSavedObject { + id: string; + type: string; + version?: string; + updatedAt?: string; + createdAt?: string; + attributes: GraphSavedObjectAttributes; + references: Reference[]; + namespaces?: string[]; + originId?: string; + error?: { + error: string; + message: string; + statusCode: number; + metadata?: Record; + }; +} + +export type PartialGraphSavedObject = Omit & { + attributes: Partial; + references: Reference[] | undefined; +}; +// ----------- GET -------------- + +export type GraphGetIn = GetIn; + +export type GraphGetOut = GetResult< + GraphSavedObject, + { + outcome: 'exactMatch' | 'aliasMatch' | 'conflict'; + aliasTargetId?: string; + aliasPurpose?: 'savedObjectConversion' | 'savedObjectImport'; + } +>; + +// ----------- CREATE -------------- + +export interface CreateOptions { + /** If a document with the given `id` already exists, overwrite it's contents (default=false). */ + overwrite?: boolean; + /** Array of referenced saved objects. */ + references?: Reference[]; +} + +export type GraphCreateIn = CreateIn; + +export type GraphCreateOut = CreateResult; + +// ----------- UPDATE -------------- + +export interface UpdateOptions { + /** Array of referenced saved objects. */ + references?: Reference[]; +} + +export type GraphUpdateIn = UpdateIn; + +export type GraphUpdateOut = UpdateResult; + +// ----------- DELETE -------------- + +export type GraphDeleteIn = DeleteIn; + +export type GraphDeleteOut = DeleteResult; + +// ----------- SEARCH -------------- + +export interface GraphSearchQuery { + types?: string[]; + searchFields?: string[]; +} + +export type GraphSearchIn = SearchIn; + +export type GraphSearchOut = SearchResult; diff --git a/x-pack/plugins/graph/kibana.jsonc b/x-pack/plugins/graph/kibana.jsonc index 5c85742b492a2..b75a0689bc292 100644 --- a/x-pack/plugins/graph/kibana.jsonc +++ b/x-pack/plugins/graph/kibana.jsonc @@ -19,6 +19,7 @@ "inspector", "savedObjectsManagement", "savedObjectsFinder", + "contentManagement" ], "optionalPlugins": [ "home", diff --git a/x-pack/plugins/graph/public/application.tsx b/x-pack/plugins/graph/public/application.tsx index 90cbc2b88b19f..28b44b804373a 100644 --- a/x-pack/plugins/graph/public/application.tsx +++ b/x-pack/plugins/graph/public/application.tsx @@ -11,7 +11,6 @@ import { ChromeStart, CoreStart, PluginInitializerContext, - SavedObjectsClientContract, ToastsStart, OverlayStart, AppMountParameters, @@ -32,10 +31,10 @@ import { TableListViewKibanaProvider } from '@kbn/content-management-table-list' import './index.scss'; import('./font_awesome'); -import { SavedObjectsStart } from '@kbn/saved-objects-plugin/public'; import { SpacesApi } from '@kbn/spaces-plugin/public'; import { KibanaThemeProvider, toMountPoint } from '@kbn/kibana-react-plugin/public'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { GraphSavePolicy } from './types'; import { graphRouter } from './router'; import { checkLicense } from '../common/check_license'; @@ -60,14 +59,13 @@ export interface GraphDependencies { indexPatterns: DataViewsContract; data: ReturnType; unifiedSearch: UnifiedSearchPublicPluginStart; - savedObjectsClient: SavedObjectsClientContract; + contentClient: ContentClient; addBasePath: (url: string) => string; getBasePath: () => string; storage: Storage; canEditDrillDownUrls: boolean; graphSavePolicy: GraphSavePolicy; overlays: OverlayStart; - savedObjects: SavedObjectsStart; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; uiSettings: IUiSettingsClient; history: ScopedHistory; diff --git a/x-pack/plugins/graph/public/apps/listing_route.tsx b/x-pack/plugins/graph/public/apps/listing_route.tsx index 15f4898b84364..a34a4bc5b591b 100644 --- a/x-pack/plugins/graph/public/apps/listing_route.tsx +++ b/x-pack/plugins/graph/public/apps/listing_route.tsx @@ -41,7 +41,7 @@ export interface ListingRouteProps { } export function ListingRoute({ - deps: { chrome, savedObjectsClient, coreStart, capabilities, addBasePath, uiSettings }, + deps: { chrome, contentClient, coreStart, capabilities, addBasePath, uiSettings }, }: ListingRouteProps) { const listingLimit = uiSettings.get(SAVED_OBJECTS_LIMIT_SETTING); const initialPageSize = uiSettings.get(SAVED_OBJECTS_PER_PAGE_SETTING); @@ -60,7 +60,7 @@ export function ListingRoute({ const findItems = useCallback( (search: string) => { return findSavedWorkspace( - { savedObjectsClient, basePath: coreStart.http.basePath }, + { contentClient, basePath: coreStart.http.basePath }, search, listingLimit ).then(({ total, hits }) => ({ @@ -68,7 +68,7 @@ export function ListingRoute({ hits: hits.map(toTableListViewSavedObject), })); }, - [coreStart.http.basePath, listingLimit, savedObjectsClient] + [coreStart.http.basePath, listingLimit, contentClient] ); const editItem = useCallback( @@ -81,11 +81,11 @@ export function ListingRoute({ const deleteItems = useCallback( async (savedWorkspaces: Array<{ id: string }>) => { await deleteSavedWorkspace( - savedObjectsClient, + contentClient, savedWorkspaces.map((cur) => cur.id!) ); }, - [savedObjectsClient] + [contentClient] ); return ( diff --git a/x-pack/plugins/graph/public/apps/workspace_route.tsx b/x-pack/plugins/graph/public/apps/workspace_route.tsx index 8fcff177d054b..b8ca873a1aa33 100644 --- a/x-pack/plugins/graph/public/apps/workspace_route.tsx +++ b/x-pack/plugins/graph/public/apps/workspace_route.tsx @@ -27,7 +27,7 @@ export const WorkspaceRoute = ({ deps: { toastNotifications, coreStart, - savedObjectsClient, + contentClient, graphSavePolicy, chrome, canEditDrillDownUrls, @@ -108,8 +108,8 @@ export const WorkspaceRoute = ({ notifications: coreStart.notifications, http: coreStart.http, overlays: coreStart.overlays, - savedObjectsClient, savePolicy: graphSavePolicy, + contentClient, changeUrl: (newUrl) => history.push(newUrl), notifyReact: () => setRenderCounter((cur) => cur + 1), chrome, @@ -120,7 +120,7 @@ export const WorkspaceRoute = ({ const loaded = useWorkspaceLoader({ workspaceRef, store, - savedObjectsClient, + contentClient, spaces, coreStart, data, diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/check_for_duplicate_title.ts b/x-pack/plugins/graph/public/helpers/saved_objects_utils/check_for_duplicate_title.ts new file mode 100644 index 0000000000000..ca2bfb359b1f9 --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/check_for_duplicate_title.ts @@ -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 type { OverlayStart } from '@kbn/core/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; +import type { GraphWorkspaceSavedObject } from '../../types'; +import { SAVE_DUPLICATE_REJECTED } from './constants'; +import { findObjectByTitle } from './find_object_by_title'; +import { displayDuplicateTitleConfirmModal } from './display_duplicate_title_confirm_modal'; + +/** + * check for an existing VisSavedObject with the same title in ES + * returns Promise when it's no duplicate, or the modal displaying the warning + * that's there's a duplicate is confirmed, else it returns a rejected Promise + * @param savedObject + * @param isTitleDuplicateConfirmed + * @param onTitleDuplicate + * @param services + */ +export async function checkForDuplicateTitle( + savedObject: Pick, + isTitleDuplicateConfirmed: boolean, + onTitleDuplicate: (() => void) | undefined, + services: { + overlays: OverlayStart; + contentClient: ContentClient; + } +): Promise { + const { overlays, contentClient } = services; + // Don't check for duplicates if user has already confirmed save with duplicate title + if (isTitleDuplicateConfirmed) { + return true; + } + + // Don't check if the user isn't updating the title, otherwise that would become very annoying to have + // to confirm the save every time, except when copyOnSave is true, then we do want to check. + if (savedObject.title === savedObject.lastSavedTitle) { + return true; + } + + const duplicate = await findObjectByTitle(contentClient, savedObject.title); + + if (!duplicate || duplicate.id === savedObject.id) { + return true; + } + + if (onTitleDuplicate) { + onTitleDuplicate(); + return Promise.reject(new Error(SAVE_DUPLICATE_REJECTED)); + } + + // TODO: make onTitleDuplicate a required prop and remove UI components from this class + // Need to leave here until all users pass onTitleDuplicate. + return displayDuplicateTitleConfirmModal(savedObject, overlays); +} diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/confirm_modal_promise.tsx b/x-pack/plugins/graph/public/helpers/saved_objects_utils/confirm_modal_promise.tsx new file mode 100644 index 0000000000000..19e236d4d63fc --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/confirm_modal_promise.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import type { OverlayStart } from '@kbn/core/public'; +import { EuiConfirmModal } from '@elastic/eui'; +import { toMountPoint } from '@kbn/kibana-react-plugin/public'; + +export function confirmModalPromise( + message = '', + title = '', + confirmBtnText = '', + overlays: OverlayStart +): Promise { + return new Promise((resolve, reject) => { + const cancelButtonText = i18n.translate('xpack.graph.confirmModal.cancelButtonLabel', { + defaultMessage: 'Cancel', + }); + + const modal = overlays.openModal( + toMountPoint( + { + modal.close(); + reject(); + }} + onConfirm={() => { + modal.close(); + resolve(true); + }} + confirmButtonText={confirmBtnText} + cancelButtonText={cancelButtonText} + title={title} + > + {message} + + ) + ); + }); +} diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/constants.ts b/x-pack/plugins/graph/public/helpers/saved_objects_utils/constants.ts new file mode 100644 index 0000000000000..0ad25fde77c66 --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/constants.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +/** An error message to be used when the user rejects a confirm overwrite. */ +export const OVERWRITE_REJECTED = i18n.translate('xpack.graph.overwriteRejectedDescription', { + defaultMessage: 'Overwrite confirmation was rejected', +}); + +/** An error message to be used when the user rejects a confirm save with duplicate title. */ +export const SAVE_DUPLICATE_REJECTED = i18n.translate( + 'xpack.graph.saveDuplicateRejectedDescription', + { + defaultMessage: 'Save with duplicate title confirmation was rejected', + } +); diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/display_duplicate_title_confirm_modal.ts b/x-pack/plugins/graph/public/helpers/saved_objects_utils/display_duplicate_title_confirm_modal.ts new file mode 100644 index 0000000000000..68f9bee87fd75 --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/display_duplicate_title_confirm_modal.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 { i18n } from '@kbn/i18n'; +import type { OverlayStart } from '@kbn/core/public'; +import type { GraphWorkspaceSavedObject } from '../../types'; +import { SAVE_DUPLICATE_REJECTED } from './constants'; +import { confirmModalPromise } from './confirm_modal_promise'; + +export function displayDuplicateTitleConfirmModal( + savedObject: Pick, + overlays: OverlayStart +): Promise { + const confirmTitle = i18n.translate('xpack.graph.confirmModal.saveDuplicateConfirmationTitle', { + defaultMessage: `This visualization already exists`, + }); + + const confirmMessage = i18n.translate( + 'xpack.graph.confirmModal.saveDuplicateConfirmationMessage', + { + defaultMessage: `Saving "{name}" creates a duplicate title. Would you like to save anyway?`, + values: { name: savedObject.title }, + } + ); + + const confirmButtonText = i18n.translate('xpack.graph.confirmModal.saveDuplicateButtonLabel', { + defaultMessage: 'Save', + }); + + try { + return confirmModalPromise(confirmMessage, confirmTitle, confirmButtonText, overlays); + } catch { + return Promise.reject(new Error(SAVE_DUPLICATE_REJECTED)); + } +} diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.test.ts b/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.test.ts new file mode 100644 index 0000000000000..8ec7eb24bb818 --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { findObjectByTitle } from './find_object_by_title'; +import { SimpleSavedObject } from '@kbn/core/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; + +const mockFindContent = jest.fn(async () => ({ + pagination: { total: 0 }, + hits: [] as unknown[], +})); +const mockGetContent = jest.fn(async () => ({ + item: { + id: 'test', + references: [ + { + id: 'test', + type: 'index-pattern', + }, + ], + attributes: { + visState: JSON.stringify({ type: 'area' }), + kibanaSavedObjectMeta: { + searchSourceJSON: '{filter: []}', + }, + }, + _version: '1', + }, + meta: { + outcome: 'exact', + alias_target_id: null, + }, +})); +const mockCreateContent = jest.fn(async (input: any) => ({ + item: { + id: 'test', + }, +})); + +const mockUpdateContent = jest.fn(() => ({ + item: { + id: 'test', + }, +})); + +const contentClientMock = { + create: mockCreateContent, + update: mockUpdateContent, + get: mockGetContent, + search: mockFindContent, +} as unknown as ContentClient; + +describe('findObjectByTitle', () => { + beforeEach(() => { + mockFindContent.mockClear(); + }); + + it('returns undefined if title is not provided', async () => { + const match = await findObjectByTitle(contentClientMock, ''); + expect(match).toBeUndefined(); + }); + + it('matches any case', async () => { + const indexPattern = { + attributes: { title: 'foo' }, + } as SimpleSavedObject; + + mockFindContent.mockImplementation(async () => ({ + hits: [indexPattern], + pagination: { total: 1 }, + })); + const match = await findObjectByTitle(contentClientMock, 'FOO'); + expect(match).toEqual(indexPattern); + }); +}); diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.ts b/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.ts new file mode 100644 index 0000000000000..67c75ad4d06a8 --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/find_object_by_title.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ContentClient } from '@kbn/content-management-plugin/public'; +import { CONTENT_ID, GraphSearchIn, GraphSearchOut } from '../../../common/content_management'; + +/** Returns an object matching a given title */ +export async function findObjectByTitle(contentClient: ContentClient, title: string) { + if (!title) { + return; + } + + // Elastic search will return the most relevant results first, which means exact matches should come + // first, and so we shouldn't need to request everything. Using 10 just to be on the safe side. + const response = await contentClient.search({ + contentTypeId: CONTENT_ID, + query: { + text: `"${title}"`, + }, + options: { + searchFields: ['title'], + }, + }); + return response.hits.find((obj) => obj.attributes.title.toLowerCase() === title.toLowerCase()); +} diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/index.ts b/x-pack/plugins/graph/public/helpers/saved_objects_utils/index.ts new file mode 100644 index 0000000000000..210f6abdb1a89 --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { saveWithConfirmation } from './save_with_confirmation'; +export { checkForDuplicateTitle } from './check_for_duplicate_title'; diff --git a/x-pack/plugins/graph/public/helpers/saved_objects_utils/save_with_confirmation.ts b/x-pack/plugins/graph/public/helpers/saved_objects_utils/save_with_confirmation.ts new file mode 100644 index 0000000000000..35bcc6748dacc --- /dev/null +++ b/x-pack/plugins/graph/public/helpers/saved_objects_utils/save_with_confirmation.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { get } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import type { SavedObjectsCreateOptions, OverlayStart } from '@kbn/core/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; +import { CONTENT_ID, GraphCreateIn, GraphCreateOut } from '../../../common/content_management'; +import { OVERWRITE_REJECTED } from './constants'; +import { confirmModalPromise } from './confirm_modal_promise'; +import { GraphSavedObjectAttributes, GraphSavedObject } from '../../../common/content_management'; +import { GraphWorkspaceSavedObject } from '../../types'; + +/** + * Attempts to create the current object using the serialized source. If an object already + * exists, a warning message requests an overwrite confirmation. + * @param source - serialized version of this object what will be indexed into elasticsearch. + * @param savedObject - VisSavedObject + * @param options - options to pass to the saved object create method + * @param services - provides Kibana services savedObjectsClient and overlays + * @returns {Promise} - A promise that is resolved with the objects id if the object is + * successfully indexed. If the overwrite confirmation was rejected, an error is thrown with + * a confirmRejected = true parameter so that case can be handled differently than + * a create or index error. + * @resolved {SimpleSavedObject} + */ +export async function saveWithConfirmation( + source: GraphSavedObjectAttributes, + savedObject: Pick, + options: SavedObjectsCreateOptions, + services: { overlays: OverlayStart; contentClient: ContentClient } +): Promise<{ item: GraphSavedObject }> { + const { overlays, contentClient } = services; + try { + return await contentClient.create({ + contentTypeId: CONTENT_ID, + data: source, + options, + }); + } catch (err) { + // record exists, confirm overwriting + if (get(err, 'res.status') === 409) { + const confirmMessage = i18n.translate( + 'xpack.graph.confirmModal.overwriteConfirmationMessage', + { + defaultMessage: 'Are you sure you want to overwrite {title}?', + values: { title: savedObject.title }, + } + ); + + const title = i18n.translate('xpack.graph.confirmModal.overwriteTitle', { + defaultMessage: 'Overwrite {name}?', + values: { name: savedObject.displayName }, + }); + const confirmButtonText = i18n.translate('xpack.graph.confirmModal.overwriteButtonLabel', { + defaultMessage: 'Overwrite', + }); + + return confirmModalPromise(confirmMessage, title, confirmButtonText, overlays) + .then(() => + contentClient.create({ + contentTypeId: CONTENT_ID, + data: source, + options: { + overwrite: true, + ...options, + }, + }) + ) + .catch(() => Promise.reject(new Error(OVERWRITE_REJECTED))); + } + return await Promise.reject(err); + } +} diff --git a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts index 7d4027c91858f..5c70d4a06d4a1 100644 --- a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts +++ b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.test.ts @@ -6,6 +6,7 @@ */ import { coreMock } from '@kbn/core/public/mocks'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { GraphWorkspaceSavedObject } from '../types'; import { saveSavedWorkspace } from './saved_workspace_utils'; @@ -28,11 +29,9 @@ describe('saved_workspace_utils', () => { savedWorkspace, {}, { - savedObjectsClient: { - ...core.savedObjects.client, - find: jest.fn().mockResolvedValue({ savedObjects: [] }), - create: jest.fn().mockResolvedValue({ id: '456' }), - }, + contentClient: { + create: jest.fn().mockReturnValue(Promise.resolve({ item: { id: '456' } })), + } as unknown as ContentClient, overlays: core.overlays, } ); diff --git a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts index 03e377792f1ac..dffe12bf5e4dd 100644 --- a/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts +++ b/x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts @@ -7,26 +7,31 @@ import { cloneDeep, assign, defaults, forOwn } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { - IBasePath, - OverlayStart, - SavedObjectsClientContract, - SavedObjectAttributes, -} from '@kbn/core/public'; +import { IBasePath, OverlayStart, SavedObjectAttributes } from '@kbn/core/public'; -import { - SavedObjectSaveOpts, - checkForDuplicateTitle, - saveWithConfirmation, - isErrorNonFatal, -} from '@kbn/saved-objects-plugin/public'; +import { SavedObjectSaveOpts, isErrorNonFatal } from '@kbn/saved-objects-plugin/public'; import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; +import { + GraphGetIn, + GraphGetOut, + GraphSearchIn, + GraphSearchOut, + GraphDeleteIn, + GraphDeleteOut, + GraphCreateIn, + GraphCreateOut, + GraphSavedObjectAttributes, + GraphUpdateOut, + GraphUpdateIn, + CONTENT_ID, +} from '../../common/content_management'; import { injectReferences, extractReferences, } from '../services/persistence/saved_workspace_references'; import { GraphWorkspaceSavedObject } from '../types'; - +import { checkForDuplicateTitle, saveWithConfirmation } from './saved_objects_utils'; const savedWorkspaceType = 'graph-workspace'; const mapping: Record = { title: 'text', @@ -60,25 +65,25 @@ function mapHits(hit: any, url: string): GraphWorkspaceSavedObject { interface SavedWorkspaceServices { basePath: IBasePath; - savedObjectsClient: SavedObjectsClientContract; + contentClient: ContentClient; } export function findSavedWorkspace( - { savedObjectsClient, basePath }: SavedWorkspaceServices, + { contentClient, basePath }: SavedWorkspaceServices, searchString: string, size: number = 100 ) { - return savedObjectsClient - .find>({ - type: savedWorkspaceType, - search: searchString ? `${searchString}*` : undefined, - perPage: size, - searchFields: ['title^3', 'description'], + return contentClient + .search({ + contentTypeId: CONTENT_ID, + query: { + text: searchString ? `${searchString}*` : '', + }, }) .then((resp) => { return { - total: resp.total, - hits: resp.savedObjects.map((hit) => mapHits(hit, urlFor(basePath, hit.id))), + total: resp.pagination.total, + hits: resp.hits.map((hit) => mapHits(hit, urlFor(basePath, hit.id))), }; }); } @@ -93,18 +98,15 @@ export function getEmptyWorkspace() { }; } -export async function getSavedWorkspace( - savedObjectsClient: SavedObjectsClientContract, - id: string -) { - const resolveResult = await savedObjectsClient.resolve>( - savedWorkspaceType, - id - ); +export async function getSavedWorkspace(contentClient: ContentClient, id: string) { + const resolveResult = await contentClient.get({ + contentTypeId: CONTENT_ID, + id, + }); - const resp = resolveResult.saved_object; + const resp = resolveResult.item; - if (!resp._version) { + if (!resp.attributes) { throw new SavedObjectNotFound(savedWorkspaceType, id || ''); } @@ -112,8 +114,10 @@ export async function getSavedWorkspace( id, displayName: 'graph workspace', getEsType: () => savedWorkspaceType, - _source: cloneDeep(resp.attributes), - } as GraphWorkspaceSavedObject; + _source: cloneDeep({ + ...resp.attributes, + }), + } as unknown as GraphWorkspaceSavedObject; // assign the defaults to the response defaults(savedObject._source, defaultsProps); @@ -132,9 +136,9 @@ export async function getSavedWorkspace( } const sharingSavedObjectProps = { - outcome: resolveResult.outcome, - aliasTargetId: resolveResult.alias_target_id, - aliasPurpose: resolveResult.alias_purpose, + outcome: resolveResult.meta.outcome, + aliasTargetId: resolveResult.meta.aliasTargetId, + aliasPurpose: resolveResult.meta.aliasPurpose, }; return { @@ -143,11 +147,15 @@ export async function getSavedWorkspace( }; } -export function deleteSavedWorkspace( - savedObjectsClient: SavedObjectsClientContract, - ids: string[] -) { - return Promise.all(ids.map((id: string) => savedObjectsClient.delete(savedWorkspaceType, id))); +export function deleteSavedWorkspace(contentClient: ContentClient, ids: string[]) { + return Promise.all( + ids.map((id: string) => + contentClient.delete({ + contentTypeId: CONTENT_ID, + id, + }) + ) + ); } export async function saveSavedWorkspace( @@ -158,7 +166,7 @@ export async function saveSavedWorkspace( onTitleDuplicate, }: SavedObjectSaveOpts = {}, services: { - savedObjectsClient: SavedObjectsClientContract; + contentClient: ContentClient; overlays: OverlayStart; } ) { @@ -208,13 +216,33 @@ export async function saveSavedWorkspace( references, }; const resp = confirmOverwrite - ? await saveWithConfirmation(attributes, savedObject, createOpt, services) - : await services.savedObjectsClient.create(savedObject.getEsType(), attributes, { - ...createOpt, - overwrite: true, + ? await saveWithConfirmation( + attributes as GraphSavedObjectAttributes, + savedObject, + createOpt, + services + ) + : savedObject.id + ? await services.contentClient.update({ + contentTypeId: CONTENT_ID, + id: savedObject.id, + data: { + ...(extractedRefs.attributes as GraphSavedObjectAttributes), + }, + options: { + references: extractedRefs.references, + }, + }) + : await services.contentClient.create({ + contentTypeId: CONTENT_ID, + data: attributes as GraphSavedObjectAttributes, + options: { + references: createOpt.references, + overwrite: true, + }, }); - savedObject.id = resp.id; + savedObject.id = resp.item.id; savedObject.isSaving = false; savedObject.lastSavedTitle = savedObject.title; return savedObject.id; diff --git a/x-pack/plugins/graph/public/helpers/use_graph_loader.ts b/x-pack/plugins/graph/public/helpers/use_graph_loader.ts index 0d50039ab9797..2b0b4b6d839e1 100644 --- a/x-pack/plugins/graph/public/helpers/use_graph_loader.ts +++ b/x-pack/plugins/graph/public/helpers/use_graph_loader.ts @@ -101,7 +101,7 @@ export const useGraphLoader = ({ toastNotifications, coreStart }: UseGraphLoader inspectRequest.json(dsl); return coreStart.http - .post<{ resp: estypes.GraphExploreResponse }>('../api/graph/graphExplore', request) + .post<{ resp: estypes.GraphExploreResponse }>('../internal/graph/graphExplore', request) .then(function (data) { const response = data.resp; @@ -136,7 +136,7 @@ export const useGraphLoader = ({ toastNotifications, coreStart }: UseGraphLoader inspectRequest.json(dsl); coreStart.http - .post<{ resp: estypes.GraphExploreResponse }>('../api/graph/searchProxy', request) + .post<{ resp: estypes.GraphExploreResponse }>('../internal/graph/searchProxy', request) .then(function (data) { const response = data.resp; inspectRequest.stats({}).ok({ json: response }); diff --git a/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx b/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx index af35a83735036..22790bc7f639b 100644 --- a/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx +++ b/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx @@ -10,9 +10,8 @@ import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { createMockGraphStore } from '../state_management/mocks'; import { Workspace } from '../types'; -import { SavedObjectsClientCommon } from '@kbn/data-views-plugin/public'; import { renderHook, act, RenderHookOptions } from '@testing-library/react-hooks'; -import type { SavedObjectsClientContract } from '@kbn/core/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; jest.mock('react-router-dom', () => { const useLocation = () => ({ @@ -33,19 +32,19 @@ jest.mock('react-router-dom', () => { }; }); -const mockSavedObjectsClient = { - resolve: jest.fn().mockResolvedValue({ - saved_object: { id: 10, _version: '7.15.0', attributes: { wsState: '{}' } }, - outcome: 'exactMatch', +const mockContentClient = { + get: jest.fn().mockResolvedValue({ + item: { id: 10, _version: '7.15.0', attributes: { wsState: '{}' } }, + meta: { outcome: 'exactMatch' }, }), - find: jest.fn().mockResolvedValue({ title: 'test', perPage: 1, total: 1, page: 1 }), -} as unknown as SavedObjectsClientCommon; + search: jest.fn().mockResolvedValue({ title: 'test', perPage: 1, total: 1, page: 1 }), +} as unknown as ContentClient; describe('use_workspace_loader', () => { const defaultProps: UseWorkspaceLoaderProps = { workspaceRef: { current: {} as Workspace }, store: createMockGraphStore({}).store, - savedObjectsClient: mockSavedObjectsClient as unknown as SavedObjectsClientContract, + contentClient: mockContentClient as unknown as ContentClient, coreStart: coreMock.createStart(), spaces: spacesPluginMock.createStartContract(), data: dataPluginMock.createStartContract(), @@ -65,13 +64,15 @@ describe('use_workspace_loader', () => { const props = { ...defaultProps, spaces: spacesPluginMock.createStartContract(), - savedObjectsClient: { - ...mockSavedObjectsClient, - resolve: jest.fn().mockResolvedValue({ - saved_object: { id: 10, _version: '7.15.0', attributes: { wsState: '{}' } }, - outcome: 'aliasMatch', - alias_target_id: 'aliasTargetId', - alias_purpose: 'savedObjectConversion', + contentClient: { + ...mockContentClient, + get: jest.fn().mockResolvedValue({ + item: { id: 10, _version: '7.15.0', attributes: { wsState: '{}' } }, + meta: { + outcome: 'aliasMatch', + aliasTargetId: 'aliasTargetId', + aliasPurpose: 'savedObjectConversion', + }, }), }, } as unknown as UseWorkspaceLoaderProps; diff --git a/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts b/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts index 8c0a7f38fdea2..ac053ab3c4ada 100644 --- a/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts +++ b/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts @@ -7,12 +7,13 @@ import { useEffect, useState } from 'react'; import { useHistory, useLocation, useParams } from 'react-router-dom'; -import type { SavedObjectsClientContract, ResolvedSimpleSavedObject } from '@kbn/core/public'; +import type { ResolvedSimpleSavedObject } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { i18n } from '@kbn/i18n'; import { CoreStart } from '@kbn/core/public'; import { SpacesApi } from '@kbn/spaces-plugin/public'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { GraphStore } from '../state_management'; import { GraphWorkspaceSavedObject, Workspace } from '../types'; import { getEmptyWorkspace, getSavedWorkspace } from './saved_workspace_utils'; @@ -21,7 +22,7 @@ import { getEditUrl } from '../services/url'; export interface UseWorkspaceLoaderProps { store: GraphStore; workspaceRef: React.MutableRefObject; - savedObjectsClient: SavedObjectsClientContract; + contentClient: ContentClient; coreStart: CoreStart; spaces?: SpacesApi; data: DataPublicPluginStart; @@ -47,7 +48,7 @@ export const useWorkspaceLoader = ({ spaces, workspaceRef, store, - savedObjectsClient, + contentClient, data, }: UseWorkspaceLoaderProps) => { const [state, setState] = useState(); @@ -85,7 +86,7 @@ export const useWorkspaceLoader = ({ sharingSavedObjectProps?: SharingSavedObjectProps; }> { return id - ? await getSavedWorkspace(savedObjectsClient, id).catch(function (e) { + ? await getSavedWorkspace(contentClient, id).catch(function (e) { coreStart.notifications.toasts.addError(e, { title: i18n.translate('xpack.graph.missingWorkspaceErrorMessage', { defaultMessage: "Couldn't load graph with ID", @@ -141,7 +142,7 @@ export const useWorkspaceLoader = ({ search, store, historyReplace, - savedObjectsClient, + contentClient, setState, coreStart, workspaceRef, diff --git a/x-pack/plugins/graph/public/plugin.ts b/x-pack/plugins/graph/public/plugin.ts index feca5656f73d6..73e040dc4e760 100644 --- a/x-pack/plugins/graph/public/plugin.ts +++ b/x-pack/plugins/graph/public/plugin.ts @@ -23,17 +23,21 @@ import { Start as InspectorPublicPluginStart } from '@kbn/inspector-plugin/publi import { Storage } from '@kbn/kibana-utils-plugin/public'; import { NavigationPublicPluginStart as NavigationStart } from '@kbn/navigation-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; - +import { + ContentManagementPublicSetup, + ContentManagementPublicStart, +} from '@kbn/content-management-plugin/public'; import { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { HomePublicPluginSetup, HomePublicPluginStart } from '@kbn/home-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; -import { SavedObjectsStart } from '@kbn/saved-objects-plugin/public'; import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; import { checkLicense } from '../common/check_license'; import { ConfigSchema } from '../config'; +import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; export interface GraphPluginSetupDependencies { home?: HomePublicPluginSetup; + contentManagement: ContentManagementPublicSetup; } export interface GraphPluginStartDependencies { @@ -41,11 +45,11 @@ export interface GraphPluginStartDependencies { licensing: LicensingPluginStart; data: DataPublicPluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; - savedObjects: SavedObjectsStart; inspector: InspectorPublicPluginStart; home?: HomePublicPluginStart; spaces?: SpacesApi; savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; } export class GraphPlugin @@ -55,7 +59,10 @@ export class GraphPlugin constructor(private initializerContext: PluginInitializerContext) {} - setup(core: CoreSetup, { home }: GraphPluginSetupDependencies) { + setup( + core: CoreSetup, + { home, contentManagement }: GraphPluginSetupDependencies + ) { if (home) { home.featureCatalogue.register({ id: 'graph', @@ -77,6 +84,16 @@ export class GraphPlugin const config = this.initializerContext.config.get(); + contentManagement.registry.register({ + id: CONTENT_ID, + version: { + latest: LATEST_VERSION, + }, + name: i18n.translate('xpack.graph.content.name', { + defaultMessage: 'Graph Visualization', + }), + }); + core.application.register({ id: 'graph', title: 'Graph', @@ -100,7 +117,7 @@ export class GraphPlugin navigation: pluginsStart.navigation, data: pluginsStart.data, unifiedSearch: pluginsStart.unifiedSearch, - savedObjectsClient: coreStart.savedObjects.client, + contentClient: pluginsStart.contentManagement.client, addBasePath: core.http.basePath.prepend, getBasePath: core.http.basePath.get, canEditDrillDownUrls: config.canEditDrillDownUrls, @@ -111,7 +128,6 @@ export class GraphPlugin toastNotifications: coreStart.notifications.toasts, indexPatterns: pluginsStart.data!.indexPatterns, overlays: coreStart.overlays, - savedObjects: pluginsStart.savedObjects, uiSettings: core.uiSettings, spaces: pluginsStart.spaces, inspect: pluginsStart.inspector, diff --git a/x-pack/plugins/graph/public/services/fetch_top_nodes.test.ts b/x-pack/plugins/graph/public/services/fetch_top_nodes.test.ts index 756ae27024118..700118a96011c 100644 --- a/x-pack/plugins/graph/public/services/fetch_top_nodes.test.ts +++ b/x-pack/plugins/graph/public/services/fetch_top_nodes.test.ts @@ -33,7 +33,7 @@ describe('fetch_top_nodes', () => { aggregatable: true, }, ]); - expect(postMock).toHaveBeenCalledWith('../api/graph/searchProxy', { + expect(postMock).toHaveBeenCalledWith('../internal/graph/searchProxy', { body: JSON.stringify({ index: 'test', body: { diff --git a/x-pack/plugins/graph/public/services/fetch_top_nodes.ts b/x-pack/plugins/graph/public/services/fetch_top_nodes.ts index b0c6e09bbd9ff..4b8496c62545b 100644 --- a/x-pack/plugins/graph/public/services/fetch_top_nodes.ts +++ b/x-pack/plugins/graph/public/services/fetch_top_nodes.ts @@ -97,7 +97,7 @@ export async function fetchTopNodes( const body = createSamplerSearchBody(aggs); const response = ( - await post<{ resp: TopTermsAggResponse }>('../api/graph/searchProxy', { + await post<{ resp: TopTermsAggResponse }>('../internal/graph/searchProxy', { body: JSON.stringify({ index, body }), }) ).resp; diff --git a/x-pack/plugins/graph/public/services/save_modal.tsx b/x-pack/plugins/graph/public/services/save_modal.tsx index ab1db894a47c2..735d231a0e2e2 100644 --- a/x-pack/plugins/graph/public/services/save_modal.tsx +++ b/x-pack/plugins/graph/public/services/save_modal.tsx @@ -6,15 +6,16 @@ */ import React from 'react'; -import { OverlayStart, SavedObjectsClientContract } from '@kbn/core/public'; +import { OverlayStart } from '@kbn/core/public'; import { SaveResult } from '@kbn/saved-objects-plugin/public'; import { showSaveModal } from '@kbn/saved-objects-plugin/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { GraphWorkspaceSavedObject, GraphSavePolicy } from '../types'; import { SaveModal, OnSaveGraphProps } from '../components/save_modal'; export interface SaveWorkspaceServices { overlays: OverlayStart; - savedObjectsClient: SavedObjectsClientContract; + contentClient: ContentClient; } export type SaveWorkspaceHandler = ( diff --git a/x-pack/plugins/graph/public/state_management/mocks.ts b/x-pack/plugins/graph/public/state_management/mocks.ts index d6d0cd8e1acd4..23a666a385130 100644 --- a/x-pack/plugins/graph/public/state_management/mocks.ts +++ b/x-pack/plugins/graph/public/state_management/mocks.ts @@ -5,16 +5,12 @@ * 2.0. */ -import { - NotificationsStart, - HttpStart, - OverlayStart, - SavedObjectsClientContract, -} from '@kbn/core/public'; +import { NotificationsStart, HttpStart, OverlayStart } from '@kbn/core/public'; import createSagaMiddleware from 'redux-saga'; import { createStore, applyMiddleware, AnyAction } from 'redux'; import { ChromeStart } from '@kbn/core/public'; import type { DataView } from '@kbn/data-views-plugin/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { GraphStoreDependencies, createRootReducer, GraphStore, GraphState } from './store'; import { Workspace } from '../types'; @@ -58,6 +54,12 @@ export function createMockGraphStore({ } as unknown as ChromeStart, createWorkspace: jest.fn((index, advancedSettings) => workspaceMock), getWorkspace: jest.fn(() => workspaceMock), + contentClient: { + get: jest.fn(), + search: jest.fn(), + create: jest.fn(), + update: jest.fn(), + } as unknown as ContentClient, indexPatternProvider: { get: jest.fn(async (id: string) => { if (id === 'missing-dataview') { @@ -78,10 +80,6 @@ export function createMockGraphStore({ overlays: { openModal: jest.fn(), } as unknown as OverlayStart, - savedObjectsClient: { - find: jest.fn(), - get: jest.fn(), - } as unknown as SavedObjectsClientContract, handleSearchQueryError: jest.fn(), ...mockedDepsOverwrites, }; diff --git a/x-pack/plugins/graph/public/state_management/persistence.ts b/x-pack/plugins/graph/public/state_management/persistence.ts index 41bc07485cf0a..71ba688b6dfe3 100644 --- a/x-pack/plugins/graph/public/state_management/persistence.ts +++ b/x-pack/plugins/graph/public/state_management/persistence.ts @@ -231,7 +231,7 @@ function showModal( workspace: savedWorkspace, saveWorkspace: saveWorkspaceHandler, services: { - savedObjectsClient: deps.savedObjectsClient, + contentClient: deps.contentClient, overlays: deps.overlays, }, }); diff --git a/x-pack/plugins/graph/public/state_management/store.ts b/x-pack/plugins/graph/public/state_management/store.ts index c2a14dc88024a..1592ffda3c29f 100644 --- a/x-pack/plugins/graph/public/state_management/store.ts +++ b/x-pack/plugins/graph/public/state_management/store.ts @@ -7,8 +7,9 @@ import createSagaMiddleware, { SagaMiddleware } from 'redux-saga'; import { combineReducers, createStore, Store, AnyAction, Dispatch, applyMiddleware } from 'redux'; -import { ChromeStart, OverlayStart, SavedObjectsClientContract } from '@kbn/core/public'; +import { ChromeStart, OverlayStart } from '@kbn/core/public'; import { CoreStart } from '@kbn/core/public'; +import { ContentClient } from '@kbn/content-management-plugin/public'; import { fieldsReducer, FieldsState, @@ -46,7 +47,7 @@ export interface GraphStoreDependencies { notifications: CoreStart['notifications']; http: CoreStart['http']; overlays: OverlayStart; - savedObjectsClient: SavedObjectsClientContract; + contentClient: ContentClient; savePolicy: GraphSavePolicy; changeUrl: (newUrl: string) => void; notifyReact: () => void; diff --git a/x-pack/plugins/graph/server/content_management/graph_storage.ts b/x-pack/plugins/graph/server/content_management/graph_storage.ts new file mode 100644 index 0000000000000..e0faea8c99b9c --- /dev/null +++ b/x-pack/plugins/graph/server/content_management/graph_storage.ts @@ -0,0 +1,328 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import Boom from '@hapi/boom'; +import type { SearchQuery } from '@kbn/content-management-plugin/common'; +import type { ContentStorage, StorageContext } from '@kbn/content-management-plugin/server'; +import type { + SavedObject, + SavedObjectReference, + SavedObjectsFindOptions, +} from '@kbn/core-saved-objects-api-server'; + +import { cmServicesDefinition } from '../../common/content_management/cm_services'; +import type { + GraphSavedObjectAttributes, + GraphSavedObject, + PartialGraphSavedObject, + GraphGetOut, + GraphCreateIn, + GraphCreateOut, + CreateOptions, + GraphUpdateIn, + GraphUpdateOut, + UpdateOptions, + GraphDeleteOut, + GraphSearchQuery, + GraphSearchOut, +} from '../../common/content_management'; + +const savedObjectClientFromRequest = async (ctx: StorageContext) => { + if (!ctx.requestHandlerContext) { + throw new Error('Storage context.requestHandlerContext missing.'); + } + + const { savedObjects } = await ctx.requestHandlerContext.core; + return savedObjects.client; +}; + +type PartialSavedObject = Omit>, 'references'> & { + references: SavedObjectReference[] | undefined; +}; + +function savedObjectToGraphSavedObject( + savedObject: SavedObject, + partial: false +): GraphSavedObject; + +function savedObjectToGraphSavedObject( + savedObject: PartialSavedObject, + partial: true +): PartialGraphSavedObject; + +function savedObjectToGraphSavedObject( + savedObject: + | SavedObject + | PartialSavedObject +): GraphSavedObject | PartialGraphSavedObject { + const { + id, + type, + updated_at: updatedAt, + created_at: createdAt, + attributes: { + title, + description, + version, + kibanaSavedObjectMeta, + wsState, + numVertices, + numLinks, + legacyIndexPatternRef, + }, + references, + error, + namespaces, + } = savedObject; + + return { + id, + type, + updatedAt, + createdAt, + attributes: { + title, + description, + kibanaSavedObjectMeta, + wsState, + version, + numLinks, + numVertices, + legacyIndexPatternRef, + }, + references, + error, + namespaces, + }; +} + +const SO_TYPE = 'graph-workspace'; + +export class GraphStorage implements ContentStorage { + constructor() {} + + async get(ctx: StorageContext, id: string): Promise { + const { + utils: { getTransforms }, + version: { request: requestVersion }, + } = ctx; + const transforms = getTransforms(cmServicesDefinition, requestVersion); + const soClient = await savedObjectClientFromRequest(ctx); + + // Save data in DB + const { + saved_object: savedObject, + alias_purpose: aliasPurpose, + alias_target_id: aliasTargetId, + outcome, + } = await soClient.resolve(SO_TYPE, id); + + const response: GraphGetOut = { + item: savedObjectToGraphSavedObject(savedObject, false), + meta: { + aliasPurpose, + aliasTargetId, + outcome, + }, + }; + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.get.out.result.down( + response + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async bulkGet(): Promise { + // Not implemented. Graph does not use bulkGet + throw new Error(`[bulkGet] has not been implemented. See GraphStorage class.`); + } + + async create( + ctx: StorageContext, + data: GraphCreateIn['data'], + options: CreateOptions + ): Promise { + const { + utils: { getTransforms }, + version: { request: requestVersion }, + } = ctx; + const transforms = getTransforms(cmServicesDefinition, requestVersion); + + // Validate input (data & options) & UP transform them to the latest version + const { value: dataToLatest, error: dataError } = transforms.create.in.data.up< + GraphSavedObjectAttributes, + GraphSavedObjectAttributes + >(data); + if (dataError) { + throw Boom.badRequest(`Invalid data. ${dataError.message}`); + } + + const { value: optionsToLatest, error: optionsError } = transforms.create.in.options.up< + CreateOptions, + CreateOptions + >(options); + if (optionsError) { + throw Boom.badRequest(`Invalid options. ${optionsError.message}`); + } + + // Save data in DB + const soClient = await savedObjectClientFromRequest(ctx); + const savedObject = await soClient.create( + SO_TYPE, + dataToLatest, + optionsToLatest + ); + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.create.out.result.down< + GraphCreateOut, + GraphCreateOut + >({ + item: savedObjectToGraphSavedObject(savedObject, false), + }); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async update( + ctx: StorageContext, + id: string, + data: GraphUpdateIn['data'], + options: UpdateOptions + ): Promise { + const { + utils: { getTransforms }, + version: { request: requestVersion }, + } = ctx; + const transforms = getTransforms(cmServicesDefinition, requestVersion); + + // Validate input (data & options) & UP transform them to the latest version + const { value: dataToLatest, error: dataError } = transforms.update.in.data.up< + GraphSavedObjectAttributes, + GraphSavedObjectAttributes + >(data); + if (dataError) { + throw Boom.badRequest(`Invalid data. ${dataError.message}`); + } + + const { value: optionsToLatest, error: optionsError } = transforms.update.in.options.up< + CreateOptions, + CreateOptions + >(options); + if (optionsError) { + throw Boom.badRequest(`Invalid options. ${optionsError.message}`); + } + + // Save data in DB + const soClient = await savedObjectClientFromRequest(ctx); + const partialSavedObject = await soClient.update( + SO_TYPE, + id, + dataToLatest, + optionsToLatest + ); + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.update.out.result.down< + GraphUpdateOut, + GraphUpdateOut + >({ + item: savedObjectToGraphSavedObject(partialSavedObject, true), + }); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async delete(ctx: StorageContext, id: string): Promise { + const soClient = await savedObjectClientFromRequest(ctx); + await soClient.delete(SO_TYPE, id); + return { success: true }; + } + + async search( + ctx: StorageContext, + query: SearchQuery, + options: GraphSearchQuery = {} + ): Promise { + const { + utils: { getTransforms }, + version: { request: requestVersion }, + } = ctx; + const transforms = getTransforms(cmServicesDefinition, requestVersion); + const soClient = await savedObjectClientFromRequest(ctx); + + // Validate and UP transform the options + const { value: optionsToLatest, error: optionsError } = transforms.search.in.options.up< + GraphSearchQuery, + GraphSearchQuery + >(options); + if (optionsError) { + throw Boom.badRequest(`Invalid payload. ${optionsError.message}`); + } + const { searchFields = ['title^3', 'description'], types = ['graph-workspace'] } = + optionsToLatest; + + const { included, excluded } = query.tags ?? {}; + const hasReference: SavedObjectsFindOptions['hasReference'] = included + ? included.map((id) => ({ + id, + type: 'tag', + })) + : undefined; + + const hasNoReference: SavedObjectsFindOptions['hasNoReference'] = excluded + ? excluded.map((id) => ({ + id, + type: 'tag', + })) + : undefined; + + const soQuery: SavedObjectsFindOptions = { + type: types, + search: query.text, + perPage: query.limit, + page: query.cursor ? Number(query.cursor) : undefined, + defaultSearchOperator: 'AND', + searchFields, + hasReference, + hasNoReference, + }; + + // Execute the query in the DB + const response = await soClient.find(soQuery); + + // Validate the response and DOWN transform to the request version + const { value, error: resultError } = transforms.search.out.result.down< + GraphSearchOut, + GraphSearchOut + >({ + hits: response.saved_objects.map((so) => savedObjectToGraphSavedObject(so, false)), + pagination: { + total: response.total, + }, + }); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } +} diff --git a/x-pack/plugins/graph/server/content_management/index.ts b/x-pack/plugins/graph/server/content_management/index.ts new file mode 100644 index 0000000000000..1562b9177d6b0 --- /dev/null +++ b/x-pack/plugins/graph/server/content_management/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { GraphStorage } from './graph_storage'; diff --git a/x-pack/plugins/graph/server/plugin.ts b/x-pack/plugins/graph/server/plugin.ts index 3043ab7e5aae1..db33a04c6a0bf 100644 --- a/x-pack/plugins/graph/server/plugin.ts +++ b/x-pack/plugins/graph/server/plugin.ts @@ -11,11 +11,14 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { ContentManagementServerSetup } from '@kbn/content-management-plugin/server'; import { LicenseState } from './lib/license_state'; import { registerSearchRoute } from './routes/search'; import { registerExploreRoute } from './routes/explore'; import { registerSampleData } from './sample_data'; import { graphWorkspace } from './saved_objects'; +import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; +import { GraphStorage } from './content_management/graph_storage'; export class GraphPlugin implements Plugin { private licenseState: LicenseState | null = null; @@ -26,10 +29,12 @@ export class GraphPlugin implements Plugin { licensing, home, features, + contentManagement, }: { licensing: LicensingPluginSetup; home?: HomeServerPluginSetup; features?: FeaturesPluginSetup; + contentManagement: ContentManagementServerSetup; } ) { const licenseState = new LicenseState(); @@ -38,6 +43,14 @@ export class GraphPlugin implements Plugin { core.savedObjects.registerType(graphWorkspace); licensing.featureUsage.register('Graph', 'platinum'); + contentManagement.register({ + id: CONTENT_ID, + storage: new GraphStorage(), + version: { + latest: LATEST_VERSION, + }, + }); + if (home) { registerSampleData(home.sampleData, licenseState); } diff --git a/x-pack/plugins/graph/server/routes/explore.ts b/x-pack/plugins/graph/server/routes/explore.ts index 6a6072e17274c..b97f3fe882c35 100644 --- a/x-pack/plugins/graph/server/routes/explore.ts +++ b/x-pack/plugins/graph/server/routes/explore.ts @@ -26,7 +26,7 @@ export function registerExploreRoute({ }) { router.post( { - path: '/api/graph/graphExplore', + path: '/internal/graph/graphExplore', validate: { body: schema.object({ index: schema.string(), diff --git a/x-pack/plugins/graph/server/routes/search.ts b/x-pack/plugins/graph/server/routes/search.ts index 2bdb956196ed4..822b22648c7cc 100644 --- a/x-pack/plugins/graph/server/routes/search.ts +++ b/x-pack/plugins/graph/server/routes/search.ts @@ -19,7 +19,7 @@ export function registerSearchRoute({ }) { router.post( { - path: '/api/graph/searchProxy', + path: '/internal/graph/searchProxy', validate: { body: schema.object({ index: schema.string(), diff --git a/x-pack/plugins/graph/tsconfig.json b/x-pack/plugins/graph/tsconfig.json index 579cda78b0fed..b91a6913f07ae 100644 --- a/x-pack/plugins/graph/tsconfig.json +++ b/x-pack/plugins/graph/tsconfig.json @@ -41,6 +41,9 @@ "@kbn/saved-objects-management-plugin", "@kbn/saved-objects-finder-plugin", "@kbn/core-saved-objects-server", + "@kbn/content-management-plugin", + "@kbn/core-saved-objects-api-server", + "@kbn/object-versioning", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/infra/common/source_configuration/source_configuration.ts b/x-pack/plugins/infra/common/source_configuration/source_configuration.ts index 3b1694abdadc7..8881b5fab5f5f 100644 --- a/x-pack/plugins/infra/common/source_configuration/source_configuration.ts +++ b/x-pack/plugins/infra/common/source_configuration/source_configuration.ts @@ -19,25 +19,6 @@ import { omit } from 'lodash'; import * as rt from 'io-ts'; -import moment from 'moment'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { chain } from 'fp-ts/lib/Either'; - -export const TimestampFromString = new rt.Type( - 'TimestampFromString', - (input): input is number => typeof input === 'number', - (input, context) => - pipe( - rt.string.validate(input, context), - chain((stringInput) => { - const momentValue = moment(stringInput); - return momentValue.isValid() - ? rt.success(momentValue.valueOf()) - : rt.failure(stringInput, context); - }) - ), - (output) => new Date(output).toISOString() -); /** * Source configuration config file properties. @@ -246,21 +227,3 @@ export const SourceResponseRuntimeType = rt.type({ }); export type SourceResponse = rt.TypeOf; - -/** - * Saved object type with metadata - */ - -export const SourceConfigurationSavedObjectRuntimeType = rt.intersection([ - rt.type({ - id: rt.string, - attributes: SavedSourceConfigurationRuntimeType, - }), - rt.partial({ - version: rt.string, - updated_at: TimestampFromString, - }), -]); - -export interface SourceConfigurationSavedObject - extends rt.TypeOf {} diff --git a/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx index 32cc6e56d861f..e5dcc75ce9c4e 100644 --- a/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/asset_details.stories.tsx @@ -5,15 +5,15 @@ * 2.0. */ +import React from 'react'; import { EuiButton, EuiCard } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n-react'; import type { Meta, Story } from '@storybook/react/types-6-0'; -import React from 'react'; import { i18n } from '@kbn/i18n'; import { DecorateWithKibanaContext } from './asset_details.story_decorators'; - -import { AssetDetails, FlyoutTabIds, type AssetDetailsProps } from './asset_details'; +import { AssetDetails } from './asset_details'; import { decorateWithGlobalStorybookThemeProviders } from '../../test_utils/use_global_storybook_theme'; +import { FlyoutTabIds, type AssetDetailsProps } from './types'; export default { title: 'infra/Asset Details View/Asset Details Embeddable', @@ -42,20 +42,12 @@ export default { memoryTotal: 34359738368, }, nodeType: 'host', - closeFlyout: () => {}, - onTabClick: () => {}, - renderedTabsSet: { current: new Set(['metadata']) }, currentTimeRange: { interval: '1s', from: 1683630468, to: 1683630469, }, - hostFlyoutOpen: { - clickedItemId: 'host1-macos', - selectedTabId: 'metadata', - searchFilter: '', - metadataSearch: '', - }, + selectedTabId: 'metadata', tabs: [ { id: FlyoutTabIds.METADATA, @@ -73,7 +65,7 @@ export default { }, ], links: ['apmServices', 'uptime'], - }, + } as AssetDetailsProps, } as Meta; const Template: Story = (args) => { @@ -91,26 +83,32 @@ const FlyoutTemplate: Story = (args) => { > Open flyout - + ); }; export const DefaultAssetDetailsWithMetadataTabSelected = Template.bind({}); DefaultAssetDetailsWithMetadataTabSelected.args = { - showActionsColumn: true, + overrides: { + metadata: { + showActionsColumn: true, + }, + }, }; export const AssetDetailsWithMetadataTabSelectedWithPersistedSearch = Template.bind({}); AssetDetailsWithMetadataTabSelectedWithPersistedSearch.args = { - showActionsColumn: true, - hostFlyoutOpen: { - clickedItemId: 'host1-macos', - selectedTabId: 'metadata', - searchFilter: '', - metadataSearch: 'ip', + overrides: { + metadata: { + showActionsColumn: true, + query: 'ip', + }, }, - setHostFlyoutState: () => {}, + activeTabId: 'metadata', + onTabsStateChange: () => {}, }; export const AssetDetailsWithMetadataWithoutActions = Template.bind({}); @@ -120,22 +118,21 @@ export const AssetDetailsWithMetadataWithoutLinks = Template.bind({}); AssetDetailsWithMetadataWithoutLinks.args = { links: [] }; export const AssetDetailsAsFlyout = FlyoutTemplate.bind({}); -AssetDetailsAsFlyout.args = { showInFlyout: true }; +AssetDetailsAsFlyout.args = { + renderMode: { + showInFlyout: true, + closeFlyout: () => {}, + }, +}; export const AssetDetailsWithProcessesTabSelected = Template.bind({}); AssetDetailsWithProcessesTabSelected.args = { - renderedTabsSet: { current: new Set(['processes']) }, + activeTabId: 'processes', currentTimeRange: { interval: '1s', from: 1683630468, to: 1683630469, }, - hostFlyoutOpen: { - clickedItemId: 'host1-macos', - selectedTabId: 'processes', - searchFilter: '', - metadataSearch: '', - }, }; export const AssetDetailsWithMetadataTabOnly = Template.bind({}); diff --git a/x-pack/plugins/infra/public/components/asset_details/asset_details.story_decorators.tsx b/x-pack/plugins/infra/public/components/asset_details/asset_details.story_decorators.tsx index ba75f8ed6329f..7abc2d5937bef 100644 --- a/x-pack/plugins/infra/public/components/asset_details/asset_details.story_decorators.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/asset_details.story_decorators.tsx @@ -9,6 +9,7 @@ import type { StoryContext } from '@storybook/react'; import React from 'react'; import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { of } from 'rxjs'; import { SourceProvider } from '../../containers/metrics_source'; export const DecorateWithKibanaContext = ( @@ -172,7 +173,7 @@ export const DecorateWithKibanaContext = {} }, + currentAppId$: of('infra'), navigateToUrl: () => {}, }, dataViews: { create: () => {} }, diff --git a/x-pack/plugins/infra/public/components/asset_details/asset_details.tsx b/x-pack/plugins/infra/public/components/asset_details/asset_details.tsx index 2037b536d0f69..9ea1a5163059a 100644 --- a/x-pack/plugins/infra/public/components/asset_details/asset_details.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/asset_details.tsx @@ -5,188 +5,77 @@ * 2.0. */ -import React, { useState } from 'react'; -import { - EuiFlyout, - EuiFlyoutHeader, - EuiTitle, - EuiFlyoutBody, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiTabs, - EuiTab, - useEuiTheme, -} from '@elastic/eui'; -import { css } from '@emotion/react'; -import { LinkToUptime } from './links/link_to_uptime'; -import { LinkToApmServices } from './links/link_to_apm_services'; -import type { HostNodeRow } from './types'; +import React from 'react'; +import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody } from '@elastic/eui'; +import type { AssetDetailsProps, RenderMode } from './types'; import type { InventoryItemType } from '../../../common/inventory_models/types'; -import type { SetNewHostFlyoutOpen } from '../../pages/metrics/hosts/hooks/use_host_flyout_open_url_state'; -import { AssetDetailsTabContent } from './tabs_content/tabs_content'; +import { TabContent } from './tab_content/tab_content'; +import { Header } from './header/header'; +import { TabSwitcherProvider } from './hooks/use_tab_switcher'; -export enum FlyoutTabIds { - METADATA = 'metadata', - PROCESSES = 'processes', -} - -export type TabIds = `${FlyoutTabIds}`; - -export interface Tab { - id: FlyoutTabIds; - name: string; - 'data-test-subj': string; -} +// Setting host as default as it will be the only supported type for now +const NODE_TYPE = 'host' as InventoryItemType; -export interface AssetDetailsProps { - node: HostNodeRow; - nodeType: InventoryItemType; - closeFlyout: () => void; - renderedTabsSet: React.MutableRefObject>; - currentTimeRange: { - interval: string; - from: number; - to: number; - }; - tabs: Tab[]; - hostFlyoutOpen?: { - clickedItemId: string; - selectedTabId: TabIds; - searchFilter: string; - metadataSearch: string; - }; - setHostFlyoutState?: SetNewHostFlyoutOpen; - onTabClick?: (tab: Tab) => void; - links?: Array<'uptime' | 'apmServices'>; - showInFlyout?: boolean; - showActionsColumn?: boolean; +interface ContentTemplateProps { + header: React.ReactElement; + body: React.ReactElement; + renderMode: RenderMode; } -// Setting host as default as it will be the only supported type for now -const NODE_TYPE = 'host' as InventoryItemType; +const ContentTemplate = ({ header, body, renderMode }: ContentTemplateProps) => { + return renderMode.showInFlyout ? ( + + {header} + {body} + + ) : ( + <> + {header} + {body} + + ); +}; export const AssetDetails = ({ node, - closeFlyout, - onTabClick, - renderedTabsSet, currentTimeRange, - hostFlyoutOpen, - setHostFlyoutState, + activeTabId, + overrides, + onTabsStateChange, tabs, - showInFlyout, links, - showActionsColumn, nodeType = NODE_TYPE, + renderMode = { + showInFlyout: false, + }, }: AssetDetailsProps) => { - const { euiTheme } = useEuiTheme(); - const [selectedTabId, setSelectedTabId] = useState('metadata'); - - const onTabSelectClick = (tab: Tab) => { - renderedTabsSet.current.add(tab.id); // On a tab click, mark the tab content as allowed to be rendered - setSelectedTabId(tab.id); - }; - - const tabEntries = tabs.map((tab) => ( - (onTabClick ? onTabClick(tab) : onTabSelectClick(tab))} - isSelected={tab.id === hostFlyoutOpen?.selectedTabId ?? selectedTabId} - > - {tab.name} - - )); - - const linksMapping = { - apmServices: ( - - - - ), - uptime: ( - - - - ), - }; - - const headerLinks = links?.map((link) => linksMapping[link]); - - if (!showInFlyout) { - return ( - <> - - - -

{node.name}

-
-
- {links && headerLinks} -
- - - {tabEntries} - - - - ); - } - return ( - - - - - -

{node.name}

-
-
- {links && headerLinks} -
- - - {tabEntries} - -
- - - -
+ 0 ? activeTabId ?? tabs[0].id : undefined} + > + + } + body={ + + } + renderMode={renderMode} + /> + ); }; diff --git a/x-pack/plugins/infra/public/components/asset_details/asset_details_embeddable.tsx b/x-pack/plugins/infra/public/components/asset_details/asset_details_embeddable.tsx index 5549668665c13..4fca0718864f8 100644 --- a/x-pack/plugins/infra/public/components/asset_details/asset_details_embeddable.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/asset_details_embeddable.tsx @@ -14,7 +14,7 @@ import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { CoreProviders } from '../../apps/common_providers'; import { InfraClientStartDeps, InfraClientStartExports } from '../../types'; import { LazyAssetDetailsWrapper } from './lazy_asset_details_wrapper'; -import type { AssetDetailsProps } from './asset_details'; +import type { AssetDetailsProps } from './types'; export const ASSET_DETAILS_EMBEDDABLE = 'ASSET_DETAILS_EMBEDDABLE'; @@ -71,18 +71,15 @@ export class AssetDetailsEmbeddable extends Embeddable
diff --git a/x-pack/plugins/infra/public/components/asset_details/header/header.tsx b/x-pack/plugins/infra/public/components/asset_details/header/header.tsx new file mode 100644 index 0000000000000..6937b8354be6b --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/header/header.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 { + EuiTitle, + EuiSpacer, + EuiFlexItem, + EuiFlexGroup, + EuiTabs, + EuiTab, + useEuiTheme, + useEuiMaxBreakpoint, + useEuiMinBreakpoint, +} from '@elastic/eui'; +import { css } from '@emotion/react'; +import { EuiShowFor } from '@elastic/eui'; +import type { AssetDetailsProps } from '../types'; +import { LinkToApmServices } from '../links/link_to_apm_services'; +import { LinkToUptime } from '../links/link_to_uptime'; +import { useTabSwitcherContext } from '../hooks/use_tab_switcher'; +import type { TabIds } from '../types'; +type Props = Pick< + AssetDetailsProps, + 'node' | 'nodeType' | 'links' | 'tabs' | 'onTabsStateChange' +> & { + compact: boolean; +}; + +export const Header = ({ nodeType, node, tabs, links, compact, onTabsStateChange }: Props) => { + const { euiTheme } = useEuiTheme(); + const { showTab, activeTabId } = useTabSwitcherContext(); + + const onTabClick = (tabId: TabIds) => { + if (onTabsStateChange) { + onTabsStateChange({ activeTabId: tabId }); + } + + showTab(tabId); + }; + + const tabEntries = tabs.map((tab) => ( + onTabClick(tab.id)} + isSelected={tab.id === activeTabId} + > + {tab.name} + + )); + + const linkComponent = { + apmServices: , + uptime: , + }; + + const headerLinks = links?.map((link, index) => ( + + {linkComponent[link]} + + )); + + return ( + <> + + {!compact && ( + + + + )} + + +

{node.name}

+
+
+ + + {headerLinks} + + +
+ + + {tabEntries} + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_tab_switcher.tsx b/x-pack/plugins/infra/public/components/asset_details/hooks/use_tab_switcher.tsx new file mode 100644 index 0000000000000..f6f7757bb062f --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_tab_switcher.tsx @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useState } from 'react'; +import createContainer from 'constate'; +import { useLazyRef } from '../../../hooks/use_lazy_ref'; +import type { TabIds } from '../types'; + +export function useTabSwitcher({ initialActiveTabId }: { initialActiveTabId?: TabIds }) { + const [activeTabId, setActiveTabId] = useState(initialActiveTabId); + + // This set keeps track of which tabs content have been rendered the first time. + // We need it in order to load a tab content only if it gets clicked, and then keep it in the DOM for performance improvement. + const renderedTabsSet = useLazyRef(() => new Set([initialActiveTabId])); + + const showTab = (tabId: TabIds) => { + renderedTabsSet.current.add(tabId); // On a tab click, mark the tab content as allowed to be rendered + setActiveTabId(tabId); + }; + + return { + activeTabId, + renderedTabsSet, + showTab, + }; +} + +export const TabSwitcher = createContainer(useTabSwitcher); +export const [TabSwitcherProvider, useTabSwitcherContext] = TabSwitcher; diff --git a/x-pack/plugins/infra/public/components/asset_details/lazy_asset_details_wrapper.tsx b/x-pack/plugins/infra/public/components/asset_details/lazy_asset_details_wrapper.tsx index e6eec56ddfe87..02f12ca659821 100644 --- a/x-pack/plugins/infra/public/components/asset_details/lazy_asset_details_wrapper.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/lazy_asset_details_wrapper.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { EuiLoadingSpinner } from '@elastic/eui'; -import type { AssetDetailsProps } from './asset_details'; +import type { AssetDetailsProps } from './types'; const AssetDetails = React.lazy(() => import('./asset_details')); diff --git a/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.stories.tsx index 323369a06f4e0..fb8f8a4a7a053 100644 --- a/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.stories.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/links/link_to_apm_services.stories.tsx @@ -10,12 +10,13 @@ import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import type { Meta, Story } from '@storybook/react/types-6-0'; import React from 'react'; +import { of } from 'rxjs'; import { decorateWithGlobalStorybookThemeProviders } from '../../../test_utils/use_global_storybook_theme'; import { LinkToApmServices, type LinkToApmServicesProps } from './link_to_apm_services'; const mockServices = { application: { - currentAppId$: { title: 'infra', subscribe: () => {} }, + currentAppId$: of('infra'), navigateToUrl: () => {}, }, http: { diff --git a/x-pack/plugins/infra/public/components/asset_details/tab_content/tab_content.tsx b/x-pack/plugins/infra/public/components/asset_details/tab_content/tab_content.tsx new file mode 100644 index 0000000000000..506306760bc85 --- /dev/null +++ b/x-pack/plugins/infra/public/components/asset_details/tab_content/tab_content.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { useTabSwitcherContext } from '../hooks/use_tab_switcher'; +import Metadata from '../tabs/metadata/metadata'; +import { Processes } from '../tabs/processes/processes'; +import { FlyoutTabIds, type TabState, type AssetDetailsProps } from '../types'; + +type Props = Pick< + AssetDetailsProps, + 'currentTimeRange' | 'node' | 'nodeType' | 'overrides' | 'onTabsStateChange' +>; + +export const TabContent = ({ + overrides, + currentTimeRange, + node, + nodeType, + onTabsStateChange, +}: Props) => { + const onChange = (state: TabState) => { + if (!onTabsStateChange) { + return; + } + + onTabsStateChange(state); + }; + + return ( + <> + + onChange({ metadata: { query } })} + /> + + + onChange({ processes: { query } })} + /> + + + ); +}; + +const TabPanel = ({ + activeWhen, + children, +}: { + activeWhen: FlyoutTabIds; + children: React.ReactNode; +}) => { + const { renderedTabsSet, activeTabId } = useTabSwitcherContext(); + + return renderedTabsSet.current.has(activeWhen) ? ( + + ) : null; +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/add_metadata_filter_button.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/add_metadata_filter_button.tsx similarity index 92% rename from x-pack/plugins/infra/public/components/asset_details/metadata/add_metadata_filter_button.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/add_metadata_filter_button.tsx index 8a89e8faecb77..31d978235be32 100644 --- a/x-pack/plugins/infra/public/components/asset_details/metadata/add_metadata_filter_button.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/add_metadata_filter_button.tsx @@ -8,9 +8,9 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; -import { useMetricsDataViewContext } from '../../../pages/metrics/hosts/hooks/use_data_view'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; -import { useUnifiedSearchContext } from '../../../pages/metrics/hosts/hooks/use_unified_search'; +import { useMetricsDataViewContext } from '../../../../pages/metrics/hosts/hooks/use_data_view'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; +import { useUnifiedSearchContext } from '../../../../pages/metrics/hosts/hooks/use_unified_search'; import { buildMetadataFilter } from './build_metadata_filter'; interface AddMetadataFilterButtonProps { diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/build_metadata_filter.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/build_metadata_filter.ts similarity index 100% rename from x-pack/plugins/infra/public/components/asset_details/metadata/build_metadata_filter.ts rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/build_metadata_filter.ts diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/lazy_metadata_wrapper.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/lazy_metadata_wrapper.tsx similarity index 100% rename from x-pack/plugins/infra/public/components/asset_details/metadata/lazy_metadata_wrapper.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/lazy_metadata_wrapper.tsx diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/metadata.test.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.test.tsx similarity index 92% rename from x-pack/plugins/infra/public/components/asset_details/metadata/metadata.test.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.test.tsx index df2242dda3bb0..2373d0008d08d 100644 --- a/x-pack/plugins/infra/public/components/asset_details/metadata/metadata.test.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.test.tsx @@ -8,14 +8,14 @@ import React from 'react'; import { Metadata, type MetadataProps } from './metadata'; -import { useMetadata } from '../hooks/use_metadata'; -import { useSourceContext } from '../../../containers/metrics_source'; +import { useMetadata } from '../../hooks/use_metadata'; +import { useSourceContext } from '../../../../containers/metrics_source'; import { render } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n-react'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; -jest.mock('../../../containers/metrics_source'); -jest.mock('../hooks/use_metadata'); +jest.mock('../../../../containers/metrics_source'); +jest.mock('../../hooks/use_metadata'); const metadataProps: MetadataProps = { currentTimeRange: { diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/metadata.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx similarity index 79% rename from x-pack/plugins/infra/public/components/asset_details/metadata/metadata.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx index 2cf7fce4c9ce2..09217bc743149 100644 --- a/x-pack/plugins/infra/public/components/asset_details/metadata/metadata.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx @@ -9,14 +9,14 @@ import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiCallOut, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { InventoryItemType } from '../../../../common/inventory_models/types'; -import { findInventoryModel } from '../../../../common/inventory_models'; -import type { MetricsTimeInput } from '../../../pages/metrics/metric_detail/hooks/use_metrics_time'; -import { useMetadata } from '../hooks/use_metadata'; -import { useSourceContext } from '../../../containers/metrics_source'; +import type { InventoryItemType } from '../../../../../common/inventory_models/types'; +import { findInventoryModel } from '../../../../../common/inventory_models'; +import type { MetricsTimeInput } from '../../../../pages/metrics/metric_detail/hooks/use_metrics_time'; +import { useMetadata } from '../../hooks/use_metadata'; +import { useSourceContext } from '../../../../containers/metrics_source'; import { Table } from './table'; import { getAllFields } from './utils'; -import type { HostNodeRow } from '../types'; +import type { HostNodeRow } from '../../types'; export interface MetadataSearchUrlState { metadataSearchUrlState: string; @@ -28,15 +28,17 @@ export interface MetadataProps { node: HostNodeRow; nodeType: InventoryItemType; showActionsColumn?: boolean; - persistMetadataSearchToUrlState?: MetadataSearchUrlState; + search?: string; + onSearchChange?: (query: string) => void; } export const Metadata = ({ node, currentTimeRange, nodeType, - showActionsColumn, - persistMetadataSearchToUrlState, + search, + showActionsColumn = false, + onSearchChange, }: MetadataProps) => { const nodeId = node.name; const inventoryModel = findInventoryModel(nodeType); @@ -81,7 +83,8 @@ export const Metadata = ({ return ( { node={this.input.node} nodeType={this.input.nodeType} showActionsColumn={this.input.showActionsColumn} - persistMetadataSearchToUrlState={this.input.persistMetadataSearchToUrlState} + onSearchChange={this.input.onSearchChange} + search={this.input.search} /> diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/metadata_embeddable_factory.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata_embeddable_factory.ts similarity index 99% rename from x-pack/plugins/infra/public/components/asset_details/metadata/metadata_embeddable_factory.ts rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata_embeddable_factory.ts index e50d59ac51b0e..709bc49140f2f 100644 --- a/x-pack/plugins/infra/public/components/asset_details/metadata/metadata_embeddable_factory.ts +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata_embeddable_factory.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import type { EmbeddableFactoryDefinition, IContainer } from '@kbn/embeddable-plugin/public'; -import type { InfraClientStartServicesAccessor } from '../../../types'; +import type { InfraClientStartServicesAccessor } from '../../../../types'; import { MetadataEmbeddable, MetadataEmbeddableInput, diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/table.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/table.stories.tsx similarity index 98% rename from x-pack/plugins/infra/public/components/asset_details/metadata/table.stories.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/table.stories.tsx index c3d4c00d2cbda..48c17b35c70fe 100644 --- a/x-pack/plugins/infra/public/components/asset_details/metadata/table.stories.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/table.stories.tsx @@ -10,7 +10,7 @@ import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import type { Meta, Story } from '@storybook/react/types-6-0'; import React from 'react'; -import { decorateWithGlobalStorybookThemeProviders } from '../../../test_utils/use_global_storybook_theme'; +import { decorateWithGlobalStorybookThemeProviders } from '../../../../test_utils/use_global_storybook_theme'; import { Table, Props } from './table'; const mockServices = { diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/table.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/table.tsx similarity index 85% rename from x-pack/plugins/infra/public/components/asset_details/metadata/table.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/table.tsx index 8497552d6ddd9..6be4445c83d28 100644 --- a/x-pack/plugins/infra/public/components/asset_details/metadata/table.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/table.tsx @@ -21,7 +21,6 @@ import useToggle from 'react-use/lib/useToggle'; import { debounce } from 'lodash'; import { Query } from '@elastic/eui'; import { AddMetadataFilterButton } from './add_metadata_filter_button'; -import { MetadataSearchUrlState } from './metadata'; interface Row { name: string; @@ -32,7 +31,8 @@ export interface Props { rows: Row[]; loading: boolean; showActionsColumn?: boolean; - persistMetadataSearchToUrlState?: MetadataSearchUrlState; + search?: string; + onSearchChange?: (query: string) => void; } interface SearchErrorType { @@ -65,10 +65,9 @@ const LOADING = i18n.translate('xpack.infra.metadataEmbeddable.loading', { defaultMessage: 'Loading...', }); -export const Table = (props: Props) => { - const { rows, loading, showActionsColumn } = props; +export const Table = ({ loading, rows, onSearchChange, search, showActionsColumn }: Props) => { const [searchError, setSearchError] = useState(null); - const [metadataSearch, setMetadataSearch] = useState(''); + const [metadataSearch, setMetadataSearch] = useState(search); const defaultColumns = useMemo( () => [ @@ -93,13 +92,12 @@ export const Table = (props: Props) => { const debouncedSearchOnChange = useMemo( () => debounce<(queryText: string) => void>((queryText) => { - return props.persistMetadataSearchToUrlState - ? props.persistMetadataSearchToUrlState.setMetadataSearchUrlState({ - metadataSearch: String(queryText) ?? '', - }) - : setMetadataSearch(String(queryText) ?? ''); + if (onSearchChange) { + onSearchChange(queryText); + } + setMetadataSearch(queryText); }, 500), - [props.persistMetadataSearchToUrlState] + [onSearchChange] ); const searchBarOnChange = useCallback( @@ -114,7 +112,7 @@ export const Table = (props: Props) => { [debouncedSearchOnChange] ); - const search: EuiSearchBarProps = { + const searchBar: EuiSearchBarProps = { onChange: searchBarOnChange, box: { 'data-test-subj': 'infraHostMetadataSearchBarInput', @@ -122,13 +120,7 @@ export const Table = (props: Props) => { schema: true, placeholder: SEARCH_PLACEHOLDER, }, - query: props.persistMetadataSearchToUrlState - ? props.persistMetadataSearchToUrlState.metadataSearchUrlState - ? Query.parse(props.persistMetadataSearchToUrlState.metadataSearchUrlState) - : Query.MATCH_ALL - : metadataSearch - ? Query.parse(metadataSearch) - : Query.MATCH_ALL, + query: metadataSearch ? Query.parse(metadataSearch) : Query.MATCH_ALL, }; const columns = useMemo( @@ -159,7 +151,7 @@ export const Table = (props: Props) => { columns={columns} items={rows} rowProps={{ className: 'euiTableRow-hasActions' }} - search={search} + search={searchBar} loading={loading} error={searchError ? `${searchError.message}` : ''} message={ diff --git a/x-pack/plugins/infra/public/components/asset_details/metadata/utils.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/utils.ts similarity index 97% rename from x-pack/plugins/infra/public/components/asset_details/metadata/utils.ts rename to x-pack/plugins/infra/public/components/asset_details/tabs/metadata/utils.ts index e8dd94df751e8..f277eb1c337e5 100644 --- a/x-pack/plugins/infra/public/components/asset_details/metadata/utils.ts +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { InfraMetadata } from '../../../../common/http_api'; +import type { InfraMetadata } from '../../../../../common/http_api'; export const getAllFields = (metadata: InfraMetadata | null) => { if (!metadata?.info) return []; diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/parse_search_string.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/parse_search_string.ts similarity index 100% rename from x-pack/plugins/infra/public/components/asset_details/processes/parse_search_string.ts rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/parse_search_string.ts diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/processes.stories.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.stories.tsx similarity index 97% rename from x-pack/plugins/infra/public/components/asset_details/processes/processes.stories.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.stories.tsx index 42e04737509d6..09b4d30147c17 100644 --- a/x-pack/plugins/infra/public/components/asset_details/processes/processes.stories.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.stories.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { DecorateWithKibanaContext } from './processes.story_decorators'; import { Processes, type ProcessesProps } from './processes'; -import { decorateWithGlobalStorybookThemeProviders } from '../../../test_utils/use_global_storybook_theme'; +import { decorateWithGlobalStorybookThemeProviders } from '../../../../test_utils/use_global_storybook_theme'; export default { title: 'infra/Asset Details View/Components/Processes', diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/processes.story_decorators.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.story_decorators.tsx similarity index 99% rename from x-pack/plugins/infra/public/components/asset_details/processes/processes.story_decorators.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.story_decorators.tsx index 29e4b4b79faff..4310467a51aec 100644 --- a/x-pack/plugins/infra/public/components/asset_details/processes/processes.story_decorators.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.story_decorators.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { useParameter } from '@storybook/addons'; import { I18nProvider } from '@kbn/i18n-react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { SourceProvider } from '../../../containers/metrics_source'; +import { SourceProvider } from '../../../../containers/metrics_source'; export const DecorateWithKibanaContext = ( wrappedStory: () => StoryFnReactReturnType, diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/processes.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx similarity index 88% rename from x-pack/plugins/infra/public/components/asset_details/processes/processes.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx index c014e9a3c457a..cb6660c64a926 100644 --- a/x-pack/plugins/infra/public/components/asset_details/processes/processes.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx @@ -21,22 +21,22 @@ import { parseSearchString } from './parse_search_string'; import { ProcessesTable } from './processes_table'; import { STATE_NAMES } from './states'; import { SummaryTable } from './summary_table'; -import { TabContent } from '../../../pages/metrics/inventory_view/components/node_details/tabs/shared'; +import { TabContent } from '../../../../pages/metrics/inventory_view/components/node_details/tabs/shared'; import { SortBy, useProcessList, ProcessListContextProvider, -} from '../../../pages/metrics/inventory_view/hooks/use_process_list'; -import { getFieldByType } from '../../../../common/inventory_models'; -import type { HostNodeRow } from '../types'; -import type { InventoryItemType } from '../../../../common/inventory_models/types'; +} from '../../../../pages/metrics/inventory_view/hooks/use_process_list'; +import { getFieldByType } from '../../../../../common/inventory_models'; +import type { HostNodeRow } from '../../types'; +import type { InventoryItemType } from '../../../../../common/inventory_models/types'; export interface ProcessesProps { node: HostNodeRow; nodeType: InventoryItemType; currentTime: number; searchFilter?: string; - setSearchFilter?: (searchFilter: { searchFilter: string }) => void; + onSearchFilterChange?: (searchFilter: string) => void; } const options = Object.entries(STATE_NAMES).map(([value, view]: [string, string]) => ({ @@ -49,7 +49,7 @@ export const Processes = ({ node, nodeType, searchFilter, - setSearchFilter, + onSearchFilterChange, }: ProcessesProps) => { const [searchText, setSearchText] = useState(searchFilter ?? ''); const [searchBarState, setSearchBarState] = useState(() => @@ -75,12 +75,12 @@ export const Processes = ({ const debouncedSearchOnChange = useMemo(() => { return debounce<(queryText: string) => void>((queryText) => { - if (setSearchFilter) { - setSearchFilter({ searchFilter: queryText }); + if (onSearchFilterChange) { + onSearchFilterChange(queryText); } setSearchText(queryText); }, 500); - }, [setSearchFilter]); + }, [onSearchFilterChange]); const searchBarOnChange = useCallback( ({ query, queryText }) => { @@ -92,11 +92,11 @@ export const Processes = ({ const clearSearchBar = useCallback(() => { setSearchBarState(Query.MATCH_ALL); - if (setSearchFilter) { - setSearchFilter({ searchFilter: '' }); + if (onSearchFilterChange) { + onSearchFilterChange(''); } setSearchText(''); - }, [setSearchFilter]); + }, [onSearchFilterChange]); return ( diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/processes_table.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes_table.tsx similarity index 96% rename from x-pack/plugins/infra/public/components/asset_details/processes/processes_table.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes_table.tsx index d885cac7cf255..09111093a226a 100644 --- a/x-pack/plugins/infra/public/components/asset_details/processes/processes_table.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes_table.tsx @@ -25,13 +25,13 @@ import { RIGHT_ALIGNMENT, } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import { FORMATTERS } from '../../../../common/formatters'; -import type { SortBy } from '../../../pages/metrics/inventory_view/hooks/use_process_list'; +import { FORMATTERS } from '../../../../../common/formatters'; +import type { SortBy } from '../../../../pages/metrics/inventory_view/hooks/use_process_list'; import type { Process } from './types'; -import { ProcessRow } from '../../../pages/metrics/inventory_view/components/node_details/tabs/processes/process_row'; +import { ProcessRow } from '../../../../pages/metrics/inventory_view/components/node_details/tabs/processes/process_row'; import { StateBadge } from './state_badge'; import { STATE_ORDER } from './states'; -import type { ProcessListAPIResponse } from '../../../../common/http_api'; +import type { ProcessListAPIResponse } from '../../../../../common/http_api'; interface TableProps { processList: ProcessListAPIResponse['processList']; diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/state_badge.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/state_badge.tsx similarity index 100% rename from x-pack/plugins/infra/public/components/asset_details/processes/state_badge.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/state_badge.tsx diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/states.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/states.ts similarity index 100% rename from x-pack/plugins/infra/public/components/asset_details/processes/states.ts rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/states.ts diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/summary_table.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/summary_table.tsx similarity index 97% rename from x-pack/plugins/infra/public/components/asset_details/processes/summary_table.tsx rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/summary_table.tsx index 92007d769a4eb..6cbf25013f876 100644 --- a/x-pack/plugins/infra/public/components/asset_details/processes/summary_table.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/summary_table.tsx @@ -18,7 +18,7 @@ import { EuiHorizontalRule, } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; -import type { ProcessListAPIResponse } from '../../../../common/http_api'; +import type { ProcessListAPIResponse } from '../../../../../common/http_api'; import { STATE_NAMES } from './states'; interface Props { diff --git a/x-pack/plugins/infra/public/components/asset_details/processes/types.ts b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/types.ts similarity index 87% rename from x-pack/plugins/infra/public/components/asset_details/processes/types.ts rename to x-pack/plugins/infra/public/components/asset_details/tabs/processes/types.ts index ef4b177ecae4b..024ffe9e5cdf5 100644 --- a/x-pack/plugins/infra/public/components/asset_details/processes/types.ts +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { MetricsExplorerSeries } from '../../../../common/http_api'; +import type { MetricsExplorerSeries } from '../../../../../common/http_api'; import { STATE_NAMES } from './states'; export interface Process { diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs_content/tabs_content.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs_content/tabs_content.tsx deleted file mode 100644 index e4c2d028defdf..0000000000000 --- a/x-pack/plugins/infra/public/components/asset_details/tabs_content/tabs_content.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { type AssetDetailsProps, type TabIds, FlyoutTabIds } from '../asset_details'; -import Metadata from '../metadata/metadata'; -import { Processes } from '../processes/processes'; - -export const AssetDetailsTabContent = ({ - renderedTabsSet, - hostFlyoutOpen, - currentTimeRange, - node, - nodeType, - showActionsColumn, - setHostFlyoutState, - selectedTabId, -}: Pick< - AssetDetailsProps, - | 'renderedTabsSet' - | 'hostFlyoutOpen' - | 'currentTimeRange' - | 'node' - | 'nodeType' - | 'showActionsColumn' - | 'setHostFlyoutState' -> & { selectedTabId: TabIds }) => { - const persistMetadataSearchToUrlState = - setHostFlyoutState && hostFlyoutOpen - ? { - metadataSearchUrlState: hostFlyoutOpen.metadataSearch, - setMetadataSearchUrlState: setHostFlyoutState, - } - : undefined; - - const isTabSelected = (flyoutTabId: FlyoutTabIds) => { - return selectedTabId === flyoutTabId; - }; - - return ( - <> - {renderedTabsSet.current.has(FlyoutTabIds.METADATA) && ( - - )} - {renderedTabsSet.current.has(FlyoutTabIds.PROCESSES) && ( - - )} - - ); -}; diff --git a/x-pack/plugins/infra/public/components/asset_details/types.ts b/x-pack/plugins/infra/public/components/asset_details/types.ts index 8432d6f7085ef..2fdee6e59a811 100644 --- a/x-pack/plugins/infra/public/components/asset_details/types.ts +++ b/x-pack/plugins/infra/public/components/asset_details/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { InventoryItemType } from '../../../common/inventory_models/types'; import { InfraAssetMetricType } from '../../../common/http_api'; export type CloudProvider = 'gcp' | 'aws' | 'azure' | 'unknownProvider'; @@ -21,3 +22,55 @@ export type HostNodeRow = HostMetadata & HostMetrics & { name: string; }; + +export enum FlyoutTabIds { + METADATA = 'metadata', + PROCESSES = 'processes', +} + +export type TabIds = `${FlyoutTabIds}`; + +export interface TabState { + metadata?: { + query?: string; + showActionsColumn?: boolean; + }; + processes?: { + query?: string; + }; +} + +export interface FlyoutProps { + closeFlyout: () => void; + showInFlyout: true; +} + +export interface FullPageProps { + showInFlyout: false; +} + +export type RenderMode = FlyoutProps | FullPageProps; + +export interface Tab { + id: FlyoutTabIds; + name: string; + 'data-test-subj': string; +} + +export interface AssetDetailsProps { + node: HostNodeRow; + nodeType: InventoryItemType; + currentTimeRange: { + interval: string; + from: number; + to: number; + }; + tabs: Tab[]; + activeTabId?: TabIds; + overrides?: TabState; + renderMode?: RenderMode; + onTabsStateChange?: TabsStateChangeFn; + links?: Array<'uptime' | 'apmServices'>; +} + +export type TabsStateChangeFn = (state: TabState & { activeTabId?: TabIds }) => void; diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts index d748647935356..d636cefa04905 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/api/validate_indices.ts @@ -28,6 +28,7 @@ export const callValidateIndicesAPI = async (requestArgs: RequestArgs, fetch: Ht const response = await fetch(LOG_ANALYSIS_VALIDATE_INDICES_PATH, { method: 'POST', body: JSON.stringify( + // @ts-expect-error TODO: fix after elasticsearch-js bump validationIndicesRequestPayloadRT.encode({ data: { indices, fields, runtimeMappings } }) ), }); diff --git a/x-pack/plugins/infra/public/locators/discover_logs_locator.ts b/x-pack/plugins/infra/public/locators/discover_logs_locator.ts index 8693c5e281078..9e610d41af34b 100644 --- a/x-pack/plugins/infra/public/locators/discover_logs_locator.ts +++ b/x-pack/plugins/infra/public/locators/discover_logs_locator.ts @@ -7,13 +7,12 @@ import { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public'; import type { LogsLocatorDependencies, LogsLocatorParams } from './logs_locator'; - -const DISCOVER_LOGS_LOCATOR_ID = 'DISCOVER_LOGS_LOCATOR'; +import { LOGS_LOCATOR_ID } from './logs_locator'; export type DiscoverLogsLocator = LocatorPublic; export class DiscoverLogsLocatorDefinition implements LocatorDefinition { - public readonly id = DISCOVER_LOGS_LOCATOR_ID; + public readonly id = LOGS_LOCATOR_ID; constructor(protected readonly deps: LogsLocatorDependencies) {} diff --git a/x-pack/plugins/infra/public/locators/discover_node_logs_locator.ts b/x-pack/plugins/infra/public/locators/discover_node_logs_locator.ts index 727c7abb401a5..e4ad2b34c5e66 100644 --- a/x-pack/plugins/infra/public/locators/discover_node_logs_locator.ts +++ b/x-pack/plugins/infra/public/locators/discover_node_logs_locator.ts @@ -7,13 +7,12 @@ import { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public'; import type { NodeLogsLocatorDependencies, NodeLogsLocatorParams } from './node_logs_locator'; - -const DISCOVER_NODE_LOGS_LOCATOR_ID = 'DISCOVER_NODE_LOGS_LOCATOR'; +import { NODE_LOGS_LOCATOR_ID } from './node_logs_locator'; export type DiscoverNodeLogsLocator = LocatorPublic; export class DiscoverNodeLogsLocatorDefinition implements LocatorDefinition { - public readonly id = DISCOVER_NODE_LOGS_LOCATOR_ID; + public readonly id = NODE_LOGS_LOCATOR_ID; constructor(protected readonly deps: NodeLogsLocatorDependencies) {} diff --git a/x-pack/plugins/infra/public/locators/logs_locator.ts b/x-pack/plugins/infra/public/locators/logs_locator.ts index fd78b9cce74fe..3c95384ff9af7 100644 --- a/x-pack/plugins/infra/public/locators/logs_locator.ts +++ b/x-pack/plugins/infra/public/locators/logs_locator.ts @@ -11,7 +11,7 @@ import type { LogViewReference } from '../../common/log_views'; import type { TimeRange } from '../../common/time'; import type { InfraClientCoreSetup } from '../types'; -const LOGS_LOCATOR_ID = 'LOGS_LOCATOR'; +export const LOGS_LOCATOR_ID = 'LOGS_LOCATOR'; export interface LogsLocatorParams extends SerializableRecord { /** Defines log position */ diff --git a/x-pack/plugins/infra/public/locators/node_logs_locator.ts b/x-pack/plugins/infra/public/locators/node_logs_locator.ts index afa49882262c4..f0c9ad0ff73ca 100644 --- a/x-pack/plugins/infra/public/locators/node_logs_locator.ts +++ b/x-pack/plugins/infra/public/locators/node_logs_locator.ts @@ -9,7 +9,7 @@ import { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public'; import type { InventoryItemType } from '../../common/inventory_models/types'; import type { LogsLocatorDependencies, LogsLocatorParams } from './logs_locator'; -const NODE_LOGS_LOCATOR_ID = 'NODE_LOGS_LOCATOR'; +export const NODE_LOGS_LOCATOR_ID = 'NODE_LOGS_LOCATOR'; export interface NodeLogsLocatorParams extends LogsLocatorParams { nodeId: string; diff --git a/x-pack/plugins/infra/public/pages/link_to/index.ts b/x-pack/plugins/infra/public/pages/link_to/index.ts index d2a10b0c4504f..0991c6dba1936 100644 --- a/x-pack/plugins/infra/public/pages/link_to/index.ts +++ b/x-pack/plugins/infra/public/pages/link_to/index.ts @@ -7,5 +7,5 @@ export { LinkToLogsPage } from './link_to_logs'; export { LinkToMetricsPage } from './link_to_metrics'; -export { getNodeLogsUrl, RedirectToNodeLogs } from './redirect_to_node_logs'; +export { RedirectToNodeLogs } from './redirect_to_node_logs'; export { getNodeDetailUrl, RedirectToNodeDetail } from './redirect_to_node_detail'; diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx index ab5723427a1ec..7cf40df09b80e 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { LinkDescriptor } from '@kbn/observability-shared-plugin/public'; import { useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { InventoryItemType } from '../../../common/inventory_models/types'; @@ -47,23 +46,3 @@ export const RedirectToNodeLogs = ({ return null; }; - -export const getNodeLogsUrl = ({ - nodeId, - nodeType, - time, -}: { - nodeId: string; - nodeType: InventoryItemType; - time?: number; -}): LinkDescriptor => { - return { - app: 'logs', - pathname: `link-to/${nodeType}-logs/${nodeId}`, - search: time - ? { - time: `${time}`, - } - : undefined, - }; -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx index fda3185b4c363..7686330566d6a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx @@ -8,10 +8,8 @@ import React, { useMemo } from 'react'; import type { InventoryItemType } from '../../../../../../common/inventory_models/types'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search'; -import { useLazyRef } from '../../../../../hooks/use_lazy_ref'; import type { HostNodeRow } from '../../hooks/use_hosts_table'; -import type { Tab } from '../../../../../components/asset_details/asset_details'; -import { useHostFlyoutOpen } from '../../hooks/use_host_flyout_open_url_state'; +import { HostFlyout, useHostFlyoutUrlState } from '../../hooks/use_host_flyout_url_state'; import { AssetDetails } from '../../../../../components/asset_details/asset_details'; import { metadataTab, processesTab } from './tabs'; @@ -32,31 +30,36 @@ export const FlyoutWrapper = ({ node, closeFlyout }: Props) => { [getDateRangeAsTimestamp] ); - const [hostFlyoutOpen, setHostFlyoutOpen] = useHostFlyoutOpen(); - - // This map allow to keep track of which tabs content have been rendered the first time. - // We need it in order to load a tab content only if it gets clicked, and then keep it in the DOM for performance improvement. - const renderedTabsSet = useLazyRef(() => new Set([hostFlyoutOpen?.selectedTabId])); - - const onTabClick = (tab: Tab) => { - renderedTabsSet.current.add(tab.id); // On a tab click, mark the tab content as allowed to be rendered - setHostFlyoutOpen({ selectedTabId: tab.id }); - }; + const [hostFlyoutOpen, setHostFlyoutOpen] = useHostFlyoutUrlState(); return ( + setHostFlyoutOpen({ + metadataSearch: state.metadata?.query, + processSearch: state.processes?.query, + selectedTabId: state.activeTabId as HostFlyout['selectedTabId'], + }) + } tabs={[metadataTab, processesTab]} links={['apmServices', 'uptime']} - nodeType={NODE_TYPE} + renderMode={{ + showInFlyout: true, + closeFlyout, + }} /> ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/tabs.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/tabs.ts index 8485664a4cd6a..43ada7b6ae4bf 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/tabs.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/tabs.ts @@ -6,8 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { Tab } from '../../../../../components/asset_details/asset_details'; -import { FlyoutTabIds } from '../../hooks/use_host_flyout_open_url_state'; +import { FlyoutTabIds, type Tab } from '../../../../../components/asset_details/types'; export const processesTab: Tab = { id: FlyoutTabIds.PROCESSES, diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_flyout_open_url_state.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_flyout_open_url_state.ts deleted file mode 100644 index 1db5787719a74..0000000000000 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_flyout_open_url_state.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as rt from 'io-ts'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { constant, identity } from 'fp-ts/lib/function'; -import { useUrlState } from '../../../../utils/use_url_state'; - -export enum FlyoutTabIds { - METADATA = 'metadata', - PROCESSES = 'processes', -} - -export const GET_DEFAULT_TABLE_PROPERTIES = { - clickedItemId: '', - selectedTabId: FlyoutTabIds.METADATA, - searchFilter: '', - metadataSearch: '', -}; -const HOST_TABLE_PROPERTIES_URL_STATE_KEY = 'hostFlyoutOpen'; - -type Action = rt.TypeOf; -export type SetNewHostFlyoutOpen = (newProp: Action) => void; -type SetNewHostFlyoutClose = () => void; - -export const useHostFlyoutOpen = (): [ - HostFlyoutOpen, - SetNewHostFlyoutOpen, - SetNewHostFlyoutClose -] => { - const [urlState, setUrlState] = useUrlState({ - defaultState: '', - decodeUrlState, - encodeUrlState, - urlStateKey: HOST_TABLE_PROPERTIES_URL_STATE_KEY, - }); - - const setHostFlyoutOpen = (newProps: Action) => - typeof urlState !== 'string' - ? setUrlState({ ...urlState, ...newProps }) - : setUrlState({ ...GET_DEFAULT_TABLE_PROPERTIES, ...newProps }); - - const setFlyoutClosed = () => setUrlState(''); - - return [urlState as HostFlyoutOpen, setHostFlyoutOpen, setFlyoutClosed]; -}; - -const FlyoutTabIdRT = rt.union([rt.literal('metadata'), rt.literal('processes')]); -const ClickedItemIdRT = rt.string; -const SearchFilterRT = rt.string; - -const SetFlyoutTabId = rt.partial({ - selectedTabId: FlyoutTabIdRT, -}); - -const SetClickedItemIdRT = rt.partial({ - clickedItemId: ClickedItemIdRT, -}); - -const SetSearchFilterRT = rt.partial({ - searchFilter: SearchFilterRT, -}); - -const SetMetadataSearchRT = rt.partial({ - metadataSearch: SearchFilterRT, -}); - -const ActionRT = rt.intersection([ - SetClickedItemIdRT, - SetFlyoutTabId, - SetSearchFilterRT, - SetMetadataSearchRT, -]); - -const HostFlyoutOpenRT = rt.type({ - clickedItemId: ClickedItemIdRT, - selectedTabId: FlyoutTabIdRT, - searchFilter: SearchFilterRT, - metadataSearch: SearchFilterRT, -}); - -const HostFlyoutUrlRT = rt.union([HostFlyoutOpenRT, rt.string]); - -type HostFlyoutUrl = rt.TypeOf; -type HostFlyoutOpen = rt.TypeOf; - -const encodeUrlState = HostFlyoutUrlRT.encode; -const decodeUrlState = (value: unknown) => { - return pipe(HostFlyoutUrlRT.decode(value), fold(constant('undefined'), identity)); -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_flyout_url_state.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_flyout_url_state.ts new file mode 100644 index 0000000000000..e54a48a9432f3 --- /dev/null +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_flyout_url_state.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as rt from 'io-ts'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { fold } from 'fp-ts/lib/Either'; +import { constant, identity } from 'fp-ts/lib/function'; +import isEmpty from 'lodash/isEmpty'; +import omitBy from 'lodash/omitBy'; +import { FlyoutTabIds } from '../../../../components/asset_details/types'; +import { useUrlState } from '../../../../utils/use_url_state'; + +export const DEFAULT_STATE: HostFlyout = { + clickedItemId: '', + selectedTabId: FlyoutTabIds.METADATA, + processSearch: undefined, + metadataSearch: undefined, +}; +const HOST_FLYOUT_URL_STATE_KEY = 'hostFlyoutOpen'; + +type SetHostFlyoutState = (newProp: Payload | null) => void; + +export const useHostFlyoutUrlState = (): [HostFlyoutUrl, SetHostFlyoutState] => { + const [urlState, setUrlState] = useUrlState({ + defaultState: null, + decodeUrlState, + encodeUrlState, + urlStateKey: HOST_FLYOUT_URL_STATE_KEY, + }); + + const setHostFlyoutState = (newProps: Payload | null) => { + if (!newProps) { + setUrlState(DEFAULT_STATE); + } else { + const payload = omitBy(newProps, isEmpty); + setUrlState({ ...(urlState ?? DEFAULT_STATE), ...payload }); + } + }; + + return [urlState as HostFlyoutUrl, setHostFlyoutState]; +}; + +const FlyoutTabIdRT = rt.union([ + rt.literal(FlyoutTabIds.METADATA), + rt.literal(FlyoutTabIds.PROCESSES), +]); + +const HostFlyoutStateRT = rt.intersection([ + rt.type({ + clickedItemId: rt.string, + selectedTabId: FlyoutTabIdRT, + }), + rt.partial({ + processSearch: rt.string, + metadataSearch: rt.string, + }), +]); + +const HostFlyoutUrlRT = rt.union([HostFlyoutStateRT, rt.null]); + +type HostFlyoutState = rt.TypeOf; +type HostFlyoutUrl = rt.TypeOf; +type Payload = Partial; +export type HostFlyout = rt.TypeOf; + +const encodeUrlState = HostFlyoutUrlRT.encode; +const decodeUrlState = (value: unknown) => { + return pipe(HostFlyoutUrlRT.decode(value), fold(constant(undefined), identity)); +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx index 6fb206880cf44..ae2796d9d7b27 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx @@ -20,7 +20,7 @@ import { InfraAssetMetricsItem, InfraAssetMetricType, } from '../../../../../common/http_api'; -import { useHostFlyoutOpen } from './use_host_flyout_open_url_state'; +import { useHostFlyoutUrlState } from './use_host_flyout_url_state'; import { Sorting, useHostsTableUrlState } from './use_hosts_table_url_state'; import { useHostsViewContext } from './use_hosts_view'; import { useUnifiedSearchContext } from './use_unified_search'; @@ -171,9 +171,9 @@ export const useHostsTable = () => { services: { telemetry }, } = useKibanaContextForPlugin(); - const [hostFlyoutOpen, setHostFlyoutOpen, setFlyoutClosed] = useHostFlyoutOpen(); + const [hostFlyoutState, setHostFlyoutState] = useHostFlyoutUrlState(); - const closeFlyout = () => setFlyoutClosed(); + const closeFlyout = useCallback(() => setHostFlyoutState(null), [setHostFlyoutState]); const reportHostEntryClick = useCallback( ({ name, cloudProvider }: HostNodeRow['title']) => { @@ -204,8 +204,8 @@ export const useHostsTable = () => { const items = useMemo(() => buildItemsList(hostNodes), [hostNodes]); const clickedItem = useMemo( - () => items.find(({ id }) => id === hostFlyoutOpen.clickedItemId), - [hostFlyoutOpen.clickedItemId, items] + () => items.find(({ id }) => id === hostFlyoutState?.clickedItemId), + [hostFlyoutState?.clickedItemId, items] ); const currentPage = useMemo(() => { @@ -228,19 +228,19 @@ export const useHostsTable = () => { name: toggleDialogActionLabel, description: toggleDialogActionLabel, icon: ({ id }) => - hostFlyoutOpen.clickedItemId && id === hostFlyoutOpen.clickedItemId + hostFlyoutState?.clickedItemId && id === hostFlyoutState?.clickedItemId ? 'minimize' : 'expand', type: 'icon', 'data-test-subj': 'hostsView-flyout-button', onClick: ({ id }) => { - setHostFlyoutOpen({ + setHostFlyoutState({ clickedItemId: id, }); - if (id === hostFlyoutOpen.clickedItemId) { - setFlyoutClosed(); + if (id === hostFlyoutState?.clickedItemId) { + setHostFlyoutState(null); } else { - setHostFlyoutOpen({ clickedItemId: id }); + setHostFlyoutState({ clickedItemId: id }); } }, }, @@ -317,11 +317,10 @@ export const useHostsTable = () => { }, ], [ - hostFlyoutOpen.clickedItemId, + hostFlyoutState?.clickedItemId, reportHostEntryClick, searchCriteria.dateRange, - setFlyoutClosed, - setHostFlyoutOpen, + setHostFlyoutState, ] ); @@ -331,7 +330,7 @@ export const useHostsTable = () => { currentPage, closeFlyout, items, - isFlyoutOpen: !!hostFlyoutOpen.clickedItemId, + isFlyoutOpen: !!hostFlyoutState?.clickedItemId, onTableChange, pagination, sorting, diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx index 773a1261e81e2..3024ff3d1bd06 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/node_details/tabs/logs.tsx @@ -13,14 +13,16 @@ import { EuiFieldSearch } from '@elastic/eui'; import { EuiFlexGroup } from '@elastic/eui'; import { EuiFlexItem } from '@elastic/eui'; import { EuiButtonEmpty } from '@elastic/eui'; -import { useLinkProps } from '@kbn/observability-shared-plugin/public'; +import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; +import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; import { TabContent, TabProps } from './shared'; import { LogStream } from '../../../../../../components/log_stream'; import { useWaffleOptionsContext } from '../../../hooks/use_waffle_options'; import { findInventoryFields } from '../../../../../../../common/inventory_models'; -import { getNodeLogsUrl } from '../../../../../link_to'; const TabComponent = (props: TabProps) => { + const { services } = useKibanaContextForPlugin(); + const { locators } = services; const [textQuery, setTextQuery] = useState(''); const [textQueryDebounced, setTextQueryDebounced] = useState(''); const endTimestamp = props.currentTime; @@ -46,13 +48,14 @@ const TabComponent = (props: TabProps) => { setTextQuery(e.target.value); }, []); - const nodeLogsMenuItemLinkProps = useLinkProps( - getNodeLogsUrl({ + const logsUrl = useMemo(() => { + return locators.nodeLogsLocator.getRedirectUrl({ nodeType, nodeId: node.id, time: startTimestamp, - }) - ); + filter: textQueryDebounced, + }); + }, [locators.nodeLogsLocator, node.id, nodeType, startTimestamp, textQueryDebounced]); return ( @@ -70,18 +73,20 @@ const TabComponent = (props: TabProps) => { /> - - - + + + + + = withTheme const [flyoutVisible, setFlyoutVisible] = useState(false); const inventoryModel = findInventoryModel(nodeType); const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; - const { application, share } = useKibana() - .services; + const { services } = useKibanaContextForPlugin(); + const { application, share, locators } = services; const uiCapabilities = application?.capabilities; // Due to the changing nature of the fields between APM and this UI, // We need to have some exceptions until 7.0 & ECS is finalized. Reference @@ -76,13 +75,6 @@ export const NodeContextMenu: React.FC = withTheme return { label: '', value: '' }; }, [nodeType, node.ip, node.id]); - const nodeLogsMenuItemLinkProps = useLinkProps( - getNodeLogsUrl({ - nodeType, - nodeId: node.id, - time: currentTime, - }) - ); const nodeDetailMenuItemLinkProps = useLinkProps({ ...getNodeDetailUrl({ nodeType, @@ -104,7 +96,11 @@ export const NodeContextMenu: React.FC = withTheme defaultMessage: '{inventoryName} logs', values: { inventoryName: inventoryModel.singularDisplayName }, }), - ...nodeLogsMenuItemLinkProps, + href: locators.nodeLogsLocator.getRedirectUrl({ + nodeType, + nodeId: node.id, + time: currentTime, + }), 'data-test-subj': 'viewLogsContextMenuItem', isDisabled: !showLogsLink, }; diff --git a/x-pack/plugins/infra/server/lib/sources/index.ts b/x-pack/plugins/infra/server/lib/sources/index.ts index 73b50ac2662cc..1afcd7415daf6 100644 --- a/x-pack/plugins/infra/server/lib/sources/index.ts +++ b/x-pack/plugins/infra/server/lib/sources/index.ts @@ -12,3 +12,4 @@ export { } from './saved_object_type'; export * from './sources'; export * from '../../../common/source_configuration/source_configuration'; +export { SourceConfigurationSavedObjectRT } from './types'; diff --git a/x-pack/plugins/infra/server/lib/sources/sources.ts b/x-pack/plugins/infra/server/lib/sources/sources.ts index c1042f3794f0c..693c4aba20ae1 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.ts @@ -22,8 +22,8 @@ import { InfraStaticSourceConfiguration, SourceConfigurationConfigFileProperties, sourceConfigurationConfigFilePropertiesRT, - SourceConfigurationSavedObjectRuntimeType, } from '../../../common/source_configuration/source_configuration'; +import { SourceConfigurationSavedObjectRT } from '.'; import { InfraConfig } from '../..'; import { defaultSourceConfiguration } from './defaults'; import { AnomalyThresholdRangeError, NotFoundError } from './errors'; @@ -258,7 +258,7 @@ export const mergeSourceConfiguration = ( export const convertSavedObjectToSavedSourceConfiguration = (savedObject: SavedObject) => pipe( - SourceConfigurationSavedObjectRuntimeType.decode(savedObject), + SourceConfigurationSavedObjectRT.decode(savedObject), map((savedSourceConfiguration) => ({ id: savedSourceConfiguration.id, version: savedSourceConfiguration.version, diff --git a/x-pack/plugins/infra/server/lib/sources/types.ts b/x-pack/plugins/infra/server/lib/sources/types.ts new file mode 100644 index 0000000000000..7c2448dc48018 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/sources/types.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 * as rt from 'io-ts'; +import moment from 'moment'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { chain } from 'fp-ts/lib/Either'; + +export const TimestampFromString = new rt.Type( + 'TimestampFromString', + (input): input is number => typeof input === 'number', + (input, context) => + pipe( + rt.string.validate(input, context), + chain((stringInput) => { + const momentValue = moment(stringInput); + return momentValue.isValid() + ? rt.success(momentValue.valueOf()) + : rt.failure(stringInput, context); + }) + ), + (output) => new Date(output).toISOString() +); + +export const SourceConfigurationSavedObjectFieldColumnRT = rt.type({ + fieldColumn: rt.type({ + id: rt.string, + field: rt.string, + }), +}); + +export const SourceConfigurationSavedObjectMessageColumnRT = rt.type({ + messageColumn: rt.type({ + id: rt.string, + }), +}); + +export const SourceConfigurationSavedObjectTimestampColumnRT = rt.type({ + timestampColumn: rt.type({ + id: rt.string, + }), +}); + +export const SourceConfigurationSavedObjectColumnRT = rt.union([ + SourceConfigurationSavedObjectTimestampColumnRT, + SourceConfigurationSavedObjectMessageColumnRT, + SourceConfigurationSavedObjectFieldColumnRT, +]); + +export const logIndexPatternSavedObjectReferenceRT = rt.type({ + type: rt.literal('index_pattern'), + indexPatternId: rt.string, +}); + +export const logIndexNameSavedObjectReferenceRT = rt.type({ + type: rt.literal('index_name'), + indexName: rt.string, +}); + +export const logIndexSavedObjectReferenceRT = rt.union([ + logIndexPatternSavedObjectReferenceRT, + logIndexNameSavedObjectReferenceRT, +]); + +export const SourceConfigurationSavedObjectAttributesRT = rt.type({ + name: rt.string, + description: rt.string, + metricAlias: rt.string, + logIndices: logIndexSavedObjectReferenceRT, + inventoryDefaultView: rt.string, + metricsExplorerDefaultView: rt.string, + fields: rt.record(rt.string, rt.unknown), + logColumns: rt.array(SourceConfigurationSavedObjectColumnRT), + anomalyThreshold: rt.number, +}); + +export const SavedSourceConfigurationSavedObjectRT = rt.partial( + SourceConfigurationSavedObjectAttributesRT.props +); + +export const SourceConfigurationSavedObjectRT = rt.intersection([ + rt.type({ + id: rt.string, + attributes: SavedSourceConfigurationSavedObjectRT, + }), + rt.partial({ + version: rt.string, + updated_at: TimestampFromString, + }), +]); diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts index 175ef4eb37179..29b282b5fbf20 100644 --- a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts @@ -40,7 +40,6 @@ export const registerPrivilegesRoute = ({ router, config }: RouteDependencies) = const { has_all_requested: hasAllPrivileges, cluster } = await clusterClient.asCurrentUser.security.hasPrivileges({ - // @ts-expect-error @elastic/elasticsearch SecurityClusterPrivilege doesn’t contain all the priviledges body: { cluster: APP_CLUSTER_REQUIRED_PRIVILEGES }, }); diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 8c843e67cea87..f99b3bf1719b4 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -23,17 +23,16 @@ export const INITIAL_LAYERS_KEY = 'initialLayers'; export const MAPS_APP_PATH = `app/${APP_ID}`; export const MAP_PATH = 'map'; -export const GIS_API_PATH = `api/${APP_ID}`; -export const INDEX_SETTINGS_API_PATH = `${GIS_API_PATH}/indexSettings`; -export const FONTS_API_PATH = `${GIS_API_PATH}/fonts`; -export const INDEX_SOURCE_API_PATH = `${GIS_API_PATH}/docSource`; -export const API_ROOT_PATH = `/${GIS_API_PATH}`; -export const INDEX_FEATURE_PATH = `/${GIS_API_PATH}/feature`; -export const GET_MATCHING_INDEXES_PATH = `/${GIS_API_PATH}/getMatchingIndexes`; -export const CHECK_IS_DRAWING_INDEX = `/${GIS_API_PATH}/checkIsDrawingIndex`; - -export const MVT_GETTILE_API_PATH = 'mvt/getTile'; -export const MVT_GETGRIDTILE_API_PATH = 'mvt/getGridTile'; +export const GIS_INTERNAL_PATH = `internal/${APP_ID}`; +export const INDEX_SETTINGS_API_PATH = `${GIS_INTERNAL_PATH}/indexSettings`; +export const FONTS_API_PATH = `${GIS_INTERNAL_PATH}/fonts`; +export const INDEX_SOURCE_API_PATH = `${GIS_INTERNAL_PATH}/docSource`; +export const INDEX_FEATURE_PATH = `/${GIS_INTERNAL_PATH}/feature`; +export const GET_MATCHING_INDEXES_PATH = `/${GIS_INTERNAL_PATH}/getMatchingIndexes`; +export const CHECK_IS_DRAWING_INDEX = `/${GIS_INTERNAL_PATH}/checkIsDrawingIndex`; +export const MVT_GETTILE_API_PATH = `/${GIS_INTERNAL_PATH}/mvt/getTile`; +export const MVT_GETGRIDTILE_API_PATH = `/${GIS_INTERNAL_PATH}/mvt/getGridTile`; + export const OPEN_LAYER_WIZARD = 'openLayerWizard'; // Identifies centroid feature. diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index d9b7cc4540ec2..592ad8cd4fbef 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -1051,8 +1051,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer { async addFeature(geometry: Geometry | Position[]) { const layerSource = this.getSource(); - const defaultFields = await layerSource.getDefaultFields(); - await layerSource.addFeature(geometry, defaultFields); + await layerSource.addFeature(geometry); } async deleteFeature(featureId: string) { diff --git a/x-pack/plugins/maps/public/classes/layers/wizards/new_vector_layer_wizard/create_new_index_pattern.ts b/x-pack/plugins/maps/public/classes/layers/wizards/new_vector_layer_wizard/create_new_index_pattern.ts index 90ef4b90a4992..90e0bceec7ef6 100644 --- a/x-pack/plugins/maps/public/classes/layers/wizards/new_vector_layer_wizard/create_new_index_pattern.ts +++ b/x-pack/plugins/maps/public/classes/layers/wizards/new_vector_layer_wizard/create_new_index_pattern.ts @@ -19,6 +19,7 @@ export const createNewIndexAndPattern = async ({ return await getHttp().fetch({ path: `/${INDEX_SOURCE_API_PATH}`, method: 'POST', + version: '1', body: JSON.stringify({ index: indexName, mappings: { diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts index 71614aebe541e..7e23353460df6 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.test.ts @@ -313,7 +313,7 @@ describe('ESGeoGridSource', () => { const tileUrl = await mvtGeogridSource.getTileUrl(vectorSourceRequestMeta, '1234', false, 5); const urlParts = tileUrl.split('?'); - expect(urlParts[0]).toEqual('rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf'); + expect(urlParts[0]).toEqual('rootdir/internal/maps/mvt/getGridTile/{z}/{x}/{y}.pbf'); const params = new URLSearchParams(urlParts[1]); expect(Object.fromEntries(params)).toEqual({ diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx index ada40e859d181..25e447d6ad3ea 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.tsx @@ -25,7 +25,6 @@ import { ES_GEO_FIELD_TYPE, GEOCENTROID_AGG_NAME, GEOTILE_GRID_AGG_NAME, - GIS_API_PATH, GRID_RESOLUTION, MVT_GETGRIDTILE_API_PATH, RENDER_AS, @@ -574,7 +573,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo searchSource.setField('aggs', this.getValueAggsDsl(dataView)); const mvtUrlServicePath = getHttp().basePath.prepend( - `/${GIS_API_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf` + `${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf` ); const tileUrlParams = getTileUrlParams({ diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts index a6adb7673e00a..7f7fde393de91 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.test.ts @@ -122,7 +122,7 @@ describe('ESSearchSource', () => { const tileUrl = await esSearchSource.getTileUrl(requestMeta, '1234', false, 5); const urlParts = tileUrl.split('?'); - expect(urlParts[0]).toEqual('rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf'); + expect(urlParts[0]).toEqual('rootdir/internal/maps/mvt/getTile/{z}/{x}/{y}.pbf'); const params = new URLSearchParams(urlParts[1]); expect(Object.fromEntries(params)).toEqual({ diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx index 2db15d3f0cd72..6bcc061d44040 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.tsx @@ -37,7 +37,6 @@ import { ES_GEO_FIELD_TYPE, FIELD_ORIGIN, GEO_JSON_TYPE, - GIS_API_PATH, MVT_GETTILE_API_PATH, SCALING_TYPES, SOURCE_TYPES, @@ -491,7 +490,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource return !!(scalingType === SCALING_TYPES.TOP_HITS && topHitsSplitField); } - async getSourceIndexList(): Promise { + async _getSourceIndexList(): Promise { const dataView = await this.getIndexPattern(); try { const { success, matchingIndexes } = await getMatchingIndexes(dataView.getIndexPattern()); @@ -503,12 +502,12 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } async supportsFeatureEditing(): Promise { - const matchingIndexes = await this.getSourceIndexList(); + const matchingIndexes = await this._getSourceIndexList(); // For now we only support 1:1 index-pattern:index matches return matchingIndexes.length === 1; } - async getDefaultFields(): Promise>> { + async _getNewFeatureFields(): Promise>> { if (!(await this._isDrawingIndex())) { return {}; } @@ -820,7 +819,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource } async _getEditableIndex(): Promise { - const indexList = await this.getSourceIndexList(); + const indexList = await this._getSourceIndexList(); if (indexList.length === 0) { throw new Error( i18n.translate('xpack.maps.source.esSearch.indexZeroLengthEditError', { @@ -838,12 +837,14 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource return indexList[0]; } - async addFeature( - geometry: Geometry | Position[], - defaultFields: Record> - ) { + async addFeature(geometry: Geometry | Position[]) { const index = await this._getEditableIndex(); - await addFeatureToIndex(index, geometry, this.getGeoFieldName(), defaultFields); + await addFeatureToIndex( + index, + geometry, + this.getGeoFieldName(), + await this._getNewFeatureFields() + ); } async deleteFeature(featureId: string) { @@ -894,9 +895,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource }) ); - const mvtUrlServicePath = getHttp().basePath.prepend( - `/${GIS_API_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf` - ); + const mvtUrlServicePath = getHttp().basePath.prepend(`${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`); const tileUrlParams = getTileUrlParams({ geometryFieldName: this._descriptor.geoField, diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/feature_edit.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/feature_edit.ts index 4619cc32ae617..a2304daf40497 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/feature_edit.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/feature_edit.ts @@ -24,6 +24,7 @@ export const addFeatureToIndex = async ( return await getHttp().fetch({ path: `${INDEX_FEATURE_PATH}`, method: 'POST', + version: '1', body: JSON.stringify({ index: indexName, data, @@ -35,6 +36,7 @@ export const deleteFeatureFromIndex = async (indexName: string, featureId: strin return await getHttp().fetch({ path: `${INDEX_FEATURE_PATH}/${featureId}`, method: 'DELETE', + version: '1', body: JSON.stringify({ index: indexName, }), @@ -48,6 +50,7 @@ export const getMatchingIndexes = async (indexPattern: string) => { }>({ path: GET_MATCHING_INDEXES_PATH, method: 'GET', + version: '1', query: { indexPattern }, }); }; @@ -59,6 +62,7 @@ export const getIsDrawLayer = async (index: string) => { }>({ path: CHECK_IS_DRAWING_INDEX, method: 'GET', + version: '1', query: { index }, }); }; diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/load_index_settings.ts b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/load_index_settings.ts index a736fc664a155..f9d68053246d1 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/util/load_index_settings.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/util/load_index_settings.ts @@ -38,6 +38,7 @@ async function fetchIndexSettings(indexPatternTitle: string): Promise>> { - return {}; - } - supportsJoins(): boolean { return false; } diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx index f17de87cbef33..103e7735025c5 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx @@ -122,11 +122,7 @@ export interface IVectorSource extends ISource { getSourceStatus(sourceDataRequest?: DataRequest): SourceStatus; getTimesliceMaskFieldName(): Promise; supportsFeatureEditing(): Promise; - getDefaultFields(): Promise>>; - addFeature( - geometry: Geometry | Position[], - defaultFields: Record> - ): Promise; + addFeature(geometry: Geometry | Position[]): Promise; deleteFeature(featureId: string): Promise; /* @@ -242,10 +238,7 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc return null; } - async addFeature( - geometry: Geometry | Position[], - defaultFields: Record> - ) { + async addFeature(geometry: Geometry | Position[]) { throw new Error('Should implement VectorSource#addFeature'); } @@ -257,10 +250,6 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc return false; } - async getDefaultFields(): Promise>> { - return {}; - } - getFeatureActions({ addFilters, geoFieldNames, diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/__snapshots__/marker_size_legend.test.tsx.snap b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/__snapshots__/marker_size_legend.test.tsx.snap new file mode 100644 index 0000000000000..984d316d0fec2 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/__snapshots__/marker_size_legend.test.tsx.snap @@ -0,0 +1,958 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should invert legend 1`] = ` +
+ + + + + + + bytes + + + + + + + + + + + + + + + + + + + + + + + +
+`; + +exports[`Should render legend 1`] = ` +
+ + + + + + + bytes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+`; + +exports[`Should render legend with 2 markers when size difference does not provide enough vertical space for more labels 1`] = ` +
+ + + + + + + bytes + + + + + + + + + + + + + + + + + + +
+`; + +exports[`Should render legend with 3 markers when size difference does not provide enough vertical space for more labels 1`] = ` +
+ + + + + + + bytes + + + + + + + + + + + + + + + + + + + + + + + +
+`; + +exports[`Should render legend with only max marker when size difference does not provide enough vertical space for more labels 1`] = ` +
+ + + + + + + bytes + + + + + + + + + + + + + +
+`; + +exports[`Should render legend without label cutoff when min size is 1 1`] = ` +
+ + + + + + + bytes + + + + + + + + + + + + + + + + + + +
+`; + +exports[`Should render max label with std clamp notification 1`] = ` +
+ + + + + + + bytes + + + + + + + + + + + + + +
+`; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/__snapshots__/ordinal_legend.test.tsx.snap b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/__snapshots__/ordinal_legend.test.tsx.snap new file mode 100644 index 0000000000000..0a4d629cab86f --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/__snapshots__/ordinal_legend.test.tsx.snap @@ -0,0 +1,77 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should render legend 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + } + invert={false} + maxLabel="19KB" + minLabel="0KB" + propertyLabel="Border width" +/> +`; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/get_ordinal_label.ts b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/get_ordinal_label.ts new file mode 100644 index 0000000000000..bcae9d5543341 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/get_ordinal_label.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. + */ + +export function getMaxLabel( + isFieldMetaEnabled: boolean, + isMaxOutsideStdRange: boolean, + max: number | string +) { + return isFieldMetaEnabled && isMaxOutsideStdRange ? `> ${max}` : max; +} + +export function getMinLabel( + isFieldMetaEnabled: boolean, + isMinOutsideStdRange: boolean, + min: number | string +) { + return isFieldMetaEnabled && isMinOutsideStdRange ? `< ${min}` : min; +} diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/index.ts b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/index.ts new file mode 100644 index 0000000000000..6ca10563be5a0 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { MarkerSizeLegend } from './marker_size_legend'; +export { OrdinalLegend } from './ordinal_legend'; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_list.ts b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_list.ts new file mode 100644 index 0000000000000..67ea90a76465e --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_list.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ReactNode } from 'react'; + +export interface Marker { + svg: ReactNode; + textY: number; +} + +export class MarkerList { + private readonly _minFontDistance; + private readonly _maxMarker; + private readonly _markers: Marker[] = []; + + constructor(fontSize: number, maxMarker: Marker) { + this._minFontDistance = fontSize * 0.85; + this._maxMarker = maxMarker; + } + + push(marker: Marker) { + if (marker.textY - this._maxMarker.textY < this._minFontDistance) { + return; + } + + if (this._markers.length === 0) { + this._markers.push(marker); + return; + } + + // only push marker when there is enough vertical space to display text without collisions + const prevMarker = this._markers[this._markers.length - 1]; + if (prevMarker.textY - marker.textY > this._minFontDistance) { + this._markers.push(marker); + } + } + + getMarkers() { + const svgs = this._markers.map((marker: Marker) => { + return marker.svg; + }); + return [...svgs, this._maxMarker.svg]; + } +} diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_size_legend.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_size_legend.test.tsx new file mode 100644 index 0000000000000..89c442729efe9 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_size_legend.test.tsx @@ -0,0 +1,214 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { FIELD_ORIGIN } from '../../../../../../../common/constants'; +import type { DynamicSizeProperty } from '../../../properties/dynamic_size_property'; +import type { IField } from '../../../../../fields/field'; +import { MarkerSizeLegend } from './marker_size_legend'; + +const dynamicSizeOptions = { + minSize: 7, + maxSize: 32, + field: { + name: 'bytes', + origin: FIELD_ORIGIN.SOURCE, + }, + fieldMetaOptions: { + isEnabled: true, + sigma: 3, + }, + invert: false, +}; + +const mockStyle = { + formatField: (value: number) => { + return `${value * 0.001}KB`; + }, + getDisplayStyleName: () => { + return 'Symbol size'; + }, + getField: () => { + return { + getLabel: () => { + return 'bytes'; + }, + } as unknown as IField; + }, + getOptions: () => { + return dynamicSizeOptions; + }, + getRangeFieldMeta: () => { + return { + min: 0, + max: 19000, + delta: 19000, + }; + }, + isFieldMetaEnabled: () => { + return true; + }, +} as unknown as DynamicSizeProperty; + +test('Should render legend', async () => { + const component = shallow(); + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); +}); + +test('Should render legend with 3 markers when size difference does not provide enough vertical space for more labels', async () => { + const component = shallow( + { + return { + ...dynamicSizeOptions, + maxSize: 24, + }; + }, + } as unknown as DynamicSizeProperty + } + /> + ); + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); +}); + +test('Should render legend with 2 markers when size difference does not provide enough vertical space for more labels', async () => { + const component = shallow( + { + return { + ...dynamicSizeOptions, + maxSize: 15, + }; + }, + } as unknown as DynamicSizeProperty + } + /> + ); + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); +}); + +test('Should render legend with only max marker when size difference does not provide enough vertical space for more labels', async () => { + const component = shallow( + { + return { + ...dynamicSizeOptions, + maxSize: 11, + }; + }, + } as unknown as DynamicSizeProperty + } + /> + ); + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); +}); + +test('Should render legend without label cutoff when min size is 1', async () => { + const component = shallow( + { + return { + ...dynamicSizeOptions, + minSize: 1, + maxSize: 7, + }; + }, + } as unknown as DynamicSizeProperty + } + /> + ); + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); +}); + +test('Should render max label with std clamp notification', async () => { + const component = shallow( + { + return { + ...dynamicSizeOptions, + maxSize: 11, + }; + }, + getRangeFieldMeta: () => { + return { + min: 0, + max: 16000, + delta: 16000, + isMaxOutsideStdRange: true, + }; + }, + } as unknown as DynamicSizeProperty + } + /> + ); + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); +}); + +test('Should invert legend', async () => { + const component = shallow( + { + return { + ...dynamicSizeOptions, + maxSize: 24, + invert: true, + }; + }, + } as unknown as DynamicSizeProperty + } + /> + ); + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + expect(component).toMatchSnapshot(); +}); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/marker_size_legend.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_size_legend.tsx similarity index 67% rename from x-pack/plugins/maps/public/classes/styles/vector/components/legend/marker_size_legend.tsx rename to x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_size_legend.tsx index 11deb6e55942e..c00557a2d1382 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/marker_size_legend.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/marker_size_legend.tsx @@ -9,13 +9,14 @@ import React, { Component } from 'react'; import _ from 'lodash'; import { euiThemeVars } from '@kbn/ui-theme'; import { EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui'; -import { RangeFieldMeta } from '../../../../../../common/descriptor_types'; -import { DynamicSizeProperty } from '../../properties/dynamic_size_property'; -import { RightAlignedText } from './right_aligned_text'; +import { RangeFieldMeta } from '../../../../../../../common/descriptor_types'; +import { DynamicSizeProperty } from '../../../properties/dynamic_size_property'; +import { RightAlignedText } from '../right_aligned_text'; +import { getMaxLabel, getMinLabel } from './get_ordinal_label'; +import { type Marker, MarkerList } from './marker_list'; const FONT_SIZE = 10; const HALF_FONT_SIZE = FONT_SIZE / 2; -const MIN_MARKER_DISTANCE = (FONT_SIZE + 2) / 2; const EMPTY_VALUE = ''; @@ -103,29 +104,34 @@ export class MarkerSizeLegend extends Component { const circleCenterX = options.maxSize + circleStyle.strokeWidth; const circleBottomY = svgHeight - circleStyle.strokeWidth; - const makeMarker = (radius: number, formattedValue: string | number) => { + const makeMarker = (radius: number, formattedValue: string | number): Marker => { const circleCenterY = circleBottomY - radius; const circleTopY = circleCenterY - radius; const textOffset = this.state.maxLabelWidth + HALF_FONT_SIZE; - return ( - - - - - - ); + const rawTextY = circleTopY + HALF_FONT_SIZE; + const textY = rawTextY > svgHeight ? svgHeight : rawTextY; + return { + svg: ( + + + + + + ), + textY, + }; }; function getMarkerRadius(percentage: number) { @@ -142,34 +148,33 @@ export class MarkerSizeLegend extends Component { return fieldMeta!.delta > 3 ? Math.round(value) : value; } - const markers = []; + const maxLabel = getMaxLabel( + this.props.style.isFieldMetaEnabled(), + Boolean(fieldMeta.isMaxOutsideStdRange), + this._formatValue(fieldMeta.max) + ); - if (fieldMeta.delta > 0) { - const smallestMarker = makeMarker( - options.minSize, - this._formatValue(invert ? fieldMeta.max : fieldMeta.min) - ); - markers.push(smallestMarker); - - const markerDelta = options.maxSize - options.minSize; - if (markerDelta > MIN_MARKER_DISTANCE * 3) { - markers.push(makeMarker(getMarkerRadius(0.25), this._formatValue(getValue(0.25)))); - markers.push(makeMarker(getMarkerRadius(0.5), this._formatValue(getValue(0.5)))); - markers.push(makeMarker(getMarkerRadius(0.75), this._formatValue(getValue(0.75)))); - } else if (markerDelta > MIN_MARKER_DISTANCE) { - markers.push(makeMarker(getMarkerRadius(0.5), this._formatValue(getValue(0.5)))); - } - } + const minLabel = getMinLabel( + this.props.style.isFieldMetaEnabled(), + Boolean(fieldMeta.isMinOutsideStdRange), + this._formatValue(fieldMeta.min) + ); - const largestMarker = makeMarker( - options.maxSize, - this._formatValue(invert ? fieldMeta.min : fieldMeta.max) + const markerList = new MarkerList( + FONT_SIZE, + makeMarker(options.maxSize, invert ? minLabel : maxLabel) ); - markers.push(largestMarker); + + if (fieldMeta.delta > 0) { + markerList.push(makeMarker(options.minSize, invert ? maxLabel : minLabel)); + markerList.push(makeMarker(getMarkerRadius(0.25), this._formatValue(getValue(0.25)))); + markerList.push(makeMarker(getMarkerRadius(0.5), this._formatValue(getValue(0.5)))); + markerList.push(makeMarker(getMarkerRadius(0.75), this._formatValue(getValue(0.75)))); + } return ( - {markers} + {markerList.getMarkers()} ); } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/ordinal_legend.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/ordinal_legend.test.tsx new file mode 100644 index 0000000000000..70da28a4d289f --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/ordinal_legend.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../../../../common/constants'; +import type { DynamicSizeProperty } from '../../../properties/dynamic_size_property'; +import type { IField } from '../../../../../fields/field'; +import { OrdinalLegend } from './ordinal_legend'; + +const dynamicSizeOptions = { + minSize: 1, + maxSize: 10, + field: { + name: 'bytes', + origin: FIELD_ORIGIN.SOURCE, + }, + fieldMetaOptions: { + isEnabled: true, + sigma: 3, + }, + invert: false, +}; + +const mockStyle = { + formatField: (value: number) => { + return `${value * 0.001}KB`; + }, + getDisplayStyleName: () => { + return 'Border width'; + }, + getField: () => { + return { + getLabel: () => { + return 'bytes'; + }, + } as unknown as IField; + }, + getOptions: () => { + return dynamicSizeOptions; + }, + getRangeFieldMeta: () => { + return { + min: 0, + max: 19000, + delta: 19000, + }; + }, + getStyleName: () => { + return VECTOR_STYLES.LINE_WIDTH; + }, + isFieldMetaEnabled: () => { + return true; + }, +} as unknown as DynamicSizeProperty; + +test('Should render legend', async () => { + const component = shallow(); + + // Ensure all promises resolve + await new Promise((resolve) => process.nextTick(resolve)); + // Ensure the state changes are reflected + component.update(); + + expect(component).toMatchSnapshot(); +}); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/ordinal_legend.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/ordinal_legend.tsx similarity index 85% rename from x-pack/plugins/maps/public/classes/styles/vector/components/legend/ordinal_legend.tsx rename to x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/ordinal_legend.tsx index 048d1bf12a218..ba0edf541bbd6 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/ordinal_legend.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/size/ordinal_legend.tsx @@ -8,10 +8,11 @@ import React, { Component, Fragment } from 'react'; import _ from 'lodash'; import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui'; -import { RangedStyleLegendRow } from '../../../components/ranged_style_legend_row'; -import { VECTOR_STYLES } from '../../../../../../common/constants'; -import { CircleIcon } from './circle_icon'; -import { IDynamicStyleProperty } from '../../properties/dynamic_style_property'; +import { RangedStyleLegendRow } from '../../../../components/ranged_style_legend_row'; +import { VECTOR_STYLES } from '../../../../../../../common/constants'; +import { CircleIcon } from '../circle_icon'; +import { IDynamicStyleProperty } from '../../../properties/dynamic_style_property'; +import { getMaxLabel, getMinLabel } from './get_ordinal_label'; function getLineWidthIcons() { const defaultStyle = { @@ -130,12 +131,18 @@ export class OrdinalLegend extends Component { let maxLabel: string | number = EMPTY_VALUE; if (fieldMeta) { const min = this._formatValue(_.get(fieldMeta, 'min', EMPTY_VALUE)); - minLabel = - this.props.style.isFieldMetaEnabled() && fieldMeta.isMinOutsideStdRange ? `< ${min}` : min; + minLabel = getMinLabel( + this.props.style.isFieldMetaEnabled(), + Boolean(fieldMeta.isMinOutsideStdRange), + min + ); const max = this._formatValue(_.get(fieldMeta, 'max', EMPTY_VALUE)); - maxLabel = - this.props.style.isFieldMetaEnabled() && fieldMeta.isMaxOutsideStdRange ? `> ${max}` : max; + maxLabel = getMaxLabel( + this.props.style.isFieldMetaEnabled(), + Boolean(fieldMeta.isMaxOutsideStdRange), + max + ); } const options = this.props.style.getOptions(); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/__snapshots__/dynamic_size_property.test.tsx.snap b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/__snapshots__/dynamic_size_property.test.tsx.snap index b1fc94c4475ce..ce716d0b542d9 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/__snapshots__/dynamic_size_property.test.tsx.snap +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/__snapshots__/dynamic_size_property.test.tsx.snap @@ -1,236 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`renderLegendDetailRow Should render icon size scale 1`] = ` +exports[`renderLegendDetailRow Should render marker size legend for icon size property 1`] = `
- - - - - - - foobar_label - - - - - - - - - - - - - - - - - - - - - - - + mockMarkerSizeLegend
`; -exports[`renderLegendDetailRow Should render line width simple range 1`] = ` - - - - - - - - - - - - - - - - - - - - - - - - } - invert={false} - maxLabel="100_format" - minLabel="0_format" - propertyLabel="Border width" -/> +exports[`renderLegendDetailRow Should render ordinal legend for line width style property 1`] = ` +
+ mockMarkerSizeLegend +
`; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.test.tsx index 9f92d81313da7..f7d0d611a4d95 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.test.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.test.tsx @@ -11,6 +11,15 @@ jest.mock('../../components/vector_style_editor', () => ({ }, })); +jest.mock('../../components/legend/size', () => ({ + MarkerSizeLegend: () => { + return
mockMarkerSizeLegend
; + }, + OrdinalLegend: () => { + return
mockMarkerSizeLegend
; + }, +})); + import React from 'react'; import { shallow } from 'enzyme'; @@ -20,95 +29,37 @@ import { IField } from '../../../../fields/field'; import { IVectorLayer } from '../../../../layers/vector_layer'; describe('renderLegendDetailRow', () => { - test('Should render line width simple range', async () => { - const field = { - getLabel: async () => { - return 'foobar_label'; - }, - getName: () => { - return 'foodbar'; - }, - getOrigin: () => { - return FIELD_ORIGIN.SOURCE; - }, - supportsFieldMetaFromEs: () => { - return true; - }, - supportsFieldMetaFromLocalData: () => { - return true; - }, - } as unknown as IField; + test('Should render ordinal legend for line width style property', () => { const sizeProp = new DynamicSizeProperty( { minSize: 0, maxSize: 10, fieldMetaOptions: { isEnabled: true } }, VECTOR_STYLES.LINE_WIDTH, - field, + {} as unknown as IField, {} as unknown as IVectorLayer, () => { return (value: RawValue) => value + '_format'; }, false ); - sizeProp.getRangeFieldMeta = () => { - return { - min: 0, - max: 100, - delta: 100, - }; - }; const legendRow = sizeProp.renderLegendDetailRow(); const component = shallow(legendRow); - - // Ensure all promises resolve - await new Promise((resolve) => process.nextTick(resolve)); - // Ensure the state changes are reflected - component.update(); expect(component).toMatchSnapshot(); }); - test('Should render icon size scale', async () => { - const field = { - getLabel: async () => { - return 'foobar_label'; - }, - getName: () => { - return 'foodbar'; - }, - getOrigin: () => { - return FIELD_ORIGIN.SOURCE; - }, - supportsFieldMetaFromEs: () => { - return true; - }, - supportsFieldMetaFromLocalData: () => { - return true; - }, - } as unknown as IField; + test('Should render marker size legend for icon size property', () => { const sizeProp = new DynamicSizeProperty( { minSize: 0, maxSize: 10, fieldMetaOptions: { isEnabled: true } }, VECTOR_STYLES.ICON_SIZE, - field, + {} as unknown as IField, {} as unknown as IVectorLayer, () => { return (value: RawValue) => value + '_format'; }, false ); - sizeProp.getRangeFieldMeta = () => { - return { - min: 0, - max: 100, - delta: 100, - }; - }; const legendRow = sizeProp.renderLegendDetailRow(); const component = shallow(legendRow); - - // Ensure all promises resolve - await new Promise((resolve) => process.nextTick(resolve)); - // Ensure the state changes are reflected - component.update(); expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.tsx index dcaaa9ef227de..c3a1bbbd2ac05 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_size_property/dynamic_size_property.tsx @@ -8,8 +8,7 @@ import React from 'react'; import type { Map as MbMap } from '@kbn/mapbox-gl'; import { DynamicStyleProperty } from '../dynamic_style_property'; -import { OrdinalLegend } from '../../components/legend/ordinal_legend'; -import { MarkerSizeLegend } from '../../components/legend/marker_size_legend'; +import { MarkerSizeLegend, OrdinalLegend } from '../../components/legend/size'; import { makeMbClampedNumberExpression } from '../../style_util'; import { FieldFormatter, diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/glyphs.test.ts b/x-pack/plugins/maps/public/connected_components/mb_map/glyphs.test.ts index 18cbd8c17f03b..78df48a8c8498 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/glyphs.test.ts +++ b/x-pack/plugins/maps/public/connected_components/mb_map/glyphs.test.ts @@ -61,7 +61,7 @@ describe('EMS enabled', () => { await getCanAccessEmsFonts(); expect(getGlyphs()).toEqual({ isEmsFont: false, - glyphUrlTemplate: 'abc/api/maps/fonts/{fontstack}/{range}', + glyphUrlTemplate: 'abc/internal/maps/fonts/{fontstack}/{range}', }); }); }); @@ -108,7 +108,7 @@ describe('EMS disabled', () => { test('should return kibana fonts template URL before canAccessEmsFontsPromise resolves', () => { expect(getGlyphs()).toEqual({ isEmsFont: false, - glyphUrlTemplate: 'abc/api/maps/fonts/{fontstack}/{range}', + glyphUrlTemplate: 'abc/internal/maps/fonts/{fontstack}/{range}', }); }); @@ -116,7 +116,7 @@ describe('EMS disabled', () => { await getCanAccessEmsFonts(); expect(getGlyphs()).toEqual({ isEmsFont: false, - glyphUrlTemplate: 'abc/api/maps/fonts/{fontstack}/{range}', + glyphUrlTemplate: 'abc/internal/maps/fonts/{fontstack}/{range}', }); }); }); diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx index 71858ecb02459..7653b2c59b357 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx @@ -51,6 +51,7 @@ import type { MapExtentState } from '../../reducers/map/types'; import { CUSTOM_ICON_PIXEL_RATIO, createSdfIcon } from '../../classes/styles/vector/symbol_utils'; import { MAKI_ICONS } from '../../classes/styles/vector/maki_icons'; import { KeydownScrollZoom } from './keydown_scroll_zoom/keydown_scroll_zoom'; +import { transformRequest } from './transform_request'; export interface Props { isMapReady: boolean; @@ -171,6 +172,7 @@ export class MbMap extends Component { preserveDrawingBuffer: getPreserveDrawingBuffer(), maxZoom: this.props.settings.maxZoom, minZoom: this.props.settings.minZoom, + transformRequest, }; if (initialView) { options.zoom = initialView.zoom; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/transform_request.ts b/x-pack/plugins/maps/public/connected_components/mb_map/transform_request.ts new file mode 100644 index 0000000000000..47f14956d6dca --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/mb_map/transform_request.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 { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { + FONTS_API_PATH, + MVT_GETTILE_API_PATH, + MVT_GETGRIDTILE_API_PATH, +} from '../../../common/constants'; +import { getHttp } from '../../kibana_services'; + +const FONTS = getHttp().basePath.prepend(FONTS_API_PATH); +const GETTILE = getHttp().basePath.prepend(MVT_GETTILE_API_PATH); +const GETGRIDTILE = getHttp().basePath.prepend(MVT_GETGRIDTILE_API_PATH); + +export function transformRequest(url: string, resourceType: string | undefined) { + if (resourceType === 'Glyphs' && url.startsWith(FONTS)) { + return { + url, + method: 'GET' as 'GET', + headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1' }, + }; + } + + if (resourceType === 'Tile' && url.startsWith(GETTILE)) { + return { + url, + method: 'GET' as 'GET', + headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1' }, + }; + } + + if (resourceType === 'Tile' && url.startsWith(GETGRIDTILE)) { + return { + url, + method: 'GET' as 'GET', + headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1' }, + }; + } + + return { url }; +} diff --git a/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts b/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts index 91f9e02cd7c1c..922d45b2effc7 100644 --- a/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts +++ b/x-pack/plugins/maps/public/inspector/vector_tile_adapter/components/get_tile_request.test.ts @@ -11,7 +11,7 @@ test('Should return elasticsearch vector tile request for aggs tiles', () => { expect( getTileRequest({ layerId: '1', - tileUrl: `/pof/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=geo.coordinates&hasLabels=false&buffer=7&index=kibana_sample_data_logs&gridPrecision=8&requestBody=(_source%3A(excludes%3A!())%2Caggs%3A()%2Cfields%3A!((field%3A'%40timestamp'%2Cformat%3Adate_time)%2C(field%3Atimestamp%2Cformat%3Adate_time)%2C(field%3Autc_time%2Cformat%3Adate_time))%2Cquery%3A(bool%3A(filter%3A!((match_phrase%3A(machine.os.keyword%3Aios))%2C(range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A'2022-04-22T16%3A46%3A00.744Z'%2Clte%3A'2022-04-29T16%3A46%3A05.345Z'))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A'emit(doc%5B!'timestamp!'%5D.value.getHour())%3B')%2Ctype%3Along))%2Cscript_fields%3A()%2Csize%3A0%2Cstored_fields%3A!('*'))&renderAs=heatmap&token=e8bff005-ccea-464a-ae56-2061b4f8ce68`, + tileUrl: `/pof/internal/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=geo.coordinates&hasLabels=false&buffer=7&index=kibana_sample_data_logs&gridPrecision=8&requestBody=(_source%3A(excludes%3A!())%2Caggs%3A()%2Cfields%3A!((field%3A'%40timestamp'%2Cformat%3Adate_time)%2C(field%3Atimestamp%2Cformat%3Adate_time)%2C(field%3Autc_time%2Cformat%3Adate_time))%2Cquery%3A(bool%3A(filter%3A!((match_phrase%3A(machine.os.keyword%3Aios))%2C(range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A'2022-04-22T16%3A46%3A00.744Z'%2Clte%3A'2022-04-29T16%3A46%3A05.345Z'))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A'emit(doc%5B!'timestamp!'%5D.value.getHour())%3B')%2Ctype%3Along))%2Cscript_fields%3A()%2Csize%3A0%2Cstored_fields%3A!('*'))&renderAs=heatmap&token=e8bff005-ccea-464a-ae56-2061b4f8ce68`, x: 3, y: 0, z: 2, @@ -81,7 +81,7 @@ test('Should return elasticsearch vector tile request for hits tiles', () => { expect( getTileRequest({ layerId: '1', - tileUrl: `http://localhost:5601/zuv/api/maps/mvt/getTile/4/2/6.pbf?geometryFieldName=geo.coordinates&index=kibana_sample_data_logs&hasLabels=true&buffer=7&requestBody=(_source%3A!f%2Cfields%3A!((field%3A%27%40timestamp%27%2Cformat%3Aepoch_millis)%2Cbytes)%2Cquery%3A(bool%3A(filter%3A!((range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A%272022-06-15T20%3A00%3A00.000Z%27%2Clte%3A%272022-06-16T20%3A48%3A02.517Z%27))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A%27emit(doc%5B!%27timestamp!%27%5D.value.getHour())%3B%27)%2Ctype%3Along))%2Csize%3A10000%2Csort%3A!((%27%40timestamp%27%3A(order%3Adesc%2Cunmapped_type%3Aboolean))))&token=7afe7c2d-c96b-4bdb-9b5e-819aceac80a1`, + tileUrl: `http://localhost:5601/zuv/internal/maps/mvt/getTile/4/2/6.pbf?geometryFieldName=geo.coordinates&index=kibana_sample_data_logs&hasLabels=true&buffer=7&requestBody=(_source%3A!f%2Cfields%3A!((field%3A%27%40timestamp%27%2Cformat%3Aepoch_millis)%2Cbytes)%2Cquery%3A(bool%3A(filter%3A!((range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A%272022-06-15T20%3A00%3A00.000Z%27%2Clte%3A%272022-06-16T20%3A48%3A02.517Z%27))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A%27emit(doc%5B!%27timestamp!%27%5D.value.getHour())%3B%27)%2Ctype%3Along))%2Csize%3A10000%2Csort%3A!((%27%40timestamp%27%3A(order%3Adesc%2Cunmapped_type%3Aboolean))))&token=7afe7c2d-c96b-4bdb-9b5e-819aceac80a1`, x: 0, y: 0, z: 2, diff --git a/x-pack/plugins/maps/server/data_indexing/indexing_routes.ts b/x-pack/plugins/maps/server/data_indexing/indexing_routes.ts index 847aadb447034..94a7391f68568 100644 --- a/x-pack/plugins/maps/server/data_indexing/indexing_routes.ts +++ b/x-pack/plugins/maps/server/data_indexing/indexing_routes.ts @@ -33,193 +33,229 @@ export function initIndexingRoutes({ dataPlugin: DataPluginStart; securityPlugin?: SecurityPluginStart; }) { - router.post( - { + router.versioned + .post({ path: `/${INDEX_SOURCE_API_PATH}`, - validate: { - body: schema.object({ - index: schema.string(), - mappings: schema.any(), - }), - }, + access: 'internal', options: { body: { accepts: ['application/json'], }, }, - }, - async (context, request, response) => { - const coreContext = await context.core; - const { index, mappings } = request.body; - const indexPatternsService = await dataPlugin.indexPatterns.dataViewsServiceFactory( - coreContext.savedObjects.client, - coreContext.elasticsearch.client.asCurrentUser, - request - ); - const result = await createDocSource( - index, - mappings, - coreContext.elasticsearch.client, - indexPatternsService - ); - if (result.success) { - return response.ok({ body: result }); - } else { - if (result.error) { - logger.error(result.error); + }) + .addVersion( + { + version: '1', + validate: { + request: { + body: schema.object({ + index: schema.string(), + mappings: schema.any(), + }), + }, + }, + }, + async (context, request, response) => { + const coreContext = await context.core; + const { index, mappings } = request.body; + const indexPatternsService = await dataPlugin.indexPatterns.dataViewsServiceFactory( + coreContext.savedObjects.client, + coreContext.elasticsearch.client.asCurrentUser, + request + ); + const result = await createDocSource( + index, + mappings, + coreContext.elasticsearch.client, + indexPatternsService + ); + if (result.success) { + return response.ok({ body: result }); + } else { + if (result.error) { + logger.error(result.error); + } + return response.custom({ + body: result?.error?.message, + statusCode: 500, + }); } - return response.custom({ - body: result?.error?.message, - statusCode: 500, - }); } - } - ); + ); - router.post( - { + router.versioned + .post({ path: INDEX_FEATURE_PATH, - validate: { - body: schema.object({ - index: schema.string(), - data: schema.any(), - }), - }, + access: 'internal', options: { body: { accepts: ['application/json'], maxBytes: MAX_DRAWING_SIZE_BYTES, }, }, - }, - async (context, request, response) => { - const coreContext = await context.core; - const result = await writeDataToIndex( - request.body.index, - request.body.data, - coreContext.elasticsearch.client.asCurrentUser - ); - if (result.success) { - return response.ok({ body: result }); - } else { - logger.error(result.error); - return response.custom({ - body: result.error.message, - statusCode: 500, - }); - } - } - ); - - router.delete( - { - path: `${INDEX_FEATURE_PATH}/{featureId}`, - validate: { - params: schema.object({ - featureId: schema.string(), - }), - body: schema.object({ - index: schema.string(), - }), + }) + .addVersion( + { + version: '1', + validate: { + request: { + body: schema.object({ + index: schema.string(), + data: schema.any(), + }), + }, + }, }, - }, - async (context, request, response) => { - try { + async (context, request, response) => { const coreContext = await context.core; - const resp = await coreContext.elasticsearch.client.asCurrentUser.delete({ - index: request.body.index, - id: request.params.featureId, - refresh: true, - }); - // @ts-expect-error always false - if (resp.result === 'Error') { - throw resp; - } else { - return response.ok({ body: { success: true } }); - } - } catch (error) { - logger.error(error); - const errorStatusCode = error.meta?.statusCode; - if (errorStatusCode === 401) { - return response.unauthorized({ - body: { - message: 'User not authorized to delete indexed feature', - }, - }); - } else if (errorStatusCode === 403) { - return response.forbidden({ - body: { - message: 'Access to delete indexed feature forbidden', - }, - }); - } else if (errorStatusCode === 404) { - return response.notFound({ - body: { message: 'Feature not found' }, - }); + const result = await writeDataToIndex( + request.body.index, + request.body.data, + coreContext.elasticsearch.client.asCurrentUser + ); + if (result.success) { + return response.ok({ body: result }); } else { + logger.error(result.error); return response.custom({ - body: 'Unknown error deleting feature', + body: result.error.message, statusCode: 500, }); } } - } - ); + ); + + router.versioned + .delete({ + path: `${INDEX_FEATURE_PATH}/{featureId}`, + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: schema.object({ + featureId: schema.string(), + }), + body: schema.object({ + index: schema.string(), + }), + }, + }, + }, + async (context, request, response) => { + try { + const coreContext = await context.core; + const resp = await coreContext.elasticsearch.client.asCurrentUser.delete({ + index: request.body.index, + id: request.params.featureId, + refresh: true, + }); + // @ts-expect-error always false + if (resp.result === 'Error') { + throw resp; + } else { + return response.ok({ body: { success: true } }); + } + } catch (error) { + logger.error(error); + const errorStatusCode = error.meta?.statusCode; + if (errorStatusCode === 401) { + return response.unauthorized({ + body: { + message: 'User not authorized to delete indexed feature', + }, + }); + } else if (errorStatusCode === 403) { + return response.forbidden({ + body: { + message: 'Access to delete indexed feature forbidden', + }, + }); + } else if (errorStatusCode === 404) { + return response.notFound({ + body: { message: 'Feature not found' }, + }); + } else { + return response.custom({ + body: 'Unknown error deleting feature', + statusCode: 500, + }); + } + } + } + ); - router.get( - { + router.versioned + .get({ path: GET_MATCHING_INDEXES_PATH, - validate: { - query: schema.object({ - indexPattern: schema.string(), - }), + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + query: schema.object({ + indexPattern: schema.string(), + }), + }, + }, }, - }, - async (context, request, response) => { - const coreContext = await context.core; - return await getMatchingIndexes( - request.query.indexPattern, - coreContext.elasticsearch.client, - response, - logger - ); - } - ); + async (context, request, response) => { + const coreContext = await context.core; + return await getMatchingIndexes( + request.query.indexPattern, + coreContext.elasticsearch.client, + response, + logger + ); + } + ); - router.get( - { + router.versioned + .get({ path: CHECK_IS_DRAWING_INDEX, - validate: { - query: schema.object({ - index: schema.string(), - }), + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + query: schema.object({ + index: schema.string(), + }), + }, + }, }, - }, - async (context, request, response) => { - const { index } = request.query; - try { - const coreContext = await context.core; - const mappingsResp = - await coreContext.elasticsearch.client.asCurrentUser.indices.getMapping({ - index: request.query.index, + async (context, request, response) => { + const { index } = request.query; + try { + const coreContext = await context.core; + const mappingsResp = + await coreContext.elasticsearch.client.asCurrentUser.indices.getMapping({ + index: request.query.index, + }); + const isDrawingIndex = + mappingsResp[index].mappings?._meta?.created_by === + MAPS_NEW_VECTOR_LAYER_META_CREATED_BY; + return response.ok({ + body: { + success: true, + isDrawingIndex, + }, }); - const isDrawingIndex = - mappingsResp[index].mappings?._meta?.created_by === MAPS_NEW_VECTOR_LAYER_META_CREATED_BY; - return response.ok({ - body: { - success: true, - isDrawingIndex, - }, - }); - } catch (error) { - // Index likely doesn't exist - return response.ok({ - body: { - success: false, - error, - }, - }); + } catch (error) { + // Index likely doesn't exist + return response.ok({ + body: { + success: false, + error, + }, + }); + } } - } - ); + ); } diff --git a/x-pack/plugins/maps/server/mvt/mvt_routes.ts b/x-pack/plugins/maps/server/mvt/mvt_routes.ts index ed9235f8a5ae6..2900bd072318a 100644 --- a/x-pack/plugins/maps/server/mvt/mvt_routes.ts +++ b/x-pack/plugins/maps/server/mvt/mvt_routes.ts @@ -17,7 +17,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { APP_ID, MVT_GETTILE_API_PATH, - API_ROOT_PATH, MVT_GETGRIDTILE_API_PATH, RENDER_AS, } from '../../common/constants'; @@ -34,147 +33,161 @@ export function initMVTRoutes({ logger: Logger; core: CoreStart; }) { - router.get( - { - path: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`, - validate: { - params: schema.object({ - x: schema.number(), - y: schema.number(), - z: schema.number(), - }), - query: schema.object({ - buffer: schema.maybe(schema.number()), - geometryFieldName: schema.string(), - hasLabels: schema.boolean(), - requestBody: schema.string(), - index: schema.string(), - token: schema.maybe(schema.string()), - executionContextId: schema.maybe(schema.string()), - }), + router.versioned + .get({ + path: `${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`, + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: schema.object({ + x: schema.number(), + y: schema.number(), + z: schema.number(), + }), + query: schema.object({ + buffer: schema.maybe(schema.number()), + geometryFieldName: schema.string(), + hasLabels: schema.boolean(), + requestBody: schema.string(), + index: schema.string(), + token: schema.maybe(schema.string()), + executionContextId: schema.maybe(schema.string()), + }), + }, + }, }, - }, - async ( - context: DataRequestHandlerContext, - request: KibanaRequest, unknown>, - response: KibanaResponseFactory - ) => { - const { query, params } = request; - const x = parseInt((params as any).x, 10) as number; - const y = parseInt((params as any).y, 10) as number; - const z = parseInt((params as any).z, 10) as number; + async ( + context: DataRequestHandlerContext, + request: KibanaRequest, unknown>, + response: KibanaResponseFactory + ) => { + const { query, params } = request; + const x = parseInt((params as any).x, 10) as number; + const y = parseInt((params as any).y, 10) as number; + const z = parseInt((params as any).z, 10) as number; - let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = { - path: '', - body: {}, - }; - try { - tileRequest = getHitsTileRequest({ - buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5, - risonRequestBody: query.requestBody as string, - geometryFieldName: query.geometryFieldName as string, - hasLabels: query.hasLabels as boolean, - index: query.index as string, - x, - y, - z, - }); - } catch (e) { - return response.badRequest(); - } + let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = { + path: '', + body: {}, + }; + try { + tileRequest = getHitsTileRequest({ + buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5, + risonRequestBody: query.requestBody as string, + geometryFieldName: query.geometryFieldName as string, + hasLabels: query.hasLabels as boolean, + index: query.index as string, + x, + y, + z, + }); + } catch (e) { + return response.badRequest(); + } - const { stream, headers, statusCode } = await getTile({ - abortController: makeAbortController(request), - body: tileRequest.body, - context, - core, - executionContext: makeExecutionContext({ - type: 'server', - name: APP_ID, - description: 'mvt:get_hits_tile', - url: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}/${z}/${x}/${y}.pbf`, - id: query.executionContextId, - }), - logger, - path: tileRequest.path, - }); + const { stream, headers, statusCode } = await getTile({ + abortController: makeAbortController(request), + body: tileRequest.body, + context, + core, + executionContext: makeExecutionContext({ + type: 'server', + name: APP_ID, + description: 'mvt:get_hits_tile', + url: `${MVT_GETTILE_API_PATH}/${z}/${x}/${y}.pbf`, + id: query.executionContextId, + }), + logger, + path: tileRequest.path, + }); - return sendResponse(response, stream, headers, statusCode); - } - ); + return sendResponse(response, stream, headers, statusCode); + } + ); - router.get( - { - path: `${API_ROOT_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`, - validate: { - params: schema.object({ - x: schema.number(), - y: schema.number(), - z: schema.number(), - }), - query: schema.object({ - buffer: schema.maybe(schema.number()), - geometryFieldName: schema.string(), - hasLabels: schema.boolean(), - requestBody: schema.string(), - index: schema.string(), - renderAs: schema.string(), - token: schema.maybe(schema.string()), - gridPrecision: schema.number(), - executionContextId: schema.maybe(schema.string()), - }), + router.versioned + .get({ + path: `${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`, + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: schema.object({ + x: schema.number(), + y: schema.number(), + z: schema.number(), + }), + query: schema.object({ + buffer: schema.maybe(schema.number()), + geometryFieldName: schema.string(), + hasLabels: schema.boolean(), + requestBody: schema.string(), + index: schema.string(), + renderAs: schema.string(), + token: schema.maybe(schema.string()), + gridPrecision: schema.number(), + executionContextId: schema.maybe(schema.string()), + }), + }, + }, }, - }, - async ( - context: DataRequestHandlerContext, - request: KibanaRequest, unknown>, - response: KibanaResponseFactory - ) => { - const { query, params } = request; - const x = parseInt((params as any).x, 10) as number; - const y = parseInt((params as any).y, 10) as number; - const z = parseInt((params as any).z, 10) as number; + async ( + context: DataRequestHandlerContext, + request: KibanaRequest, unknown>, + response: KibanaResponseFactory + ) => { + const { query, params } = request; + const x = parseInt((params as any).x, 10) as number; + const y = parseInt((params as any).y, 10) as number; + const z = parseInt((params as any).z, 10) as number; - let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = { - path: '', - body: {}, - }; - try { - tileRequest = getAggsTileRequest({ - buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5, - risonRequestBody: query.requestBody as string, - geometryFieldName: query.geometryFieldName as string, - gridPrecision: parseInt(query.gridPrecision, 10), - hasLabels: query.hasLabels as boolean, - index: query.index as string, - renderAs: query.renderAs as RENDER_AS, - x, - y, - z, - }); - } catch (e) { - return response.badRequest(); - } + let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = { + path: '', + body: {}, + }; + try { + tileRequest = getAggsTileRequest({ + buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5, + risonRequestBody: query.requestBody as string, + geometryFieldName: query.geometryFieldName as string, + gridPrecision: parseInt(query.gridPrecision, 10), + hasLabels: query.hasLabels as boolean, + index: query.index as string, + renderAs: query.renderAs as RENDER_AS, + x, + y, + z, + }); + } catch (e) { + return response.badRequest(); + } - const { stream, headers, statusCode } = await getTile({ - abortController: makeAbortController(request), - body: tileRequest.body, - context, - core, - executionContext: makeExecutionContext({ - type: 'server', - name: APP_ID, - description: 'mvt:get_aggs_tile', - url: `${API_ROOT_PATH}/${MVT_GETGRIDTILE_API_PATH}/${z}/${x}/${y}.pbf`, - id: query.executionContextId, - }), - logger, - path: tileRequest.path, - }); + const { stream, headers, statusCode } = await getTile({ + abortController: makeAbortController(request), + body: tileRequest.body, + context, + core, + executionContext: makeExecutionContext({ + type: 'server', + name: APP_ID, + description: 'mvt:get_aggs_tile', + url: `${MVT_GETGRIDTILE_API_PATH}/${z}/${x}/${y}.pbf`, + id: query.executionContextId, + }), + logger, + path: tileRequest.path, + }); - return sendResponse(response, stream, headers, statusCode); - } - ); + return sendResponse(response, stream, headers, statusCode); + } + ); } async function getTile({ diff --git a/x-pack/plugins/maps/server/routes.ts b/x-pack/plugins/maps/server/routes.ts index 427f403927d5d..347cae9e04b47 100644 --- a/x-pack/plugins/maps/server/routes.ts +++ b/x-pack/plugins/maps/server/routes.ts @@ -21,79 +21,93 @@ export async function initRoutes(coreSetup: CoreSetup, logger: Logger): Promise< const [coreStart, { data: dataPlugin }]: [CoreStart, StartDeps] = (await coreSetup.getStartServices()) as unknown as [CoreStart, StartDeps]; - router.get( - { + router.versioned + .get({ path: `/${FONTS_API_PATH}/{fontstack}/{range}`, - validate: { - params: schema.object({ - fontstack: schema.string(), - range: schema.string(), - }), + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: schema.object({ + fontstack: schema.string(), + range: schema.string(), + }), + }, + }, }, - }, - (context, request, response) => { - const range = path.normalize(request.params.range); - const rootPath = path.resolve(__dirname, 'fonts', 'open_sans'); - const fontPath = path.resolve(rootPath, `${range}.pbf`); - return !fontPath.startsWith(rootPath) - ? response.notFound() - : new Promise((resolve) => { - fs.readFile(fontPath, (error, data) => { - if (error) { - resolve(response.notFound()); - } else { - resolve( - response.ok({ - body: data, - }) - ); - } + (context, request, response) => { + const range = path.normalize(request.params.range); + const rootPath = path.resolve(__dirname, 'fonts', 'open_sans'); + const fontPath = path.resolve(rootPath, `${range}.pbf`); + return !fontPath.startsWith(rootPath) + ? response.notFound() + : new Promise((resolve) => { + fs.readFile(fontPath, (error, data) => { + if (error) { + resolve(response.notFound()); + } else { + resolve( + response.ok({ + body: data, + }) + ); + } + }); }); - }); - } - ); + } + ); - router.get( - { + router.versioned + .get({ path: `/${INDEX_SETTINGS_API_PATH}`, - validate: { - query: schema.object({ - indexPatternTitle: schema.string(), - }), + access: 'internal', + }) + .addVersion( + { + version: '1', + validate: { + request: { + query: schema.object({ + indexPatternTitle: schema.string(), + }), + }, + }, }, - }, - async (context, request, response) => { - const { query } = request; - if (!query.indexPatternTitle) { - logger.warn(`Required query parameter 'indexPatternTitle' not provided.`); - return response.custom({ - body: `Required query parameter 'indexPatternTitle' not provided.`, - statusCode: 400, - }); - } + async (context, request, response) => { + const { query } = request; + if (!query.indexPatternTitle) { + logger.warn(`Required query parameter 'indexPatternTitle' not provided.`); + return response.custom({ + body: `Required query parameter 'indexPatternTitle' not provided.`, + statusCode: 400, + }); + } - try { - const coreContext = await context.core; - const resp = await coreContext.elasticsearch.client.asCurrentUser.indices.getSettings({ - index: query.indexPatternTitle, - }); - const indexPatternSettings = getIndexPatternSettings( - resp as unknown as Record - ); - return response.ok({ - body: indexPatternSettings, - }); - } catch (error) { - logger.warn( - `Cannot load index settings for data view '${query.indexPatternTitle}', error: ${error.message}.` - ); - return response.custom({ - body: 'Error loading index settings', - statusCode: 400, - }); + try { + const coreContext = await context.core; + const resp = await coreContext.elasticsearch.client.asCurrentUser.indices.getSettings({ + index: query.indexPatternTitle, + }); + const indexPatternSettings = getIndexPatternSettings( + resp as unknown as Record + ); + return response.ok({ + body: indexPatternSettings, + }); + } catch (error) { + logger.warn( + `Cannot load index settings for data view '${query.indexPatternTitle}', error: ${error.message}.` + ); + return response.custom({ + body: 'Error loading index settings', + statusCode: 400, + }); + } } - } - ); + ); initMVTRoutes({ router, logger, core: coreStart }); initIndexingRoutes({ router, logger, dataPlugin }); diff --git a/x-pack/plugins/maps/tsconfig.json b/x-pack/plugins/maps/tsconfig.json index 0b129c7985a0e..6f24d4d7d3c5e 100644 --- a/x-pack/plugins/maps/tsconfig.json +++ b/x-pack/plugins/maps/tsconfig.json @@ -70,6 +70,7 @@ "@kbn/content-management-utils", "@kbn/core-saved-objects-server", "@kbn/maps-vector-tile-utils", + "@kbn/core-http-common", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/ml/common/util/alerts.ts b/x-pack/plugins/ml/common/util/alerts.ts index 6c997dfb71566..db74701992e1e 100644 --- a/x-pack/plugins/ml/common/util/alerts.ts +++ b/x-pack/plugins/ml/common/util/alerts.ts @@ -21,7 +21,7 @@ const narrowBucketLength = 60; */ export function resolveLookbackInterval(jobs: Job[], datafeeds: Datafeed[]): string { const bucketSpanInSeconds = Math.ceil( - resolveMaxTimeInterval(jobs.map((v) => v.analysis_config.bucket_span)) ?? 0 + resolveMaxTimeInterval(jobs.map((v) => v.analysis_config.bucket_span!)) ?? 0 ); const queryDelayInSeconds = Math.ceil( resolveMaxTimeInterval(datafeeds.map((v) => v.query_delay).filter(isDefined)) ?? 0 @@ -45,7 +45,7 @@ export function getLookbackInterval(jobs: CombinedJobWithStats[]): string { } export function getTopNBuckets(job: Job): number { - const bucketSpan = parseInterval(job.analysis_config.bucket_span); + const bucketSpan = parseInterval(job.analysis_config.bucket_span!); if (bucketSpan === null) { throw new Error('Unable to resolve a bucket span length'); diff --git a/x-pack/plugins/ml/common/util/job_utils.ts b/x-pack/plugins/ml/common/util/job_utils.ts index 2b3f3d82042d1..01419d51f3c00 100644 --- a/x-pack/plugins/ml/common/util/job_utils.ts +++ b/x-pack/plugins/ml/common/util/job_utils.ts @@ -133,7 +133,7 @@ export function isSourceDataChartableForDetector(job: CombinedJob, detectorIndex const { detectors } = job.analysis_config; if (detectorIndex >= 0 && detectorIndex < detectors.length) { const dtr = detectors[detectorIndex]; - const functionName = dtr.function; + const functionName = dtr.function as ML_JOB_AGGREGATION; // Check that the function maps to an ES aggregation, // and that the partitioning field isn't mlcategory @@ -334,7 +334,7 @@ export function isJobVersionGte(job: CombinedJob, version: string): boolean { // Note that the 'function' field in a record contains what the user entered e.g. 'high_count', // whereas the 'function_description' field holds an ML-built display hint for function e.g. 'count'. export function mlFunctionToESAggregation( - functionName: ML_JOB_AGGREGATION | string + functionName?: ML_JOB_AGGREGATION | string ): ES_AGGREGATION | null { if ( functionName === ML_JOB_AGGREGATION.MEAN || diff --git a/x-pack/plugins/ml/public/alerting/config_validator.tsx b/x-pack/plugins/ml/public/alerting/config_validator.tsx index 0a6df6978e67e..3afc02dc60600 100644 --- a/x-pack/plugins/ml/public/alerting/config_validator.tsx +++ b/x-pack/plugins/ml/public/alerting/config_validator.tsx @@ -50,7 +50,7 @@ export const ConfigValidator: FC = React.memo( lookbackIntervalInSeconds && alertIntervalInSeconds < lookbackIntervalInSeconds; - const bucketSpanDuration = parseInterval(jobConfigs[0].analysis_config.bucket_span); + const bucketSpanDuration = parseInterval(jobConfigs[0].analysis_config.bucket_span!); const notificationDuration = bucketSpanDuration ? Math.ceil(bucketSpanDuration.asMinutes()) * Math.min( diff --git a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx index f9fdfb17b319c..b9a4054879ec1 100644 --- a/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx +++ b/x-pack/plugins/ml/public/alerting/ml_anomaly_alert_trigger.tsx @@ -145,7 +145,7 @@ const MlAnomalyAlertTrigger: FC = ({ const maxNumberOfBuckets = useMemo(() => { if (jobConfigs.length === 0) return; - const bucketDuration = parseInterval(jobConfigs[0].analysis_config.bucket_span); + const bucketDuration = parseInterval(jobConfigs[0].analysis_config.bucket_span!); const lookbackIntervalDuration = advancedSettings.lookbackInterval ? parseInterval(advancedSettings.lookbackInterval) diff --git a/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts b/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts index 31c4f81545dcb..61e730ed48708 100644 --- a/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts +++ b/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts @@ -389,7 +389,7 @@ function buildAppStateQueryParam(queryFieldNames: string[]) { // may contain dollar delimited partition / influencer entity tokens and // drilldown time range settings. async function getAnomalyDetectionJobTestUrl(job: Job, customUrl: MlUrlConfig): Promise { - const interval = parseInterval(job.analysis_config.bucket_span); + const interval = parseInterval(job.analysis_config.bucket_span!); const bucketSpanSecs = interval !== null ? interval.asSeconds() : 0; // By default, return configured url_value. Look to substitute any dollar-delimited @@ -462,6 +462,7 @@ async function getAnomalyDetectionJobTestUrl(job: Job, customUrl: MlUrlConfig): undefined, jobConfig, datafeedConfig + // @ts-expect-error TODO: fix after elasticsearch-js bump )) as unknown as estypes.MlPreviewDatafeedResponse>['data']; const docTimeFieldName = job.data_description.time_field; diff --git a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx index fc6a913544169..33b6099565bd3 100644 --- a/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx +++ b/x-pack/plugins/ml/public/application/components/model_snapshots/revert_model_snapshot_flyout/revert_model_snapshot_flyout.tsx @@ -102,7 +102,7 @@ export const RevertModelSnapshotFlyout: FC = ({ }, [calendarEvents]); const createChartData = useCallback(async () => { - const bucketSpanMs = parseInterval(job.analysis_config.bucket_span)!.asMilliseconds(); + const bucketSpanMs = parseInterval(job.analysis_config.bucket_span!)!.asMilliseconds(); const eventRate = await loadEventRateForJob(job, bucketSpanMs, 100); const anomalyData = await loadAnomalyDataForJob(job, bucketSpanMs, 100); setEventRateData(eventRate); diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts b/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts index f6744dbd272b0..6b441f78da453 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts +++ b/x-pack/plugins/ml/public/application/explorer/explorer_utils.ts @@ -141,7 +141,7 @@ export interface SourceIndicesWithGeoFields { // create new job objects based on standard job config objects export function createJobs(jobs: CombinedJob[]): ExplorerJob[] { return jobs.map((job) => { - const bucketSpan = parseInterval(job.analysis_config.bucket_span); + const bucketSpan = parseInterval(job.analysis_config.bucket_span!); return { id: job.job_id, selected: false, diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts index 8a8db92dcc45f..589a4258503de 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/categorization_job_creator.ts @@ -237,7 +237,7 @@ export class CategorizationJobCreator extends JobCreator { ? ML_JOB_AGGREGATION.COUNT : ML_JOB_AGGREGATION.RARE; - const bs = job.analysis_config.bucket_span; + const bs = job.analysis_config.bucket_span!; this.setDetectorType(detectorType); if (dtr.partitionField !== null) { this.categorizationPerPartitionField = dtr.partitionField.id; diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts index d1c0364791064..0a6acf72791fd 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/job_creator.ts @@ -191,7 +191,7 @@ export class JobCreator { } public get bucketSpan(): BucketSpan { - return this._job_config.analysis_config.bucket_span; + return this._job_config.analysis_config.bucket_span!; } protected _setBucketSpanMs(bucketSpan: BucketSpan) { diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts index b12d9aa004d98..634699abe53d2 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/single_metric_job_creator.ts @@ -59,7 +59,7 @@ export class SingleMetricJobCreator extends JobCreator { // overriding set means we need to override get too // JS doesn't do inheritance very well public get bucketSpan(): BucketSpan { - return this._job_config.analysis_config.bucket_span; + return this._job_config.analysis_config.bucket_span!; } // aggregations need to be recreated whenever the detector or bucket_span change diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts index a933fdc0af5d5..ea409cfa0870a 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/job_creator/util/general.ts @@ -75,7 +75,7 @@ export function getRichDetectors( } return { - agg: newJobCapsService.getAggById(d.function), + agg: newJobCapsService.getAggById(d.function!), field, byField, overField, diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts index ad42adad33cd5..5954ed710c5f2 100644 --- a/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts +++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/inference_base.ts @@ -335,7 +335,7 @@ export abstract class InferenceBase { } private getDefaultInferenceConfig(): estypes.MlInferenceConfigUpdateContainer[keyof estypes.MlInferenceConfigUpdateContainer] { - return this.model.inference_config[ + return this.model.inference_config![ this.inferenceType as keyof estypes.MlInferenceConfigUpdateContainer ]; } diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/models/text_classification/common.ts b/x-pack/plugins/ml/public/application/model_management/test_models/models/text_classification/common.ts index e1a0ae6438e11..db40b056e8f7a 100644 --- a/x-pack/plugins/ml/public/application/model_management/test_models/models/text_classification/common.ts +++ b/x-pack/plugins/ml/public/application/model_management/test_models/models/text_classification/common.ts @@ -55,7 +55,7 @@ export function processInferenceResult( inferenceResult: InferenceResult, model: estypes.MlTrainedModelConfig ): FormattedTextClassificationResponse { - const labels: string[] = model.inference_config.text_classification?.classification_labels ?? []; + const labels: string[] = model.inference_config?.text_classification?.classification_labels ?? []; let formattedResponse = [ { diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx b/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx index c719aa7368cfa..06ff8128aa173 100644 --- a/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx +++ b/x-pack/plugins/ml/public/application/model_management/test_models/selected_model.tsx @@ -37,7 +37,7 @@ export const SelectedModel: FC = ({ model, inputType, deploymentId }) => const inferrer = useMemo(() => { if (model.model_type === TRAINED_MODEL_TYPE.PYTORCH) { - const taskType = Object.keys(model.inference_config)[0]; + const taskType = Object.keys(model.inference_config ?? {})[0]; switch (taskType) { case SUPPORTED_PYTORCH_TASKS.NER: diff --git a/x-pack/plugins/ml/public/application/model_management/test_models/utils.ts b/x-pack/plugins/ml/public/application/model_management/test_models/utils.ts index f97015773c908..a9f3d895fca36 100644 --- a/x-pack/plugins/ml/public/application/model_management/test_models/utils.ts +++ b/x-pack/plugins/ml/public/application/model_management/test_models/utils.ts @@ -21,7 +21,7 @@ export function isTestable(modelItem: ModelItem, checkForState = false) { if ( modelItem.model_type === TRAINED_MODEL_TYPE.PYTORCH && PYTORCH_TYPES.includes( - Object.keys(modelItem.inference_config)[0] as SupportedPytorchTasksType + Object.keys(modelItem.inference_config ?? {})[0] as SupportedPytorchTasksType ) && (checkForState === false || modelItem.stats?.deployment_stats?.some((v) => v.state === DEPLOYMENT_STATE.STARTED)) diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_viewable_detectors.ts b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_viewable_detectors.ts index 5df5aa9f971d4..b7e16306527fa 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_viewable_detectors.ts +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_viewable_detectors.ts @@ -21,7 +21,7 @@ export function getViewableDetectors(selectedJob: CombinedJob): ViewableDetector viewableDetectors.push({ index, detector_description: dtr.detector_description, - function: dtr.function, + function: dtr.function!, }); } }); diff --git a/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts b/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts index c2a329a0ba650..ff648d4ea7eff 100644 --- a/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts +++ b/x-pack/plugins/ml/public/embeddables/common/get_jobs_observable.ts @@ -24,7 +24,7 @@ export function getJobsObservable( switchMap((jobsIds) => anomalyDetectorService.getJobs$(jobsIds)), map((jobs) => { const explorerJobs: ExplorerJob[] = jobs.map((job) => { - const bucketSpan = parseInterval(job.analysis_config.bucket_span); + const bucketSpan = parseInterval(job.analysis_config.bucket_span!); return { id: job.job_id, selected: true, diff --git a/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts b/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts index 84241f58d04dc..68b3ed3491503 100644 --- a/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts +++ b/x-pack/plugins/ml/server/lib/alerts/alerting_service.ts @@ -481,7 +481,7 @@ export function alertingServiceProvider( } const maxBucket = resolveMaxTimeInterval( - jobsResponse.map((v) => v.analysis_config.bucket_span) + jobsResponse.map((v) => v.analysis_config.bucket_span!) ); if (maxBucket === undefined) { @@ -620,7 +620,7 @@ export function alertingServiceProvider( const datafeeds = await datafeedsService.getDatafeedByJobId(jobIds); const maxBucketInSeconds = resolveMaxTimeInterval( - jobsResponse.map((v) => v.analysis_config.bucket_span) + jobsResponse.map((v) => v.analysis_config.bucket_span!) ); if (maxBucketInSeconds === undefined) { diff --git a/x-pack/plugins/ml/server/lib/ml_client/types.ts b/x-pack/plugins/ml/server/lib/ml_client/types.ts index 45318a685d16c..afa2d204f9e43 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/types.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/types.ts @@ -29,6 +29,7 @@ export interface MlInferTrainedModelRequest extends estypes.MlInferTrainedModelR deployment_id?: string; } +// @ts-expect-error TODO: fix after elasticsearch-js bump export interface MlClient extends Omit { anomalySearch: ReturnType['anomalySearch']; diff --git a/x-pack/plugins/ml/server/models/job_service/jobs.ts b/x-pack/plugins/ml/server/models/job_service/jobs.ts index de2869899b65f..be9d6961cd6ba 100644 --- a/x-pack/plugins/ml/server/models/job_service/jobs.ts +++ b/x-pack/plugins/ml/server/models/job_service/jobs.ts @@ -80,7 +80,6 @@ export function jobsProvider( job_id: jobId, force: true, wait_for_completion: false, - // @ts-expect-error delete_user_annotations is not in types yet delete_user_annotations: deleteUserAnnotations, }); } @@ -166,7 +165,6 @@ export function jobsProvider( const { task } = await mlClient.resetJob({ job_id: jobId, wait_for_completion: false, - // @ts-expect-error delete_user_annotations is not in types yet delete_user_annotations: deleteUserAnnotations, }); results[jobId] = { reset: true, task }; @@ -254,7 +252,7 @@ export function jobsProvider( awaitingNodeAssignment: isJobAwaitingNodeAssignment(job), alertingRules: job.alerting_rules, jobTags: job.custom_settings?.job_tags ?? {}, - bucketSpanSeconds: parseInterval(job.analysis_config.bucket_span)!.asSeconds(), + bucketSpanSeconds: parseInterval(job.analysis_config.bucket_span!)!.asSeconds(), }; if (jobIds.find((j) => j === tempJob.id)) { diff --git a/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts b/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts index 815013da3cfd2..6b085f3e5490e 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job_caps/field_service.ts @@ -162,9 +162,9 @@ function combineAllRollupFields( rollupFields[fieldName] = conf.fields[fieldName]; } else { const aggs = conf.fields[fieldName]; - // @ts-expect-error fix type. our RollupFields type is better aggs.forEach((agg) => { if (rollupFields[fieldName].find((f) => f.agg === agg.agg) === null) { + // @ts-expect-error TODO: fix after elasticsearch-js bump rollupFields[fieldName].push(agg); } }); diff --git a/x-pack/plugins/ml/server/models/job_validation/validate_datafeed_preview.ts b/x-pack/plugins/ml/server/models/job_validation/validate_datafeed_preview.ts index 7491506505820..4477f423da25d 100644 --- a/x-pack/plugins/ml/server/models/job_validation/validate_datafeed_preview.ts +++ b/x-pack/plugins/ml/server/models/job_validation/validate_datafeed_preview.ts @@ -46,7 +46,6 @@ export async function validateDatafeedPreview( job_config: tempJob, datafeed_config: datafeed, }, - // @ts-expect-error es client types are wrong start, end, }, diff --git a/x-pack/plugins/ml/server/models/job_validation/validate_time_range.ts b/x-pack/plugins/ml/server/models/job_validation/validate_time_range.ts index c75303be46941..8e280811fb8c7 100644 --- a/x-pack/plugins/ml/server/models/job_validation/validate_time_range.ts +++ b/x-pack/plugins/ml/server/models/job_validation/validate_time_range.ts @@ -81,7 +81,7 @@ export async function validateTimeRange( } // check for minimum time range (25 buckets or 2 hours, whichever is longer) - const interval = parseInterval(job.analysis_config.bucket_span, true); + const interval = parseInterval(job.analysis_config.bucket_span!, true); if (interval === null) { messages.push({ id: 'bucket_span_invalid' }); } else { diff --git a/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts b/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts index ea282d78ada60..ba70e62f7d59d 100644 --- a/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts +++ b/x-pack/plugins/ml/server/models/results_service/anomaly_charts.ts @@ -734,7 +734,7 @@ export function anomalyChartsDataProvider(mlClient: MlClient, client: IScopedClu // Add extra properties used by the explorer dashboard charts. fullSeriesConfig.functionDescription = record.function_description; - const parsedBucketSpan = parseInterval(job.analysis_config.bucket_span); + const parsedBucketSpan = parseInterval(job.analysis_config.bucket_span!); if (parsedBucketSpan !== null) { fullSeriesConfig.bucketSpanSeconds = parsedBucketSpan.asSeconds(); } diff --git a/x-pack/plugins/ml/server/routes/management.ts b/x-pack/plugins/ml/server/routes/management.ts index 0179085869d36..9c68c8fcef261 100644 --- a/x-pack/plugins/ml/server/routes/management.ts +++ b/x-pack/plugins/ml/server/routes/management.ts @@ -139,7 +139,7 @@ export function managementRoutes({ router, routeGuard }: RouteInitialization) { state: modelStatsMapped[id].deployment_stats?.state ?? '', type: [ m.model_type, - ...Object.keys(m.inference_config), + ...Object.keys(m.inference_config!), ...(m.tags.includes(BUILT_IN_MODEL_TAG) ? [BUILT_IN_MODEL_TYPE] : []), ], spaces: modelSpaces.trainedModels[id] ?? [], diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule.cy.ts index 4965072e7038d..c11969448597d 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule.cy.ts @@ -153,15 +153,15 @@ describe('Custom query rules', () => { // expect define step to repopulate cy.get(DEFINE_EDIT_BUTTON).click(); cy.get(CUSTOM_QUERY_INPUT).should('have.value', ruleFields.ruleQuery); - cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true }); + cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click(); cy.get(DEFINE_CONTINUE_BUTTON).should('not.exist'); // expect about step to populate cy.get(ABOUT_EDIT_BUTTON).click(); cy.get(RULE_NAME_INPUT).invoke('val').should('eql', ruleFields.ruleName); - cy.get(ABOUT_CONTINUE_BTN).should('exist').click({ force: true }); + cy.get(ABOUT_CONTINUE_BTN).should('exist').click(); cy.get(ABOUT_CONTINUE_BTN).should('not.exist'); - cy.get(SCHEDULE_CONTINUE_BUTTON).click({ force: true }); + cy.get(SCHEDULE_CONTINUE_BUTTON).click(); createAndEnableRule(); @@ -209,7 +209,7 @@ describe('Custom query rules', () => { 'contain', `${ruleFields.threatSubtechnique.name} (${ruleFields.threatSubtechnique.id})` ); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', 'auditbeat-*'); @@ -410,7 +410,7 @@ describe('Custom query rules', () => { cy.get(ACTIONS_NOTIFY_WHEN_BUTTON).should('have.text', 'Per rule run'); goToAboutStepTab(); - cy.get(TAGS_CLEAR_BUTTON).click({ force: true }); + cy.get(TAGS_CLEAR_BUTTON).click(); fillAboutRule(getEditedRule()); cy.intercept('GET', '/api/detection_engine/rules?id*').as('getRule'); @@ -430,7 +430,7 @@ describe('Custom query rules', () => { getDetails(RISK_SCORE_DETAILS).should('have.text', `${getEditedRule().risk_score}`); getDetails(TAGS_DETAILS).should('have.text', expectedEditedtags); }); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', getEditedRule().note); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should( diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule_data_view.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule_data_view.cy.ts index b0227919b6885..accdf1dfaa8af 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule_data_view.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_query_rule_data_view.cy.ts @@ -124,7 +124,7 @@ describe('Custom query rules', () => { }); getDetails(TAGS_DETAILS).should('have.text', expectedTags); }); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(DATA_VIEW_DETAILS).should('have.text', rule.data_view_id); @@ -153,17 +153,17 @@ describe('Custom query rules', () => { it('Creates and edits a new rule with a data view', function () { visit(RULE_CREATION); fillDefineCustomRuleAndContinue(rule); - cy.get(RULE_NAME_INPUT).clear({ force: true }).type(rule.name, { force: true }); - cy.get(RULE_DESCRIPTION_INPUT).clear({ force: true }).type(rule.description, { force: true }); + cy.get(RULE_NAME_INPUT).clear().type(rule.name); + cy.get(RULE_DESCRIPTION_INPUT).clear().type(rule.description); - cy.get(ABOUT_CONTINUE_BTN).should('exist').click({ force: true }); + cy.get(ABOUT_CONTINUE_BTN).should('exist').click(); fillScheduleRuleAndContinue(rule); createRuleWithoutEnabling(); goToRuleDetails(); - cy.get(EDIT_RULE_SETTINGS_LINK).click({ force: true }); + cy.get(EDIT_RULE_SETTINGS_LINK).click(); cy.get(RULE_NAME_HEADER).should('contain', 'Edit rule settings'); }); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_saved_query_rule.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_saved_query_rule.cy.ts index 6b8a2acc6ba8a..ff08bb35582e5 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_saved_query_rule.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/custom_saved_query_rule.cy.ts @@ -74,7 +74,7 @@ describe('Custom saved_query rules', () => { getCustomQueryInput().should('have.value', savedQueryQuery).should('be.disabled'); cy.get(QUERY_BAR).should('contain', savedQueryFilterKey); - cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true }); + cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click(); cy.get(DEFINE_CONTINUE_BUTTON).should('not.exist'); fillAboutRuleAndContinue(rule); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/event_correlation_rule.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/event_correlation_rule.cy.ts index 6eb47d6bc7765..79160b3677865 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/event_correlation_rule.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/event_correlation_rule.cy.ts @@ -111,7 +111,7 @@ describe('EQL rules', () => { }); getDetails(TAGS_DETAILS).should('have.text', expectedTags); }); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join('')); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/indicator_match_rule.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/indicator_match_rule.cy.ts index fbc28e8a2c671..843a6250dca2c 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/indicator_match_rule.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/indicator_match_rule.cy.ts @@ -458,7 +458,7 @@ describe('indicator match', () => { }); getDetails(TAGS_DETAILS).should('have.text', expectedTags); }); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/new_terms_rule.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/new_terms_rule.cy.ts index 8eb5fc0ea90b7..d455164d0931e 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/new_terms_rule.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/new_terms_rule.cy.ts @@ -110,7 +110,7 @@ describe('New Terms rules', () => { }); getDetails(TAGS_DETAILS).should('have.text', expectedTags); }); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join('')); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/override.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/override.cy.ts index 5b24bf20bff00..9d67eb3ed680a 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/override.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/override.cy.ts @@ -125,7 +125,7 @@ describe('Detection rules, override', () => { }); }); }); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join('')); diff --git a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/threshold_rule.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/threshold_rule.cy.ts index e20fac10624ac..f5ee340633e71 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/detection_rules/threshold_rule.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/detection_rules/threshold_rule.cy.ts @@ -109,7 +109,7 @@ describe('Detection rules, threshold', () => { }); getDetails(TAGS_DETAILS).should('have.text', expectedTags); }); - cy.get(INVESTIGATION_NOTES_TOGGLE).click({ force: true }); + cy.get(INVESTIGATION_NOTES_TOGGLE).click(); cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', getIndexPatterns().join('')); diff --git a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts b/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts index 22f5609b0d6af..ba36ed2f70cd8 100644 --- a/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts +++ b/x-pack/plugins/security_solution/cypress/e2e/investigations/alerts/expandable_flyout/alert_details_right_panel_overview_tab.cy.ts @@ -32,12 +32,14 @@ import { DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_HEADER, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_CONTENT, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VALUES, - DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VIEW_ALL_BUTTON, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_HEADER, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_CONTENT, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES, DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VIEW_ALL_BUTTON, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES, } from '../../../../screens/document_expandable_flyout'; import { expandFirstAlertExpandableFlyout, @@ -46,6 +48,8 @@ import { toggleOverviewTabInvestigationSection, toggleOverviewTabInsightsSection, toggleOverviewTabVisualizationsSection, + clickThreatIntelligenceViewAllButton, + clickPrevalenceViewAllButton, } from '../../../../tasks/document_expandable_flyout'; import { cleanKibana } from '../../../../tasks/common'; import { login, visit } from '../../../../tasks/login'; @@ -138,7 +142,7 @@ describe.skip( ); }); - it('should display investigatioin guide button', () => { + it('should display investigation guide button', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INVESTIGATION_GUIDE_BUTTON) .should('be.visible') .and('have.text', 'Investigation guide'); @@ -222,9 +226,7 @@ describe.skip( // TODO work on getting proper IoC data to make the threat intelligence section work here // and improve when we can navigate Threat Intelligence to sub tab directly it.skip('should navigate to left panel, entities tab when view all fields of threat intelligence is clicked', () => { - cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VIEW_ALL_BUTTON) - .should('be.visible') - .click(); + clickThreatIntelligenceViewAllButton(); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); }); @@ -261,12 +263,35 @@ describe.skip( // TODO work on getting proper data to display in the cases, ancestry, session and source event sections // and improve when we can navigate Correlations to sub tab directly - it.skip('should navigate to left panel, entities tab when view all fields of threat intelligence is clicked', () => { + it.skip('should navigate to left panel, entities tab when view all fields of correlations is clicked', () => { cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VIEW_ALL_BUTTON) .should('be.visible') .click(); cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); }); + + // TODO work on getting proper data to make the prevalence section work here + // we need to generate enough data to have at least one field with prevalence + it.skip('should display prevalence section', () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER) + .scrollIntoView() + .should('be.visible') + .and('have.text', 'Prevalence'); + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT) + .should('be.visible') + .within(() => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES) + .should('be.visible') + .and('have.text', 'is uncommon'); + }); + }); + + // TODO work on getting proper data to make the prevalence section work here + // we need to generate enough data to have at least one field with prevalence + it.skip('should navigate to left panel, entities tab when view all fields of prevalence is clicked', () => { + clickPrevalenceViewAllButton(); + cy.get(DOCUMENT_DETAILS_FLYOUT_INSIGHTS_TAB_ENTITIES_CONTENT).should('be.visible'); + }); }); describe('visualizations section', () => { diff --git a/x-pack/plugins/security_solution/cypress/screens/document_expandable_flyout.ts b/x-pack/plugins/security_solution/cypress/screens/document_expandable_flyout.ts index 607bc93a3a6c5..680b1fd4c7eb4 100644 --- a/x-pack/plugins/security_solution/cypress/screens/document_expandable_flyout.ts +++ b/x-pack/plugins/security_solution/cypress/screens/document_expandable_flyout.ts @@ -84,6 +84,10 @@ import { INSIGHTS_CORRELATIONS_CONTENT_TEST_ID, INSIGHTS_CORRELATIONS_VALUE_TEST_ID, INSIGHTS_CORRELATIONS_VIEW_ALL_BUTTON_TEST_ID, + INSIGHTS_PREVALENCE_TITLE_TEST_ID, + INSIGHTS_PREVALENCE_CONTENT_TEST_ID, + INSIGHTS_PREVALENCE_VALUE_TEST_ID, + INSIGHTS_PREVALENCE_VIEW_ALL_BUTTON_TEST_ID, } from '../../public/flyout/right/components/test_ids'; import { getClassSelector, @@ -337,6 +341,15 @@ export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VALUES = export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_CORRELATIONS_VIEW_ALL_BUTTON = getDataTestSubjectSelector(INSIGHTS_CORRELATIONS_VIEW_ALL_BUTTON_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_HEADER = + getDataTestSubjectSelector(INSIGHTS_PREVALENCE_TITLE_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_CONTENT = + getDataTestSubjectSelector(INSIGHTS_PREVALENCE_CONTENT_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VALUES = + getDataTestSubjectSelector(INSIGHTS_PREVALENCE_VALUE_TEST_ID); +export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VIEW_ALL_BUTTON = + getDataTestSubjectSelector(INSIGHTS_PREVALENCE_VIEW_ALL_BUTTON_TEST_ID); + export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_VISUALIZATIONS_SECTION_HEADER = getDataTestSubjectSelector(VISUALIZATIONS_SECTION_HEADER_TEST_ID); export const DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_ANALYZER_TREE = diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts index 3dd0f5d563597..ae8c8108460dd 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts @@ -77,19 +77,19 @@ import { goToRuleEditSettings } from './rule_details'; import { goToActionsStepTab } from './create_new_rule'; export const enableRule = (rulePosition: number) => { - cy.get(RULE_SWITCH).eq(rulePosition).click({ force: true }); + cy.get(RULE_SWITCH).eq(rulePosition).click(); }; export const editFirstRule = () => { cy.get(COLLAPSED_ACTION_BTN).should('be.visible'); - cy.get(COLLAPSED_ACTION_BTN).first().click({ force: true }); + cy.get(COLLAPSED_ACTION_BTN).first().click(); cy.get(EDIT_RULE_ACTION_BTN).should('be.visible'); cy.get(EDIT_RULE_ACTION_BTN).click(); }; export const duplicateFirstRule = () => { cy.get(COLLAPSED_ACTION_BTN).should('be.visible'); - cy.get(COLLAPSED_ACTION_BTN).first().click({ force: true }); + cy.get(COLLAPSED_ACTION_BTN).first().click(); cy.get(DUPLICATE_RULE_ACTION_BTN).should('be.visible'); cy.get(DUPLICATE_RULE_ACTION_BTN).click(); cy.get(CONFIRM_DUPLICATE_RULE).click(); @@ -102,7 +102,7 @@ export const duplicateFirstRule = () => { * flake. */ export const duplicateRuleFromMenu = () => { - const click = ($el: Cypress.ObjectLike) => cy.wrap($el).click({ force: true }); + const click = ($el: Cypress.ObjectLike) => cy.wrap($el).click(); cy.get(LOADING_INDICATOR).should('not.exist'); cy.get(ALL_ACTIONS).pipe(click); cy.get(DUPLICATE_RULE_MENU_PANEL_BTN).should('be.visible'); @@ -124,12 +124,12 @@ export const checkDuplicatedRule = () => { }; export const deleteFirstRule = () => { - cy.get(COLLAPSED_ACTION_BTN).first().click({ force: true }); + cy.get(COLLAPSED_ACTION_BTN).first().click(); cy.get(DELETE_RULE_ACTION_BTN).click(); }; export const deleteSelectedRules = () => { - cy.get(BULK_ACTIONS_BTN).click({ force: true }); + cy.get(BULK_ACTIONS_BTN).click(); cy.get(DELETE_RULE_BULK_BTN).click(); }; @@ -150,7 +150,7 @@ export const deleteRuleFromDetailsPage = () => { export const duplicateSelectedRulesWithoutExceptions = () => { cy.log('Duplicate selected rules'); - cy.get(BULK_ACTIONS_BTN).click({ force: true }); + cy.get(BULK_ACTIONS_BTN).click(); cy.get(DUPLICATE_RULE_BULK_BTN).click(); cy.get(DUPLICATE_WITHOUT_EXCEPTIONS_OPTION).click(); cy.get(CONFIRM_DUPLICATE_RULE).click(); @@ -158,7 +158,7 @@ export const duplicateSelectedRulesWithoutExceptions = () => { export const duplicateSelectedRulesWithExceptions = () => { cy.log('Duplicate selected rules'); - cy.get(BULK_ACTIONS_BTN).click({ force: true }); + cy.get(BULK_ACTIONS_BTN).click(); cy.get(DUPLICATE_RULE_BULK_BTN).click(); cy.get(DUPLICATE_WITH_EXCEPTIONS_OPTION).click(); cy.get(CONFIRM_DUPLICATE_RULE).click(); @@ -166,7 +166,7 @@ export const duplicateSelectedRulesWithExceptions = () => { export const duplicateSelectedRulesWithNonExpiredExceptions = () => { cy.log('Duplicate selected rules'); - cy.get(BULK_ACTIONS_BTN).click({ force: true }); + cy.get(BULK_ACTIONS_BTN).click(); cy.get(DUPLICATE_RULE_BULK_BTN).click(); cy.get(DUPLICATE_WITH_EXCEPTIONS_WITHOUT_EXPIRED_OPTION).click(); cy.get(CONFIRM_DUPLICATE_RULE).click(); @@ -174,13 +174,13 @@ export const duplicateSelectedRulesWithNonExpiredExceptions = () => { export const enableSelectedRules = () => { cy.log('Enable selected rules'); - cy.get(BULK_ACTIONS_BTN).click({ force: true }); + cy.get(BULK_ACTIONS_BTN).click(); cy.get(ENABLE_RULE_BULK_BTN).click(); }; export const disableSelectedRules = () => { cy.log('Disable selected rules'); - cy.get(BULK_ACTIONS_BTN).click({ force: true }); + cy.get(BULK_ACTIONS_BTN).click(); cy.get(DISABLE_RULE_BULK_BTN).click(); }; @@ -194,9 +194,7 @@ export const exportRule = (name: string) => { export const filterBySearchTerm = (term: string) => { cy.log(`Filter rules by search term: "${term}"`); - cy.get(RULE_SEARCH_FIELD) - .type(term, { force: true }) - .trigger('search', { waitForAnimations: true }); + cy.get(RULE_SEARCH_FIELD).type(term).trigger('search'); }; export const filterByTags = (tags: string[]) => { @@ -226,23 +224,23 @@ export const filterByElasticRules = () => { }; export const filterByCustomRules = () => { - cy.get(CUSTOM_RULES_BTN).click({ force: true }); + cy.get(CUSTOM_RULES_BTN).click(); }; export const filterByEnabledRules = () => { - cy.get(ENABLED_RULES_BTN).click({ force: true }); + cy.get(ENABLED_RULES_BTN).click(); }; export const filterByDisabledRules = () => { - cy.get(DISABLED_RULES_BTN).click({ force: true }); + cy.get(DISABLED_RULES_BTN).click(); }; export const goToRuleDetails = () => { - cy.get(RULE_NAME).first().click({ force: true }); + cy.get(RULE_NAME).first().click(); }; export const goToTheRuleDetailsOf = (ruleName: string) => { - cy.contains(RULE_NAME, ruleName).click({ force: true }); + cy.contains(RULE_NAME, ruleName).click(); }; export const loadPrebuiltDetectionRules = () => { @@ -268,7 +266,7 @@ export const openIntegrationsPopover = () => { }; export const reloadDeletedRules = () => { - cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).click({ force: true }); + cy.get(LOAD_PREBUILT_RULES_ON_PAGE_HEADER_BTN).click(); }; /** @@ -395,8 +393,8 @@ export const checkAutoRefresh = (ms: number, condition: string) => { export const importRules = (rulesFile: string) => { cy.get(RULE_IMPORT_MODAL).click(); cy.get(INPUT_FILE).should('exist'); - cy.get(INPUT_FILE).trigger('click', { force: true }).selectFile(rulesFile).trigger('change'); - cy.get(RULE_IMPORT_MODAL_BUTTON).last().click({ force: true }); + cy.get(INPUT_FILE).trigger('click').selectFile(rulesFile).trigger('change'); + cy.get(RULE_IMPORT_MODAL_BUTTON).last().click(); cy.get(INPUT_FILE).should('not.exist'); }; @@ -513,11 +511,11 @@ const selectOverwriteConnectorsRulesImport = () => { export const importRulesWithOverwriteAll = (rulesFile: string) => { cy.get(RULE_IMPORT_MODAL).click(); cy.get(INPUT_FILE).should('exist'); - cy.get(INPUT_FILE).trigger('click', { force: true }).selectFile(rulesFile).trigger('change'); + cy.get(INPUT_FILE).trigger('click').selectFile(rulesFile).trigger('change'); selectOverwriteRulesImport(); selectOverwriteExceptionsRulesImport(); selectOverwriteConnectorsRulesImport(); - cy.get(RULE_IMPORT_MODAL_BUTTON).last().click({ force: true }); + cy.get(RULE_IMPORT_MODAL_BUTTON).last().click(); cy.get(INPUT_FILE).should('not.exist'); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/document_expandable_flyout.ts b/x-pack/plugins/security_solution/cypress/tasks/document_expandable_flyout.ts index cdcdb120b7f8a..9d3ee66d5a1ef 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/document_expandable_flyout.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/document_expandable_flyout.ts @@ -37,6 +37,8 @@ import { DOCUMENT_DETAILS_FLYOUT_FOOTER_TAKE_ACTION_BUTTON_DROPDOWN, KIBANA_NAVBAR_ALERTS_PAGE, KIBANA_NAVBAR_CASES_PAGE, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VIEW_ALL_BUTTON, + DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VIEW_ALL_BUTTON, } from '../screens/document_expandable_flyout'; import { EXPAND_ALERT_BTN } from '../screens/alerts'; import { getClassSelector } from '../helpers/common'; @@ -307,3 +309,21 @@ export const clearFilters = () => cy.get(DOCUMENT_DETAILS_FLYOUT_BODY).within(() => { cy.get(DOCUMENT_DETAILS_FLYOUT_TABLE_TAB_ROW_CELL_FILTER_OUT).first().click(); }); + +/** + * Click on the view all button under the right section, Insights, Threat Intelligence + */ +export const clickThreatIntelligenceViewAllButton = () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_THREAT_INTELLIGENCE_VIEW_ALL_BUTTON) + .should('be.visible') + .click(); +}; + +/** + * Click on the view all button under the right section, Insights, Prevalence + */ +export const clickPrevalenceViewAllButton = () => { + cy.get(DOCUMENT_DETAILS_FLYOUT_OVERVIEW_TAB_INSIGHTS_PREVALENCE_VIEW_ALL_BUTTON) + .should('be.visible') + .click(); +}; diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/links.ts b/x-pack/plugins/security_solution/public/cloud_security_posture/links.ts index 40c1befc990cc..ab41f2b667a10 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/links.ts +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/links.ts @@ -8,6 +8,7 @@ import { getSecuritySolutionLink } from '@kbn/cloud-security-posture-plugin/publ import { i18n } from '@kbn/i18n'; import { SecurityPageName, SERVER_APP_ID } from '../../common/constants'; import cloudSecurityPostureDashboardImage from '../common/images/cloud_security_posture_dashboard_page.png'; +import cloudNativeVulnerabilityManagementDashboardImage from '../common/images/cloud_native_vulnerability_management_dashboard_page.png'; import type { LinkCategories, LinkItem } from '../common/links/types'; import { IconExceptionLists } from '../management/icons/exception_lists'; @@ -34,6 +35,17 @@ export const dashboardLinks: LinkItem = { ...commonLinkProperties, }; +export const vulnerabilityDashboardLink: LinkItem = { + isBeta: true, + ...getSecuritySolutionLink('vulnerability_dashboard'), + description: i18n.translate('xpack.securitySolution.appLinks.vulnerabilityDashboardDescription', { + defaultMessage: + 'Cloud Native Vulnerability Management (CNVM) allows you to identify vulnerabilities in your cloud workloads.', + }), + landingImage: cloudNativeVulnerabilityManagementDashboardImage, + ...commonLinkProperties, +}; + export const manageLinks: LinkItem = { ...getSecuritySolutionLink('benchmarks'), description: i18n.translate( diff --git a/x-pack/plugins/security_solution/public/common/images/cloud_native_vulnerability_management_dashboard_page.png b/x-pack/plugins/security_solution/public/common/images/cloud_native_vulnerability_management_dashboard_page.png new file mode 100644 index 0000000000000..fa03990db6e70 Binary files /dev/null and b/x-pack/plugins/security_solution/public/common/images/cloud_native_vulnerability_management_dashboard_page.png differ diff --git a/x-pack/plugins/security_solution/public/dashboards/links.ts b/x-pack/plugins/security_solution/public/dashboards/links.ts index 452b03444988e..c913eb42abd9c 100644 --- a/x-pack/plugins/security_solution/public/dashboards/links.ts +++ b/x-pack/plugins/security_solution/public/dashboards/links.ts @@ -9,7 +9,10 @@ import { DASHBOARDS_PATH, SecurityPageName, SERVER_APP_ID } from '../../common/c import { DASHBOARDS } from '../app/translations'; import type { LinkItem } from '../common/links/types'; import { links as kubernetesLinks } from '../kubernetes/links'; -import { dashboardLinks as cloudSecurityPostureLinks } from '../cloud_security_posture/links'; +import { + dashboardLinks as cloudSecurityPostureLinks, + vulnerabilityDashboardLink, +} from '../cloud_security_posture/links'; import { ecsDataQualityDashboardLinks, detectionResponseLinks, @@ -33,6 +36,7 @@ export const dashboardsLandingLinks: LinkItem = { detectionResponseLinks, kubernetesLinks, cloudSecurityPostureLinks, + vulnerabilityDashboardLink, entityAnalyticsLinks, ecsDataQualityDashboardLinks, ], diff --git a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx index 379ea0f37929f..d7b3bfeb4a26f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.test.tsx @@ -16,12 +16,11 @@ import { } from '../../../common/mock'; import { createStore } from '../../../common/store'; import { kibanaObservable } from '@kbn/timelines-plugin/public/mock'; -import { - ALERTS_PATH, - ALERT_DETAILS_REDIRECT_PATH, - DEFAULT_ALERTS_INDEX, -} from '../../../../common/constants'; +import { ALERTS_PATH, ALERT_DETAILS_REDIRECT_PATH } from '../../../../common/constants'; import { mockHistory } from '../../../common/utils/route/mocks'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; + +jest.mock('../../../common/hooks/use_experimental_features'); jest.mock('../../../common/lib/kibana'); @@ -67,7 +66,7 @@ describe('AlertDetailsRedirect', () => { expect(historyMock.replace).toHaveBeenCalledWith({ hash: '', pathname: ALERTS_PATH, - search: `?query=(language:kuery,query:'_id: ${testAlertId}')&timerange=(global:(linkTo:!(timeline,socTrends),timerange:(from:'${testTimestamp}',kind:absolute,to:'2023-04-20T12:05:00.000Z')),timeline:(linkTo:!(global,socTrends),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now/d,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now/d)))&pageFilters=!((exclude:!f,existsSelected:!f,fieldName:kibana.alert.workflow_status,selectedOptions:!(),title:Status))&eventFlyout=(panelView:eventDetail,params:(eventId:${testAlertId},indexName:${testIndex}))`, + search: `?query=%28language%3Akuery%2Cquery%3A%27_id%3A+test-alert-id%27%29&timerange=%28global%3A%28linkTo%3A%21%28timeline%2CsocTrends%29%2Ctimerange%3A%28from%3A%272023-04-20T12%3A00%3A00.000Z%27%2Ckind%3Aabsolute%2Cto%3A%272023-04-20T12%3A05%3A00.000Z%27%29%29%2Ctimeline%3A%28linkTo%3A%21%28global%2CsocTrends%29%2Ctimerange%3A%28from%3A%272020-07-07T08%3A20%3A18.966Z%27%2CfromStr%3Anow%2Fd%2Ckind%3Arelative%2Cto%3A%272020-07-08T08%3A20%3A18.966Z%27%2CtoStr%3Anow%2Fd%29%29%29&pageFilters=%21%28%28exclude%3A%21f%2CexistsSelected%3A%21f%2CfieldName%3Akibana.alert.workflow_status%2CselectedOptions%3A%21%28%29%2Ctitle%3AStatus%29%29&eventFlyout=%28panelView%3AeventDetail%2Cparams%3A%28eventId%3Atest-alert-id%2CindexName%3A.someTestIndex%29%29`, state: undefined, }); }); @@ -96,7 +95,7 @@ describe('AlertDetailsRedirect', () => { expect(historyMock.replace).toHaveBeenCalledWith({ hash: '', pathname: ALERTS_PATH, - search: `?query=(language:kuery,query:'_id: ${testAlertId}')&timerange=(global:(linkTo:!(timeline,socTrends),timerange:(from:'2020-07-07T08:20:18.966Z',kind:absolute,to:'2020-07-08T08:25:18.966Z')),timeline:(linkTo:!(global,socTrends),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now/d,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now/d)))&pageFilters=!((exclude:!f,existsSelected:!f,fieldName:kibana.alert.workflow_status,selectedOptions:!(),title:Status))&eventFlyout=(panelView:eventDetail,params:(eventId:${testAlertId},indexName:${testIndex}))`, + search: `?query=%28language%3Akuery%2Cquery%3A%27_id%3A+test-alert-id%27%29&timerange=%28global%3A%28linkTo%3A%21%28timeline%2CsocTrends%29%2Ctimerange%3A%28from%3A%272020-07-07T08%3A20%3A18.966Z%27%2Ckind%3Aabsolute%2Cto%3A%272020-07-08T08%3A25%3A18.966Z%27%29%29%2Ctimeline%3A%28linkTo%3A%21%28global%2CsocTrends%29%2Ctimerange%3A%28from%3A%272020-07-07T08%3A20%3A18.966Z%27%2CfromStr%3Anow%2Fd%2Ckind%3Arelative%2Cto%3A%272020-07-08T08%3A20%3A18.966Z%27%2CtoStr%3Anow%2Fd%29%29%29&pageFilters=%21%28%28exclude%3A%21f%2CexistsSelected%3A%21f%2CfieldName%3Akibana.alert.workflow_status%2CselectedOptions%3A%21%28%29%2Ctitle%3AStatus%29%29&eventFlyout=%28panelView%3AeventDetail%2Cparams%3A%28eventId%3Atest-alert-id%2CindexName%3A.someTestIndex%29%29`, state: undefined, }); }); @@ -124,9 +123,42 @@ describe('AlertDetailsRedirect', () => { expect(historyMock.replace).toHaveBeenCalledWith({ hash: '', pathname: ALERTS_PATH, - search: `?query=(language:kuery,query:'_id: ${testAlertId}')&timerange=(global:(linkTo:!(timeline,socTrends),timerange:(from:'2020-07-07T08:20:18.966Z',kind:absolute,to:'2020-07-08T08:25:18.966Z')),timeline:(linkTo:!(global,socTrends),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now/d,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now/d)))&pageFilters=!((exclude:!f,existsSelected:!f,fieldName:kibana.alert.workflow_status,selectedOptions:!(),title:Status))&eventFlyout=(panelView:eventDetail,params:(eventId:${testAlertId},indexName:.internal${DEFAULT_ALERTS_INDEX}-default))`, + search: `?query=%28language%3Akuery%2Cquery%3A%27_id%3A+test-alert-id%27%29&timerange=%28global%3A%28linkTo%3A%21%28timeline%2CsocTrends%29%2Ctimerange%3A%28from%3A%272020-07-07T08%3A20%3A18.966Z%27%2Ckind%3Aabsolute%2Cto%3A%272020-07-08T08%3A25%3A18.966Z%27%29%29%2Ctimeline%3A%28linkTo%3A%21%28global%2CsocTrends%29%2Ctimerange%3A%28from%3A%272020-07-07T08%3A20%3A18.966Z%27%2CfromStr%3Anow%2Fd%2Ckind%3Arelative%2Cto%3A%272020-07-08T08%3A20%3A18.966Z%27%2CtoStr%3Anow%2Fd%29%29%29&pageFilters=%21%28%28exclude%3A%21f%2CexistsSelected%3A%21f%2CfieldName%3Akibana.alert.workflow_status%2CselectedOptions%3A%21%28%29%2Ctitle%3AStatus%29%29&eventFlyout=%28panelView%3AeventDetail%2Cparams%3A%28eventId%3Atest-alert-id%2CindexName%3A.internal.alerts-security.alerts-default%29%29`, state: undefined, }); }); }); + + describe('When expandable flyout is enabled', () => { + beforeEach(() => { + jest.mocked(useIsExperimentalFeatureEnabled).mockReturnValue(true); + }); + + describe('when eventFlyout is not in the query', () => { + it('redirects to the expected path with the correct query parameters', () => { + const testSearch = `?index=${testIndex}×tamp=${testTimestamp}`; + const historyMock = { + ...mockHistory, + location: { + hash: '', + pathname: mockPathname, + search: testSearch, + state: '', + }, + }; + render( + + + + + + ); + + const [{ search, pathname }] = historyMock.replace.mock.lastCall; + + expect(search as string).toMatch(/eventFlyout.*right/); + expect(pathname).toEqual(ALERTS_PATH); + }); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx index d2942acd0ca7b..c423fc2eac6df 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/alerts/alert_details_redirect.tsx @@ -17,6 +17,9 @@ import { ALERTS_PATH, DEFAULT_ALERTS_INDEX } from '../../../../common/constants' import { URL_PARAM_KEY } from '../../../common/hooks/use_url_state'; import { inputsSelectors } from '../../../common/store'; import { formatPageFilterSearchParam } from '../../../../common/utils/format_page_filter_search_param'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; +import { resolveFlyoutParams } from './utils'; +import { FLYOUT_URL_PARAM } from '../../../flyout/url/use_sync_flyout_state_with_url'; export const AlertDetailsRedirect = () => { const { alertId } = useParams<{ alertId: string }>(); @@ -54,14 +57,6 @@ export const AlertDetailsRedirect = () => { }, }); - const flyoutString = encode({ - panelView: 'eventDetail', - params: { - eventId: alertId, - indexName: index, - }, - }); - const kqlAppQuery = encode({ language: 'kuery', query: `_id: ${alertId}` }); const statusPageFilter: FilterItemObj = { @@ -73,7 +68,21 @@ export const AlertDetailsRedirect = () => { const pageFiltersQuery = encode(formatPageFilterSearchParam([statusPageFilter])); - const url = `${ALERTS_PATH}?${URL_PARAM_KEY.appQuery}=${kqlAppQuery}&${URL_PARAM_KEY.timerange}=${timerange}&${URL_PARAM_KEY.pageFilter}=${pageFiltersQuery}&${URL_PARAM_KEY.eventFlyout}=${flyoutString}`; + const currentFlyoutParams = searchParams.get(FLYOUT_URL_PARAM); + + const isSecurityFlyoutEnabled = useIsExperimentalFeatureEnabled('securityFlyoutEnabled'); + + const urlParams = new URLSearchParams({ + [URL_PARAM_KEY.appQuery]: kqlAppQuery, + [URL_PARAM_KEY.timerange]: timerange, + [URL_PARAM_KEY.pageFilter]: pageFiltersQuery, + [URL_PARAM_KEY.eventFlyout]: resolveFlyoutParams( + { index, alertId, isSecurityFlyoutEnabled }, + currentFlyoutParams + ), + }); + + const url = `${ALERTS_PATH}?${urlParams.toString()}`; return ; }; diff --git a/x-pack/plugins/security_solution/public/detections/pages/alerts/utils.ts b/x-pack/plugins/security_solution/public/detections/pages/alerts/utils.ts new file mode 100644 index 0000000000000..db1250b4e6cae --- /dev/null +++ b/x-pack/plugins/security_solution/public/detections/pages/alerts/utils.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { encode } from '@kbn/rison'; +import { expandableFlyoutStateFromEventMeta } from '../../../flyout/url/expandable_flyout_state_from_event_meta'; + +export interface ResolveFlyoutParamsConfig { + index: string; + alertId: string; + isSecurityFlyoutEnabled: boolean; +} + +/** + * Resolves url parameters for the flyout, serialized as + * rison string. NOTE: if user is already redirected to this route with flyout parameters set, + * we simply use them. It will be the case when users are coming here using a link obtained + * with Share Button on the Expandable Flyout + */ +export const resolveFlyoutParams = ( + { index, alertId, isSecurityFlyoutEnabled }: ResolveFlyoutParamsConfig, + currentParamsString: string | null +) => { + if (!isSecurityFlyoutEnabled) { + const legacyFlyoutString = encode({ + panelView: 'eventDetail', + params: { + eventId: alertId, + indexName: index, + }, + }); + return legacyFlyoutString; + } + + if (currentParamsString) { + return currentParamsString; + } + + const modernFlyoutString = encode( + expandableFlyoutStateFromEventMeta({ index, eventId: alertId, scopeId: 'alerts-page' }) + ); + + return modernFlyoutString; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx index 390e5c38249ae..6c08fa5b1d2c1 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/correlations_overview.tsx @@ -6,12 +6,12 @@ */ import React, { useCallback } from 'react'; -import { EuiButtonEmpty } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiPanel } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { InsightsSummaryRow } from './insights_summary_row'; import { useCorrelations } from '../hooks/use_correlations'; import { INSIGHTS_CORRELATIONS_TEST_ID } from './test_ids'; import { InsightsSubSection } from './insights_subsection'; -import { InsightsSummaryPanel } from './insights_summary_panel'; import { useRightPanelContext } from '../context'; import { CORRELATIONS_TEXT, CORRELATIONS_TITLE, VIEW_ALL } from './translations'; import { LeftPanelKey, LeftPanelInsightsTabPath } from '../../left'; @@ -51,7 +51,18 @@ export const CorrelationsOverview: React.FC = () => { title={CORRELATIONS_TITLE} data-test-subj={INSIGHTS_CORRELATIONS_TEST_ID} > - + + + {data.map((d) => ( + + ))} + + = () => { @@ -83,11 +85,9 @@ export const NoTimestamp: Story = () => { } as unknown as RightPanelContext; return ( - - - - - + + + ); }; 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 fbadb5b8b0e7f..5d9d5a4227aff 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 @@ -11,6 +11,7 @@ import { RightPanelContext } from '../context'; import { FLYOUT_HEADER_RISK_SCORE_VALUE_TEST_ID, FLYOUT_HEADER_SEVERITY_TITLE_TEST_ID, + FLYOUT_HEADER_SHARE_BUTTON_TEST_ID, FLYOUT_HEADER_TITLE_TEST_ID, } from './test_ids'; import { HeaderTitle } from './header_title'; @@ -80,6 +81,36 @@ describe('', () => { expect(getByTestId(FLYOUT_HEADER_TITLE_TEST_ID)).toHaveTextContent('test'); }); + it('should render share button in the title if document is an alert', () => { + const contextValue = { + dataFormattedForFieldBrowser: [ + { + category: 'kibana', + field: 'kibana.alert.rule.uuid', + values: ['123'], + originalValue: ['123'], + isObjectArray: false, + }, + { + category: 'kibana', + field: 'kibana.alert.url', + values: ['http://kibana.url/alert/id'], + originalValue: ['http://kibana.url/alert/id'], + isObjectArray: false, + }, + ], + getFieldsData: () => [], + } as unknown as RightPanelContext; + + const { getByTestId } = render( + + + + ); + + expect(getByTestId(FLYOUT_HEADER_SHARE_BUTTON_TEST_ID)).toBeInTheDocument(); + }); + it('should render default document detail title if document is not an alert', () => { const contextValue = { dataFormattedForFieldBrowser: [ diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx index 7fbd9145eb967..69a6a873a8202 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/header_title.tsx @@ -16,20 +16,28 @@ import { useBasicDataFromDetailsData } from '../../../timelines/components/side_ import { useRightPanelContext } from '../context'; import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; import { FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids'; +import { ShareButton } from './share_button'; /** * Document details flyout right section header */ export const HeaderTitle: FC = memo(() => { const { dataFormattedForFieldBrowser } = useRightPanelContext(); - const { isAlert, ruleName, timestamp } = useBasicDataFromDetailsData( + const { isAlert, ruleName, timestamp, alertUrl } = useBasicDataFromDetailsData( dataFormattedForFieldBrowser ); return ( <> -

{isAlert && !isEmpty(ruleName) ? ruleName : DOCUMENT_DETAILS}

+ + +

{isAlert && !isEmpty(ruleName) ? ruleName : DOCUMENT_DETAILS}

+
+ + {isAlert && alertUrl && } + +
{timestamp && } diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx index eaae42100ded3..149547c79b14d 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx @@ -15,6 +15,11 @@ import { HIGHLIGHTED_FIELDS_TITLE } from './translations'; import { useRightPanelContext } from '../context'; import { RightPanelKey, RightPanelTableTabPath } from '..'; +/** + * Component that displays the highlighted fields in the right panel under the Investigation section. + * It leverages the existing {@link AlertSummaryView} component. + * // TODO will require improvements https://github.com/elastic/security-team/issues/6428 + */ export const HighlightedFields: FC = () => { const { openRightPanel } = useExpandableFlyoutContext(); const { eventId, indexName, dataFormattedForFieldBrowser, browserFields, scopeId } = @@ -50,7 +55,7 @@ export const HighlightedFields: FC = () => { eventId={eventId} browserFields={browserFields} isDraggable={false} - scopeId={'global'} + scopeId={scopeId} title={''} isReadOnly={false} // TODO: set properly goToTable={goToTableTab} diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.stories.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.stories.tsx deleted file mode 100644 index 953edc6d57f99..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.stories.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { Story } from '@storybook/react'; -import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; -import { InsightsSection } from './insights_section'; -import { RightPanelContext } from '../context'; - -const flyoutContextValue = { - openLeftPanel: () => window.alert('openLeftPanel'), -} as unknown as ExpandableFlyoutContext; -const panelContextValue = { - getFieldsData: () => ({ - host: { - name: 'hostName', - }, - user: { - name: 'userName', - }, - }), -} as unknown as RightPanelContext; - -export default { - component: InsightsSection, - title: 'Flyout/InsightsSection', -}; - -export const Expand: Story = () => { - return ( - - - - - - ); -}; - -export const Collapse: Story = () => { - return ( - - - - - - ); -}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx index e70848fb2d5df..7e78e9f121a12 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_section.tsx @@ -6,8 +6,9 @@ */ import React from 'react'; -import { ThreatIntelligenceOverview } from './threat_intelligence_overview'; import { CorrelationsOverview } from './correlations_overview'; +import { PrevalenceOverview } from './prevalence_overview'; +import { ThreatIntelligenceOverview } from './threat_intelligence_overview'; import { INSIGHTS_TEST_ID } from './test_ids'; import { INSIGHTS_TITLE } from './translations'; import { EntitiesOverview } from './entities_overview'; @@ -29,6 +30,7 @@ export const InsightsSection: React.FC = ({ expanded = fal + ); }; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_subsection.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_subsection.tsx index 4b5c1a541e316..5993d2d7555c3 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_subsection.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_subsection.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSpacer, EuiTitle } from '@elastic/eui'; -export interface InsightsSectionProps { +export interface InsightsSubSectionProps { /** * Renders a loading spinner if true */ @@ -35,16 +35,15 @@ export interface InsightsSectionProps { * Presentational component to handle loading and error in the subsections of the Insights section. * Should be used for Entities, Threat Intelligence, Prevalence, Correlations and Results */ -export const InsightsSubSection: React.FC = ({ +export const InsightsSubSection: React.FC = ({ loading = false, error = false, title, 'data-test-subj': dataTestSubj, children, }) => { + // showing the loading in this component as well as in SummaryPanel because we're hiding the entire section if no data const loadingDataTestSubj = `${dataTestSubj}Loading`; - // showing the loading in this component instead of SummaryPanel because we're hiding the entire section if no data - if (loading) { return ( diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.stories.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.stories.tsx deleted file mode 100644 index 5637d3c036860..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.stories.tsx +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { Story } from '@storybook/react'; -import { css } from '@emotion/react'; -import type { InsightsSummaryPanelData } from './insights_summary_panel'; -import { InsightsSummaryPanel } from './insights_summary_panel'; - -export default { - component: InsightsSummaryPanel, - title: 'Flyout/InsightsSummaryPanel', -}; - -export const Default: Story = () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 1, - text: 'this is a test for red', - color: 'rgb(189,39,30)', - }, - { - icon: 'warning', - value: 2, - text: 'this is test for orange', - color: 'rgb(255,126,98)', - }, - { - icon: 'warning', - value: 3, - text: 'this is test for yellow', - color: 'rgb(241,216,11)', - }, - ]; - - return ( -
- -
- ); -}; - -export const InvalidColor: Story = () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 1, - text: 'this is a test for an invalid color (abc)', - color: 'abc', - }, - ]; - - return ( -
- -
- ); -}; - -export const NoColor: Story = () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 1, - text: 'this is a test for red', - }, - { - icon: 'warning', - value: 2, - text: 'this is test for orange', - }, - { - icon: 'warning', - value: 3, - text: 'this is test for yellow', - }, - ]; - - return ( -
- -
- ); -}; - -export const LongText: Story = () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 1, - text: 'this is an extremely long text to verify it is properly cut off and and we show three dots at the end', - color: 'abc', - }, - ]; - - return ( -
- -
- ); -}; -export const LongNumber: Story = () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 160000, - text: 'this is an extremely long value to verify it is properly cut off and and we show three dots at the end', - color: 'abc', - }, - ]; - - return ( -
- -
- ); -}; - -export const NoData: Story = () => { - const data: InsightsSummaryPanelData[] = []; - - return ( -
- -
- ); -}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.test.tsx deleted file mode 100644 index a3a452c48aaa6..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.test.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { render } from '@testing-library/react'; -import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; -import type { InsightsSummaryPanelData } from './insights_summary_panel'; -import { InsightsSummaryPanel } from './insights_summary_panel'; - -const TEST_ID = 'testid'; - -describe('', () => { - it('should render by default', () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 1, - text: 'this is a test for red', - color: 'rgb(189,39,30)', - }, - ]; - - const { getByTestId } = render( - - - - ); - - const iconTestId = `${TEST_ID}Icon0`; - const valueTestId = `${TEST_ID}Value0`; - const colorTestId = `${TEST_ID}Color0`; - expect(getByTestId(iconTestId)).toBeInTheDocument(); - expect(getByTestId(valueTestId)).toHaveTextContent('1 this is a test for red'); - expect(getByTestId(colorTestId)).toBeInTheDocument(); - }); - - it('should only render null when data is null', () => { - const data = null as unknown as InsightsSummaryPanelData[]; - - const { container } = render(); - - expect(container).toBeEmptyDOMElement(); - }); - - it('should handle big number in a compact notation', () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 160000, - text: 'this is a test for red', - color: 'rgb(189,39,30)', - }, - ]; - - const { getByTestId } = render( - - - - ); - - const valueTestId = `${TEST_ID}Value0`; - expect(getByTestId(valueTestId)).toHaveTextContent('160k this is a test for red'); - }); - - it(`should not show the colored dot if color isn't provided`, () => { - const data: InsightsSummaryPanelData[] = [ - { - icon: 'image', - value: 160000, - text: 'this is a test for no color', - }, - ]; - - const { queryByTestId } = render( - - - - ); - - expect(queryByTestId(`${TEST_ID}Color`)).not.toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.tsx deleted file mode 100644 index 306eaa101b804..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_panel.tsx +++ /dev/null @@ -1,106 +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 { VFC } from 'react'; -import React from 'react'; -import { css } from '@emotion/react'; -import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiPanel } from '@elastic/eui'; -import { FormattedCount } from '../../../common/components/formatted_number'; - -export interface InsightsSummaryPanelData { - /** - * Icon to display on the left side of each row - */ - icon: string; - /** - * Number of results/entries found - */ - value: number; - /** - * Text corresponding of the number of results/entries - */ - text: string; - /** - * Optional parameter for now, will be used to display a dot on the right side - * (corresponding to some sort of severity?) - */ - color?: string; // TODO remove optional when we have guidance on what the colors will actually be -} - -export interface InsightsSummaryPanelProps { - /** - * Array of data to display in each row - */ - data: InsightsSummaryPanelData[]; - /** - * Prefix data-test-subj because this component will be used in multiple places - */ - ['data-test-subj']?: string; -} - -/** - * Panel showing summary information as an icon, a count and text as well as a severity colored dot. - * Should be used for Entities, Threat Intelligence, Prevalence, Correlations and Results components under the Insights section. - * The colored dot is currently optional but will ultimately be mandatory (waiting on PM and UIUX). - */ -export const InsightsSummaryPanel: VFC = ({ - data, - 'data-test-subj': dataTestSubj, -}) => { - if (!data || data.length === 0) { - return null; - } - - const iconDataTestSubj = `${dataTestSubj}Icon`; - const valueDataTestSubj = `${dataTestSubj}Value`; - const colorDataTestSubj = `${dataTestSubj}Color`; - - return ( - - - {data.map((row, index) => ( - - - - - - {row.text} - - {row.color && ( - - - - )} - - ))} - - - ); -}; - -InsightsSummaryPanel.displayName = 'InsightsSummaryPanel'; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.stories.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.stories.tsx new file mode 100644 index 0000000000000..95dd28dd73f0f --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.stories.tsx @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { Story } from '@storybook/react'; +import { css } from '@emotion/react'; +import { InsightsSummaryRow } from './insights_summary_row'; + +export default { + component: InsightsSummaryRow, + title: 'Flyout/InsightsSummaryRow', +}; + +export const Default: Story = () => ( +
+ +
+); + +export const InvalidColor: Story = () => ( +
+ +
+); + +export const NoColor: Story = () => ( +
+ +
+); + +export const LongText: Story = () => ( +
+ +
+); + +export const LongNumber: Story = () => ( +
+ +
+); + +export const Loading: Story = () => ( +
+ +
+); + +export const Error: Story = () => ( +
+ +
+); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.test.tsx new file mode 100644 index 0000000000000..3e10e83332a97 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.test.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import { InsightsSummaryRow } from './insights_summary_row'; + +const testId = 'test'; +const iconTestId = `${testId}Icon`; +const valueTestId = `${testId}Value`; +const colorTestId = `${testId}Color`; +const loadingTestId = `${testId}Loading`; + +describe('', () => { + it('should render by default', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId(iconTestId)).toBeInTheDocument(); + expect(getByTestId(valueTestId)).toHaveTextContent('1 this is a test for red'); + expect(getByTestId(colorTestId)).toBeInTheDocument(); + }); + + it('should render loading skeletton if loading is true', () => { + const { getByTestId } = render( + + ); + + expect(getByTestId(loadingTestId)).toBeInTheDocument(); + }); + + it('should only render null when error is true', () => { + const { container } = render(); + + expect(container).toBeEmptyDOMElement(); + }); + + it('should handle big number in a compact notation', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId(valueTestId)).toHaveTextContent('160k this is a test for red'); + }); + + it(`should not show the colored dot if color isn't provided`, () => { + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId(colorTestId)).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx new file mode 100644 index 0000000000000..4e7df1aa6a5c5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/insights_summary_row.tsx @@ -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 type { VFC } from 'react'; +import React from 'react'; +import { css } from '@emotion/react'; +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiHealth, EuiSkeletonText } from '@elastic/eui'; +import { FormattedCount } from '../../../common/components/formatted_number'; + +export interface InsightsSummaryRowProps { + /** + * Optional parameter used to display a loading spinner + */ + loading?: boolean; + /** + * Optional parameter used to display a null component + */ + error?: boolean; + /** + * Icon to display on the left side of each row + */ + icon: string; + /** + * Number of results/entries found + */ + value?: number; + /** + * Text corresponding of the number of results/entries + */ + text: string; + /** + * Optional parameter for now, will be used to display a dot on the right side + * (corresponding to some sort of severity?) + */ + color?: string; // TODO remove optional when we have guidance on what the colors will actually be + /** + * Prefix data-test-subj because this component will be used in multiple places + */ + ['data-test-subj']?: string; +} + +/** + * Panel showing summary information as an icon, a count and text as well as a severity colored dot. + * Should be used for Entities, Threat Intelligence, Prevalence, Correlations and Results components under the Insights section. + * The colored dot is currently optional but will ultimately be mandatory (waiting on PM and UIUX). + */ +export const InsightsSummaryRow: VFC = ({ + loading = false, + error = false, + icon, + value, + text, + color, + 'data-test-subj': dataTestSubj, +}) => { + const loadingDataTestSubj = `${dataTestSubj}Loading`; + if (loading) { + return ( + + ); + } + + if (error) { + return null; + } + + const iconDataTestSubj = `${dataTestSubj}Icon`; + const valueDataTestSubj = `${dataTestSubj}Value`; + const colorDataTestSubj = `${dataTestSubj}Color`; + + return ( + + + + + + {value && } {text} + + {color && ( + + + + )} + + ); +}; + +InsightsSummaryRow.displayName = 'InsightsSummaryRow'; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.stories.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.stories.tsx deleted file mode 100644 index e7e1bc59b579a..0000000000000 --- a/x-pack/plugins/security_solution/public/flyout/right/components/investigation_section.stories.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import type { Story } from '@storybook/react'; -import { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; -import { InvestigationSection } from './investigation_section'; -import { mockDataFormattedForFieldBrowser, mockSearchHit } from '../mocks/mock_context'; -import { RightPanelContext } from '../context'; - -const flyoutContextValue = {} as unknown as ExpandableFlyoutContext; -const panelContextValue = { - dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, - searchHit: mockSearchHit, -} as unknown as RightPanelContext; - -export default { - component: InvestigationSection, - title: 'Flyout/InvestigationSection', -}; - -export const Expand: Story = () => { - return ( - - - - - - ); -}; - -export const Collapse: Story = () => { - return ( - - - - - - ); -}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.test.tsx new file mode 100644 index 0000000000000..c606fb2cd41c6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.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 { ExpandableFlyoutContext } from '@kbn/expandable-flyout/src/context'; +import { render } from '@testing-library/react'; +import { TestProviders } from '../../../common/mock'; +import { RightPanelContext } from '../context'; +import { INSIGHTS_PREVALENCE_TEST_ID } from './test_ids'; +import { LeftPanelInsightsTabPath, LeftPanelKey } from '../../left'; +import React from 'react'; +import { PrevalenceOverview } from './prevalence_overview'; +import { usePrevalence } from '../hooks/use_prevalence'; +import { PrevalenceOverviewRow } from './prevalence_overview_row'; +import { useFetchUniqueHostsWithFieldPair } from '../hooks/use_fetch_unique_hosts_with_field_value_pair'; +import { useFetchUniqueHosts } from '../hooks/use_fetch_unique_hosts'; + +jest.mock('../hooks/use_fetch_unique_hosts_with_field_value_pair'); +jest.mock('../hooks/use_fetch_unique_hosts'); +jest.mock('../hooks/use_prevalence'); + +const field = 'field'; +const values = ['value']; +const scopeId = 'scopeId'; +const callbackIfNull = jest.fn(); + +const panelContextValue = { + eventId: 'event id', + indexName: 'indexName', + browserFields: {}, + dataFormattedForFieldBrowser: [], +} as unknown as RightPanelContext; + +const renderPrevalenceOverview = (contextValue: RightPanelContext) => ( + + + + + +); + +describe('', () => { + it('should render PrevalenceOverviewRows', () => { + (useFetchUniqueHostsWithFieldPair as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 1, + }); + (useFetchUniqueHosts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 10, + }); + (usePrevalence as jest.Mock).mockReturnValue({ + empty: false, + prevalenceRows: [ + , + ], + }); + + const titleDataTestSubj = `${INSIGHTS_PREVALENCE_TEST_ID}Title`; + const iconDataTestSubj = 'testIcon'; + const valueDataTestSubj = 'testValue'; + + const { getByTestId } = render(renderPrevalenceOverview(panelContextValue)); + + expect(getByTestId(titleDataTestSubj)).toBeInTheDocument(); + expect(getByTestId(iconDataTestSubj)).toBeInTheDocument(); + expect(getByTestId(valueDataTestSubj)).toBeInTheDocument(); + }); + + it('should render null if no rows are rendered', () => { + (usePrevalence as jest.Mock).mockReturnValue({ + empty: true, + prevalenceRows: [], + }); + + const { container } = render(renderPrevalenceOverview(panelContextValue)); + + expect(container).toBeEmptyDOMElement(); + }); + + it('should navigate to left section Insights tab when clicking on button', () => { + (useFetchUniqueHostsWithFieldPair as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 1, + }); + (useFetchUniqueHosts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 10, + }); + (usePrevalence as jest.Mock).mockReturnValue({ + empty: false, + prevalenceRows: [ + , + ], + }); + const flyoutContextValue = { + openLeftPanel: jest.fn(), + } as unknown as ExpandableFlyoutContext; + + const { getByTestId } = render( + + + + + + + + ); + + getByTestId(`${INSIGHTS_PREVALENCE_TEST_ID}ViewAllButton`).click(); + expect(flyoutContextValue.openLeftPanel).toHaveBeenCalledWith({ + id: LeftPanelKey, + path: LeftPanelInsightsTabPath, + params: { + id: panelContextValue.eventId, + indexName: panelContextValue.indexName, + }, + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.tsx new file mode 100644 index 0000000000000..a0480468d328b --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FC } from 'react'; +import React, { useCallback } from 'react'; +import { EuiButtonEmpty, EuiFlexGroup, EuiPanel } from '@elastic/eui'; +import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { usePrevalence } from '../hooks/use_prevalence'; +import { INSIGHTS_PREVALENCE_TEST_ID } from './test_ids'; +import { InsightsSubSection } from './insights_subsection'; +import { useRightPanelContext } from '../context'; +import { PREVALENCE_TEXT, PREVALENCE_TITLE, VIEW_ALL } from './translations'; +import { LeftPanelKey, LeftPanelInsightsTabPath } from '../../left'; + +/** + * Prevalence section under Insights section, overview tab. + * The component fetches the necessary data, then pass it down to the InsightsSubSection component for loading and error state, + * and the SummaryPanel component for data rendering. + */ +export const PrevalenceOverview: FC = () => { + const { eventId, indexName, browserFields, dataFormattedForFieldBrowser, scopeId } = + useRightPanelContext(); + const { openLeftPanel } = useExpandableFlyoutContext(); + + const goToCorrelationsTab = useCallback(() => { + openLeftPanel({ + id: LeftPanelKey, + path: LeftPanelInsightsTabPath, + params: { + id: eventId, + indexName, + }, + }); + }, [eventId, openLeftPanel, indexName]); + + const { empty, prevalenceRows } = usePrevalence({ + eventId, + browserFields, + dataFormattedForFieldBrowser, + scopeId, + }); + + if (!eventId || !browserFields || !dataFormattedForFieldBrowser || empty) { + return null; + } + + return ( + + + + {prevalenceRows} + + + + {VIEW_ALL(PREVALENCE_TEXT)} + + + ); +}; + +PrevalenceOverview.displayName = 'PrevalenceOverview'; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview_row.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview_row.test.tsx new file mode 100644 index 0000000000000..6df3bada6e8e9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview_row.test.tsx @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 } from '@testing-library/react'; +import React from 'react'; +import { PrevalenceOverviewRow } from './prevalence_overview_row'; +import { useFetchUniqueHostsWithFieldPair } from '../hooks/use_fetch_unique_hosts_with_field_value_pair'; +import { useFetchUniqueHosts } from '../hooks/use_fetch_unique_hosts'; + +jest.mock('../hooks/use_fetch_unique_hosts_with_field_value_pair'); +jest.mock('../hooks/use_fetch_unique_hosts'); + +const field = 'field'; +const values = ['values']; +const scopeId = 'scopeId'; +const dataTestSubj = 'test'; +const iconDataTestSubj = 'testIcon'; +const valueDataTestSubj = 'testValue'; +const colorDataTestSubj = 'testColor'; +const loadingDataTestSubj = 'testLoading'; + +describe('', () => { + it('should display row if prevalence is below or equal threshold', () => { + (useFetchUniqueHostsWithFieldPair as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 1, + }); + (useFetchUniqueHosts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 10, + }); + + const { getByTestId, getAllByText, queryByTestId } = render( + {}} + data-test-subj={dataTestSubj} + /> + ); + + expect(getByTestId(iconDataTestSubj)).toBeInTheDocument(); + expect(getByTestId(valueDataTestSubj)).toBeInTheDocument(); + expect(getAllByText(`${field}, ${values} is uncommon`)).toHaveLength(1); + expect(queryByTestId(colorDataTestSubj)).not.toBeInTheDocument(); + }); + + it('should not display row if prevalence is higher than threshold', () => { + (useFetchUniqueHostsWithFieldPair as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 1, + }); + (useFetchUniqueHosts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 2, + }); + const callbackIfNull = jest.fn(); + + const { queryAllByAltText } = render( + + ); + + expect(queryAllByAltText('is uncommon')).toHaveLength(0); + expect(callbackIfNull).toHaveBeenCalled(); + }); + + it('should not display row if error retrieving data', () => { + (useFetchUniqueHostsWithFieldPair as jest.Mock).mockReturnValue({ + loading: false, + error: true, + count: 0, + }); + (useFetchUniqueHosts as jest.Mock).mockReturnValue({ + loading: false, + error: true, + count: 0, + }); + const callbackIfNull = jest.fn(); + + const { queryAllByAltText } = render( + + ); + + expect(queryAllByAltText('is uncommon')).toHaveLength(0); + expect(callbackIfNull).toHaveBeenCalled(); + }); + + it('should display loading', () => { + (useFetchUniqueHostsWithFieldPair as jest.Mock).mockReturnValue({ + loading: true, + error: false, + count: 1, + }); + (useFetchUniqueHosts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + count: 10, + }); + + const { getByTestId } = render( + {}} + data-test-subj={dataTestSubj} + /> + ); + + expect(getByTestId(loadingDataTestSubj)).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview_row.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview_row.tsx new file mode 100644 index 0000000000000..3a705ee02ef24 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/prevalence_overview_row.tsx @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { VFC } from 'react'; +import React from 'react'; +import { PREVALENCE_ROW_UNCOMMON } from './translations'; +import { useFetchUniqueHostsWithFieldPair } from '../hooks/use_fetch_unique_hosts_with_field_value_pair'; +import { useFetchUniqueHosts } from '../hooks/use_fetch_unique_hosts'; +import { InsightsSummaryRow } from './insights_summary_row'; +import { TimelineId } from '../../../../common/types'; + +const PERCENTAGE_THRESHOLD = 0.1; // we show the prevalence if its value is below 10% + +export interface PrevalenceOverviewRowProps { + /** + * Highlighted field + */ + field: string; + /** + * Highlighted field value + */ + values: string[]; + /** + * Maintain backwards compatibility // TODO remove when possible + */ + scopeId: string; + /** + * This is a solution to allow the parent component to NOT render if all its row children are null + */ + callbackIfNull: () => void; + /** + * Prefix data-test-subj because this component will be used in multiple places + */ + ['data-test-subj']?: string; +} + +/** + * Retrieves the unique hosts for the field/value pair as well as the total number of unique hosts, + * calculate the prevalence. If the prevalence is higher than 1, use the callback method to let the parent know + * the row will render null. + */ +export const PrevalenceOverviewRow: VFC = ({ + field, + values, + scopeId, + callbackIfNull, + 'data-test-subj': dataTestSubj, +}) => { + const isActiveTimelines = scopeId === TimelineId.active; + + const { + loading: hostsLoading, + error: hostsError, + count: hostsCount, + } = useFetchUniqueHostsWithFieldPair({ + field, + values, + isActiveTimelines, + }); + + const { + loading: uniqueHostsLoading, + error: uniqueHostsError, + count: uniqueHostsCount, + } = useFetchUniqueHosts(); + + // prevalence is number of host(s) where the field/value pair was found divided by the total number of hosts in the environment + const prevalence = hostsCount / uniqueHostsCount; + const loading = hostsLoading || uniqueHostsLoading; + const error = hostsError || uniqueHostsError; + const text = `${field}, ${values} ${PREVALENCE_ROW_UNCOMMON}`; + + // we do not want to render the row is the prevalence is Infinite, 0 or above the decided threshold + const shouldNotRender = + isFinite(prevalence) && (prevalence === 0 || prevalence > PERCENTAGE_THRESHOLD); + + // callback to let the parent component aware of which rows are null (so it can hide itself completely if all are null) + if (!loading && (error || shouldNotRender)) { + callbackIfNull(); + } + + return ( + + ); +}; + +PrevalenceOverviewRow.displayName = 'PrevalenceOverviewRow'; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/share_button.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.test.tsx new file mode 100644 index 0000000000000..891bdfacbf171 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.test.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 { render, screen, fireEvent } from '@testing-library/react'; +import { copyToClipboard } from '@elastic/eui'; +import { ShareButton } from './share_button'; +import React from 'react'; +import { FLYOUT_URL_PARAM } from '../../url/use_sync_flyout_state_with_url'; +import { FLYOUT_HEADER_SHARE_BUTTON_TEST_ID } from './test_ids'; + +jest.mock('@elastic/eui', () => ({ + ...jest.requireActual('@elastic/eui'), + copyToClipboard: jest.fn(), + EuiCopy: jest.fn(({ children: functionAsChild }) => functionAsChild(jest.fn())), +})); + +describe('ShareButton', () => { + const alertUrl = 'https://example.com/alert'; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders the share button', () => { + render(); + + expect(screen.getByTestId(FLYOUT_HEADER_SHARE_BUTTON_TEST_ID)).toBeInTheDocument(); + }); + + it('copies the alert URL to clipboard', () => { + const syncedFlyoutState = 'flyoutState'; + const query = `?${FLYOUT_URL_PARAM}=${syncedFlyoutState}`; + + Object.defineProperty(window, 'location', { + value: { + search: query, + }, + }); + + render(); + + fireEvent.click(screen.getByTestId(FLYOUT_HEADER_SHARE_BUTTON_TEST_ID)); + + expect(copyToClipboard).toHaveBeenCalledWith( + `${alertUrl}&${FLYOUT_URL_PARAM}=${syncedFlyoutState}` + ); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/share_button.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.tsx new file mode 100644 index 0000000000000..18a8d71459d26 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/components/share_button.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { copyToClipboard, EuiButtonEmpty, EuiCopy } from '@elastic/eui'; +import type { FC } from 'react'; +import React from 'react'; +import { FLYOUT_URL_PARAM } from '../../url/use_sync_flyout_state_with_url'; +import { FLYOUT_HEADER_SHARE_BUTTON_TEST_ID } from './test_ids'; +import { SHARE } from './translations'; + +interface ShareButtonProps { + /** + * Url retrieved from the kibana.alert.url field of the document + */ + alertUrl: string; +} + +/** + * Puts alertUrl to user's clipboard. If current query string contains synced flyout state, + * it will be appended to the base alertUrl + */ +export const ShareButton: FC = ({ alertUrl }) => { + return ( + + {(copy) => ( + { + // NOTE: currently, it is not possible to have textToCopy computed dynamically. + // so, we are calling copy() here to trigger the ui tooltip, and then override the link manually + copy(); + const query = new URLSearchParams(window.location.search); + const alertDetailsLink = `${alertUrl}&${FLYOUT_URL_PARAM}=${query.get( + FLYOUT_URL_PARAM + )}`; + copyToClipboard(alertDetailsLink); + }} + iconType="share" + data-test-subj={FLYOUT_HEADER_SHARE_BUTTON_TEST_ID} + > + {SHARE} + + )} + + ); +}; + +ShareButton.displayName = 'ShareButton'; diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts index 8cb0b9d0e0ff7..59b6f09608d65 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/components/test_ids.ts @@ -21,6 +21,8 @@ export const FLYOUT_HEADER_RISK_SCORE_TITLE_TEST_ID = 'securitySolutionAlertDetailsFlyoutHeaderRiskScoreTitle'; export const FLYOUT_HEADER_RISK_SCORE_VALUE_TEST_ID = 'securitySolutionAlertDetailsFlyoutHeaderRiskScoreValue'; +export const FLYOUT_HEADER_SHARE_BUTTON_TEST_ID = + 'securitySolutionAlertDetailsFlyoutHeaderShareButton'; /* Description section */ @@ -112,7 +114,16 @@ export const INSIGHTS_CORRELATIONS_VIEW_ALL_BUTTON_TEST_ID = `${INSIGHTS_CORRELA export const INSIGHTS_CORRELATIONS_LOADING_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}Loading`; export const INSIGHTS_CORRELATIONS_VALUE_TEST_ID = `${INSIGHTS_CORRELATIONS_TEST_ID}Value`; -/* Visualizations section*/ +/* Insights Prevalence */ + +export const INSIGHTS_PREVALENCE_TEST_ID = + 'securitySolutionDocumentDetailsFlyoutInsightsPrevalence'; +export const INSIGHTS_PREVALENCE_TITLE_TEST_ID = `${INSIGHTS_PREVALENCE_TEST_ID}Title`; +export const INSIGHTS_PREVALENCE_CONTENT_TEST_ID = `${INSIGHTS_PREVALENCE_TEST_ID}Content`; +export const INSIGHTS_PREVALENCE_VIEW_ALL_BUTTON_TEST_ID = `${INSIGHTS_PREVALENCE_TEST_ID}ViewAllButton`; +export const INSIGHTS_PREVALENCE_VALUE_TEST_ID = `${INSIGHTS_PREVALENCE_TEST_ID}Value`; + +/* Visualizations section */ export const VISUALIZATIONS_SECTION_TEST_ID = 'securitySolutionDocumentDetailsVisualizationsTitle'; export const VISUALIZATIONS_SECTION_HEADER_TEST_ID = diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx index ecf17f2c7e822..ba954d0960913 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.test.tsx @@ -112,9 +112,9 @@ describe('', () => { loading: true, }); - const { getByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); + const { getAllByTestId } = render(renderThreatIntelligenceOverview(panelContextValue)); - expect(getByTestId(INSIGHTS_THREAT_INTELLIGENCE_LOADING_TEST_ID)).toBeInTheDocument(); + expect(getAllByTestId(INSIGHTS_THREAT_INTELLIGENCE_LOADING_TEST_ID)).toHaveLength(2); }); it('should render null when eventId is null', () => { @@ -146,22 +146,6 @@ describe('', () => { expect(container).toBeEmptyDOMElement(); }); - it('should render null when no enrichment found is null', () => { - (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ - loading: false, - threatMatchesCount: 0, - threatEnrichmentsCount: 0, - }); - const contextValue = { - ...panelContextValue, - dataFormattedForFieldBrowser: [], - } as unknown as RightPanelContext; - - const { container } = render(renderThreatIntelligenceOverview(contextValue)); - - expect(container).toBeEmptyDOMElement(); - }); - it('should navigate to left section Insights tab when clicking on button', () => { (useFetchThreatIntelligence as jest.Mock).mockReturnValue({ loading: false, diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx index 2daa0157c9ad0..0a711eacce604 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/threat_intelligence_overview.tsx @@ -5,13 +5,13 @@ * 2.0. */ +import type { FC } from 'react'; import React, { useCallback } from 'react'; -import { EuiButtonEmpty } from '@elastic/eui'; +import { EuiButtonEmpty, EuiFlexGroup, EuiPanel } from '@elastic/eui'; import { useExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { InsightsSubSection } from './insights_subsection'; -import type { InsightsSummaryPanelData } from './insights_summary_panel'; -import { InsightsSummaryPanel } from './insights_summary_panel'; +import { InsightsSummaryRow } from './insights_summary_row'; import { useRightPanelContext } from '../context'; import { INSIGHTS_THREAT_INTELLIGENCE_TEST_ID } from './test_ids'; import { @@ -30,7 +30,7 @@ import { LeftPanelKey, LeftPanelInsightsTabPath } from '../../left'; * The component fetches the necessary data, then pass it down to the InsightsSubSection component for loading and error state, * and the SummaryPanel component for data rendering. */ -export const ThreatIntelligenceOverview: React.FC = () => { +export const ThreatIntelligenceOverview: FC = () => { const { eventId, indexName, dataFormattedForFieldBrowser } = useRightPanelContext(); const { openLeftPanel } = useExpandableFlyoutContext(); @@ -45,36 +45,43 @@ export const ThreatIntelligenceOverview: React.FC = () => { }); }, [eventId, openLeftPanel, indexName]); - const { loading, threatMatchesCount, threatEnrichmentsCount } = useFetchThreatIntelligence({ + const { + loading: threatIntelLoading, + error: threatIntelError, + threatMatchesCount, + threatEnrichmentsCount, + } = useFetchThreatIntelligence({ dataFormattedForFieldBrowser, }); - const data: InsightsSummaryPanelData[] = [ - { - icon: 'warning', - value: threatMatchesCount, - text: threatMatchesCount <= 1 ? THREAT_MATCH_DETECTED : THREAT_MATCHES_DETECTED, - }, - { - icon: 'warning', - value: threatEnrichmentsCount, - text: threatMatchesCount <= 1 ? THREAT_ENRICHMENT : THREAT_ENRICHMENTS, - }, - ]; - - const error: boolean = - !eventId || - !dataFormattedForFieldBrowser || - (threatMatchesCount === 0 && threatEnrichmentsCount === 0); + const error: boolean = !eventId || !dataFormattedForFieldBrowser || threatIntelError; return ( - + + + + + + i18n.translate('xpack.securitySolution.flyout.documentDetails.overviewTab.viewAllButton', { values: { text }, @@ -260,6 +279,10 @@ export const ANALYZER_PREVIEW_TEXT = i18n.translate( } ); +export const SHARE = i18n.translate('xpack.securitySolution.flyout.documentDetails.share', { + defaultMessage: 'Share Alert', +}); + export const INVESTIGATION_GUIDE_TITLE = i18n.translate( 'xpack.securitySolution.flyout.documentDetails.investigationGuideText', { diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_correlations.ts b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_correlations.ts index 551a10716dd2b..b60fe2836c5b7 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_correlations.ts +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_correlations.ts @@ -8,7 +8,6 @@ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { useFetchRelatedAlertsBySameSourceEvent } from './use_fetch_related_alerts_by_same_source_event'; -import type { InsightsSummaryPanelData } from '../components/insights_summary_panel'; import { useShowRelatedCases } from './use_show_related_cases'; import { useFetchRelatedCases } from './use_fetch_related_cases'; import { @@ -27,6 +26,12 @@ import { useShowRelatedAlertsBySameSourceEvent } from './use_show_related_alerts import { useShowRelatedAlertsBySession } from './use_show_related_alerts_by_session'; import { useFetchRelatedAlertsBySession } from './use_fetch_related_alerts_by_session'; +interface InsightsSummaryData { + icon: string; + value: number; + text: string; +} + export interface UseCorrelationsParams { /** * Id of the document @@ -57,7 +62,7 @@ export interface UseCorrelationsResult { /** * Data ready to be consumed by the InsightsSummaryPanel component */ - data: InsightsSummaryPanelData[]; + data: InsightsSummaryData[]; /** * Data length */ @@ -74,7 +79,7 @@ export const useCorrelations = ({ dataFormattedForFieldBrowser, scopeId, }: UseCorrelationsParams): UseCorrelationsResult => { - const data: InsightsSummaryPanelData[] = []; + const data: InsightsSummaryData[] = []; // cases const showCases = useShowRelatedCases(); diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts.test.tsx new file mode 100644 index 0000000000000..6d6bc6806a8c5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts.test.tsx @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; +import type { RenderHookResult } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react-hooks'; +import type { UseUniqueValuesValue } from './use_fetch_unique_hosts'; +import { useFetchUniqueHosts } from './use_fetch_unique_hosts'; +import { useKibana } from '../../../common/lib/kibana'; + +jest.mock('@tanstack/react-query'); +jest.mock('../../../common/lib/kibana'); + +describe('useFetchUniqueHosts', () => { + let hookResult: RenderHookResult; + + (useKibana as jest.Mock).mockReturnValue({ + services: { + data: { search: jest.fn() }, + }, + }); + + it('should return loading true while data is being fetched', () => { + (useQuery as jest.Mock).mockReturnValue({ + isLoading: true, + isError: false, + data: 0, + }); + + hookResult = renderHook(() => useFetchUniqueHosts()); + + expect(hookResult.result.current.loading).toBeTruthy(); + expect(hookResult.result.current.error).toBeFalsy(); + expect(hookResult.result.current.count).toBe(0); + }); + + it('should return error true when data fetching has errored out', () => { + (useQuery as jest.Mock).mockReturnValue({ + isLoading: false, + isError: true, + data: 0, + }); + + hookResult = renderHook(() => useFetchUniqueHosts()); + + expect(hookResult.result.current.loading).toBeFalsy(); + expect(hookResult.result.current.error).toBeTruthy(); + expect(hookResult.result.current.count).toBe(0); + }); + + it('should return count on success', () => { + (useQuery as jest.Mock).mockReturnValue({ + isLoading: false, + isError: false, + data: 1, + }); + + hookResult = renderHook(() => useFetchUniqueHosts()); + + expect(hookResult.result.current.loading).toBeFalsy(); + expect(hookResult.result.current.error).toBeFalsy(); + expect(hookResult.result.current.count).toBe(1); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts.ts b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts.ts new file mode 100644 index 0000000000000..3f3ccbc21fb07 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; +import type { IEsSearchRequest } from '@kbn/data-plugin/common'; +import { createFetchAggregatedData } from '../utils/fetch_aggregated_data'; +import { useKibana } from '../../../common/lib/kibana'; + +const AGG_KEY = 'uniqueHosts'; +const QUERY_KEY = 'useFetchUniqueHosts'; + +interface RawAggregatedDataResponse { + aggregations: { + [AGG_KEY]: { + buckets: unknown[]; + }; + }; +} + +const searchRequest: IEsSearchRequest = { + params: { + body: { + aggs: { + [AGG_KEY]: { + terms: { + field: 'host.name', + size: 1000, + }, + }, + }, + size: 0, + }, + }, +}; + +export interface UseUniqueValuesValue { + /** + * Returns true if data is being loaded + */ + loading: boolean; + /** + * Returns true if fetching data has errored out + */ + error: boolean; + /** + * Number of unique hosts found in the environment + */ + count: number; +} + +/** + * Hook to retrieve all unique hosts in the environment, using ReactQuery. + * The query uses an aggregation by unique hosts. + */ +export const useFetchUniqueHosts = (): UseUniqueValuesValue => { + const { + services: { + data: { search: searchService }, + }, + } = useKibana(); + + const { data, isLoading, isError } = useQuery( + [QUERY_KEY], + () => + createFetchAggregatedData(searchService, searchRequest, AGG_KEY), + { + select: (res) => res.aggregations[AGG_KEY].buckets.length, + keepPreviousData: true, + } + ); + + return { + loading: isLoading, + error: isError, + count: data || 0, + }; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts_with_field_value_pair.test.ts b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts_with_field_value_pair.test.ts new file mode 100644 index 0000000000000..4c3f2be096040 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts_with_field_value_pair.test.ts @@ -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 { useQuery } from '@tanstack/react-query'; +import type { RenderHookResult } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react-hooks'; +import { useKibana } from '../../../common/lib/kibana'; +import type { + UseFetchUniqueHostWithFieldPairParams, + UseFetchUniqueHostWithFieldPairResult, +} from './use_fetch_unique_hosts_with_field_value_pair'; +import { useFetchUniqueHostsWithFieldPair } from './use_fetch_unique_hosts_with_field_value_pair'; +import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; + +jest.mock('@tanstack/react-query'); +jest.mock('../../../common/lib/kibana'); +jest.mock('../../../common/hooks/use_selector'); +jest.mock('../../../common/containers/use_global_time'); + +const field = 'field'; +const values = ['values']; +const isActiveTimelines = true; + +describe('useFetchUniqueHostsWithFieldPair', () => { + let hookResult: RenderHookResult< + UseFetchUniqueHostWithFieldPairParams, + UseFetchUniqueHostWithFieldPairResult + >; + + (useKibana as jest.Mock).mockReturnValue({ + services: { + data: { search: jest.fn() }, + }, + }); + (useDeepEqualSelector as jest.Mock).mockReturnValue({ to: '', from: '' }); + (useGlobalTime as jest.Mock).mockReturnValue({ to: '', from: '' }); + + it('should return loading true while data is being fetched', async () => { + (useQuery as jest.Mock).mockReturnValue({ + isLoading: true, + isError: false, + data: 0, + }); + + hookResult = renderHook(() => + useFetchUniqueHostsWithFieldPair({ field, values, isActiveTimelines }) + ); + + expect(hookResult.result.current.loading).toBeTruthy(); + expect(hookResult.result.current.error).toBeFalsy(); + expect(hookResult.result.current.count).toBe(0); + }); + + it('should return error true when data fetching has errored out', async () => { + (useQuery as jest.Mock).mockReturnValue({ + isLoading: false, + isError: true, + data: 0, + }); + + hookResult = renderHook(() => + useFetchUniqueHostsWithFieldPair({ field, values, isActiveTimelines }) + ); + + expect(hookResult.result.current.loading).toBeFalsy(); + expect(hookResult.result.current.error).toBeTruthy(); + expect(hookResult.result.current.count).toBe(0); + }); + + it('should return count on success', async () => { + (useQuery as jest.Mock).mockReturnValue({ + isLoading: false, + isError: false, + data: 1, + }); + + hookResult = renderHook(() => + useFetchUniqueHostsWithFieldPair({ field, values, isActiveTimelines }) + ); + + expect(hookResult.result.current.loading).toBeFalsy(); + expect(hookResult.result.current.error).toBeFalsy(); + expect(hookResult.result.current.count).toBe(1); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts_with_field_value_pair.ts b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts_with_field_value_pair.ts new file mode 100644 index 0000000000000..246a22006bb54 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_fetch_unique_hosts_with_field_value_pair.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { buildEsQuery } from '@kbn/es-query'; +import { useQuery } from '@tanstack/react-query'; +import type { IEsSearchRequest } from '@kbn/data-plugin/common'; +import { createFetchAggregatedData } from '../utils/fetch_aggregated_data'; +import { useKibana } from '../../../common/lib/kibana'; +import { inputsSelectors } from '../../../common/store'; +import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; +import { useGlobalTime } from '../../../common/containers/use_global_time'; + +const AGG_KEY = 'hostsWithSameFieldValuePair'; +const QUERY_KEY = 'useFetchUniqueHostsWithFieldPair'; + +interface RawAggregatedDataResponse { + aggregations: { + [AGG_KEY]: { + buckets: unknown[]; + }; + }; +} + +export interface UseFetchUniqueHostWithFieldPairParams { + /** + * Highlighted field + */ + field: string; + /** + * Highlighted field value + */ + values: string[]; + /** + * + */ + isActiveTimelines: boolean; +} + +export interface UseFetchUniqueHostWithFieldPairResult { + /** + * Returns true if data is being loaded + */ + loading: boolean; + /** + * Returns true if fetching data has errored out + */ + error: boolean; + /** + * Number of unique hosts found for the field/value pair + */ + count: number; +} + +/** + * Hook to retrieve all the unique hosts in the environment that have the field/value pair, using ReactQuery. + * The query uses an aggregation by unique hosts. + */ +export const useFetchUniqueHostsWithFieldPair = ({ + field, + values, + isActiveTimelines, +}: UseFetchUniqueHostWithFieldPairParams): UseFetchUniqueHostWithFieldPairResult => { + const { + services: { + data: { search: searchService }, + }, + } = useKibana(); + + const timelineTime = useDeepEqualSelector((state) => + inputsSelectors.timelineTimeRangeSelector(state) + ); + const globalTime = useGlobalTime(); + const { to, from } = isActiveTimelines ? timelineTime : globalTime; + + const searchRequest = buildSearchRequest(field, values, from, to); + + const { data, isLoading, isError } = useQuery( + [QUERY_KEY, field, values], + () => + createFetchAggregatedData(searchService, searchRequest, AGG_KEY), + { + select: (res) => res.aggregations[AGG_KEY].buckets.length, + keepPreviousData: true, + } + ); + + return { + loading: isLoading, + error: isError, + count: data || 0, + }; +}; + +/** + * Build the search request for the field/values pair, for a date range from/to. + * The request contains aggregation by host.name field. + */ +const buildSearchRequest = ( + field: string, + values: string[], + from: string, + to: string +): IEsSearchRequest => { + const query = buildEsQuery( + undefined, + [], + [ + { + query: { + bool: { + filter: [ + { + match: { + [field]: values[0], + }, + }, + { + range: { + '@timestamp': { + gte: from, + lte: to, + }, + }, + }, + ], + }, + }, + meta: {}, + }, + ] + ); + + return { + params: { + body: { + query, + aggs: { + [AGG_KEY]: { + terms: { + field: 'host.name', + size: 1000, + }, + }, + }, + size: 0, + }, + }, + }; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.test.tsx b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.test.tsx new file mode 100644 index 0000000000000..dfbdf3f278ef5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.test.tsx @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getSummaryRows } from '../../../common/components/event_details/get_alert_summary_rows'; +import type { UsePrevalenceResult } from './use_prevalence'; +import { usePrevalence } from './use_prevalence'; +import type { RenderHookResult } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react-hooks'; +import { mockDataFormattedForFieldBrowser } from '../mocks/mock_context'; + +jest.mock('../../../common/components/event_details/get_alert_summary_rows'); + +const eventId = 'eventId'; +const browserFields = null; +const dataFormattedForFieldBrowser = mockDataFormattedForFieldBrowser; +const scopeId = 'scopeId'; + +describe('usePrevalence', () => { + let hookResult: RenderHookResult; + + it('should return 1 row to render', () => { + const mockSummaryRow = { + title: 'test', + description: { + data: { + field: 'field', + }, + values: ['value'], + }, + }; + (getSummaryRows as jest.Mock).mockReturnValue([mockSummaryRow]); + + hookResult = renderHook(() => + usePrevalence({ browserFields, dataFormattedForFieldBrowser, eventId, scopeId }) + ); + + expect(hookResult.result.current.prevalenceRows.length).toEqual(1); + expect(hookResult.result.current.empty).toEqual(false); + }); + + it('should return empty true', () => { + (getSummaryRows as jest.Mock).mockReturnValue([]); + + hookResult = renderHook(() => + usePrevalence({ browserFields, dataFormattedForFieldBrowser, eventId, scopeId }) + ); + + expect(hookResult.result.current.prevalenceRows.length).toEqual(0); + expect(hookResult.result.current.empty).toEqual(true); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.tsx b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.tsx new file mode 100644 index 0000000000000..1e8017b565d29 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/hooks/use_prevalence.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 type { BrowserFields, TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import type { ReactElement } from 'react'; +import React, { useMemo, useState } from 'react'; +import { getSummaryRows } from '../../../common/components/event_details/get_alert_summary_rows'; +import { PrevalenceOverviewRow } from '../components/prevalence_overview_row'; +import { INSIGHTS_PREVALENCE_TEST_ID } from '../components/test_ids'; + +export interface UsePrevalenceParams { + /** + * Id of the document + */ + eventId: string; + /** + * An object containing fields by type + */ + browserFields: BrowserFields | null; + /** + * An array of field objects with category and value + */ + dataFormattedForFieldBrowser: TimelineEventsDetailsItem[] | null; + /** + * Maintain backwards compatibility // TODO remove when possible + */ + scopeId: string; +} +export interface UsePrevalenceResult { + /** + * Returns all row children to render + */ + prevalenceRows: ReactElement[]; + /** + * Returns true if all row children render null + */ + empty: boolean; +} + +/** + * This hook retrieves the highlighted fields from the {@link getSummaryRows} method, then iterates through them + * and generate a {@link PrevalenceOverviewRow} for each. + * We use a callback method passed down to the {@link PrevalenceOverviewRow} component to know when it's rendered as null. + * We need to let the parent know when all the {@link PrevalenceOverviewRow} are null, so it can hide then entire section. + */ +export const usePrevalence = ({ + eventId, + browserFields, + dataFormattedForFieldBrowser, + scopeId, +}: UsePrevalenceParams): UsePrevalenceResult => { + const [count, setCount] = useState(0); + + // retrieves the highlighted fields + const summaryRows = useMemo( + () => + getSummaryRows({ + browserFields: browserFields || {}, + data: dataFormattedForFieldBrowser || [], + eventId, + scopeId, + isReadOnly: false, + }), + [browserFields, dataFormattedForFieldBrowser, eventId, scopeId] + ); + + const prevalenceRows = useMemo( + () => + summaryRows.map((row) => ( + setCount((prevCount) => prevCount + 1)} + data-test-subj={INSIGHTS_PREVALENCE_TEST_ID} + /> + )), + [summaryRows, scopeId] + ); + + return { + prevalenceRows, + empty: count >= summaryRows.length, + }; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/right/utils/fetch_aggregated_data.ts b/x-pack/plugins/security_solution/public/flyout/right/utils/fetch_aggregated_data.ts new file mode 100644 index 0000000000000..f523a30b61892 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/right/utils/fetch_aggregated_data.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 type { IEsSearchRequest, IKibanaSearchResponse } from '@kbn/data-plugin/common'; +import type { ISearchStart } from '@kbn/data-plugin/public'; + +/** + * Reusable method that returns a promise wrapping the search functionality of Kibana search service + */ +export const createFetchAggregatedData = async ( + searchService: ISearchStart, + req: IEsSearchRequest, + aggregationKey: string +): Promise => { + return new Promise((resolve, reject) => { + searchService.search>(req).subscribe({ + next: (response) => { + resolve(response.rawResponse); + }, + error: (error) => { + reject(error); + }, + }); + }); +}; diff --git a/x-pack/plugins/security_solution/public/flyout/url/expandable_flyout_state_from_event_meta.ts b/x-pack/plugins/security_solution/public/flyout/url/expandable_flyout_state_from_event_meta.ts new file mode 100644 index 0000000000000..1f9a18962092d --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/url/expandable_flyout_state_from_event_meta.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 { ExpandableFlyoutContext } from '@kbn/expandable-flyout'; +import { RightPanelKey } from '../right'; + +interface RedirectParams { + index: string; + eventId: string; + scopeId: string; +} + +/** + * Builds flyout state from basic event-related data, such as index name, event id and scope id. + * This value can be used to open the flyout either by passing it directly to the flyout api (exposed via ref) or + * by serializing it to the url & performing a redirect + */ +export const expandableFlyoutStateFromEventMeta = ({ + index, + eventId, + scopeId, +}: RedirectParams): ExpandableFlyoutContext['panels'] => { + return { + right: { + id: RightPanelKey, + params: { + id: eventId, + indexName: index, + scopeId, + }, + }, + left: undefined, + preview: [], + }; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/url/use_sync_flyout_state_with_url.tsx b/x-pack/plugins/security_solution/public/flyout/url/use_sync_flyout_state_with_url.tsx index be1b28147f63d..5eaa8e6f1e2cc 100644 --- a/x-pack/plugins/security_solution/public/flyout/url/use_sync_flyout_state_with_url.tsx +++ b/x-pack/plugins/security_solution/public/flyout/url/use_sync_flyout_state_with_url.tsx @@ -9,8 +9,9 @@ import { useCallback, useRef } from 'react'; import type { ExpandableFlyoutApi, ExpandableFlyoutContext } from '@kbn/expandable-flyout'; import { useSyncToUrl } from '@kbn/url-state'; import last from 'lodash/last'; +import { URL_PARAM_KEY } from '../../common/hooks/use_url_state'; -const URL_KEY = 'eventFlyout' as const; +export const FLYOUT_URL_PARAM = URL_PARAM_KEY.eventFlyout; type FlyoutState = Parameters[0]; @@ -21,7 +22,7 @@ type FlyoutState = Parameters[0]; export const useSyncFlyoutStateWithUrl = () => { const flyoutApi = useRef(null); - const syncStateToUrl = useSyncToUrl(URL_KEY, (data) => { + const syncStateToUrl = useSyncToUrl(FLYOUT_URL_PARAM, (data) => { flyoutApi.current?.openFlyout(data); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/automated_response_actions.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/automated_response_actions.cy.ts index a509af049fbf1..abf708d198984 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/automated_response_actions.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/automated_response_actions.cy.ts @@ -7,7 +7,7 @@ import type { Agent } from '@kbn/fleet-plugin/common'; import { APP_ENDPOINTS_PATH } from '../../../../../common/constants'; -import { closeAllToasts } from '../../tasks/close_all_toasts'; +import { closeAllToasts } from '../../tasks/toasts'; import { toggleRuleOffAndOn, visitRuleAlerts } from '../../tasks/isolate'; import { cleanupRule, loadRule } from '../../tasks/api_fixtures'; import { ENDPOINT_VM_NAME } from '../../tasks/common'; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/isolate.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/isolate.cy.ts index 690d1e96d2c75..dbf5f89fcb389 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/isolate.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint/isolate.cy.ts @@ -7,7 +7,7 @@ import type { Agent } from '@kbn/fleet-plugin/common'; import { APP_CASES_PATH, APP_ENDPOINTS_PATH } from '../../../../../common/constants'; -import { closeAllToasts } from '../../tasks/close_all_toasts'; +import { closeAllToasts } from '../../tasks/toasts'; import { checkEndpointListForOnlyIsolatedHosts, checkEndpointListForOnlyUnIsolatedHosts, diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/artifact_tabs_in_policy_details.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/artifact_tabs_in_policy_details.cy.ts index e3508183b960b..2977db30fadc9 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/artifact_tabs_in_policy_details.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/artifact_tabs_in_policy_details.cy.ts @@ -7,6 +7,7 @@ import { getEndpointSecurityPolicyManager } from '../../../../../scripts/endpoint/common/roles_users/endpoint_security_policy_manager'; import { getArtifactsListTestsData } from '../../fixtures/artifacts_page'; +import { visitPolicyDetailsPage } from '../../screens/policy_details'; import { createPerPolicyArtifact, createArtifactList, @@ -62,13 +63,6 @@ const visitArtifactTab = (tabId: string) => { cy.get(`#${tabId}`).click(); }; -const visitPolicyDetailsPage = () => { - cy.visit('/app/security/administration/policy'); - cy.getByTestSubj('policyNameCellLink').eq(0).click({ force: true }); - cy.getByTestSubj('policyDetailsPage').should('exist'); - cy.get('#settings').should('exist'); // waiting for Policy Settings tab -}; - describe('Artifact tabs in Policy Details page', () => { before(() => { login(); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/endpoint_role_rbac.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/endpoint_role_rbac.cy.ts index f3a84bc39935a..9493d779f3226 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/endpoint_role_rbac.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/endpoint_role_rbac.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { closeAllToasts } from '../../tasks/close_all_toasts'; +import { closeAllToasts } from '../../tasks/toasts'; import { login } from '../../tasks/login'; describe('When defining a kibana role for Endpoint security access', () => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/isolate.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/isolate.cy.ts index cc949b39404e9..118eadd4fcd5b 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/isolate.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/isolate.cy.ts @@ -19,7 +19,7 @@ import { waitForReleaseOption, } from '../../tasks/isolate'; import type { ActionDetails } from '../../../../../common/endpoint/types'; -import { closeAllToasts } from '../../tasks/close_all_toasts'; +import { closeAllToasts } from '../../tasks/toasts'; import type { ReturnTypeFromChainable } from '../../types'; import { addAlertsToCase } from '../../tasks/add_alerts_to_case'; import { APP_ALERTS_PATH, APP_CASES_PATH, APP_PATH } from '../../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/policy_details.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/policy_details.cy.ts new file mode 100644 index 0000000000000..bcc68b642de84 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/policy_details.cy.ts @@ -0,0 +1,199 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ProtectionModes } from '../../../../../common/endpoint/types'; +import { + PackagePolicyBackupHelper, + savePolicyForm, + visitPolicyDetailsPage, + yieldPolicyConfig, +} from '../../screens/policy_details'; +import type { CyIndexEndpointHosts } from '../../tasks/index_endpoint_hosts'; +import { indexEndpointHosts } from '../../tasks/index_endpoint_hosts'; +import { login } from '../../tasks/login'; + +describe('Policy Details', () => { + const packagePolicyBackupHelper = new PackagePolicyBackupHelper(); + let indexedHostsData: CyIndexEndpointHosts; + + before(() => { + login(); + indexEndpointHosts().then((results) => { + indexedHostsData = results; + }); + packagePolicyBackupHelper.backup(); + }); + + beforeEach(() => { + login(); + visitPolicyDetailsPage(); + }); + + afterEach(() => { + packagePolicyBackupHelper.restore(); + }); + + after(() => { + indexedHostsData.cleanup(); + }); + + describe('Malware Protection card', () => { + it('user should be able to see related rules', () => { + cy.getByTestSubj('malwareProtectionsForm').contains('related detection rules').click(); + + cy.url().should('contain', 'app/security/rules/management'); + }); + + it('changing protection level should enable or disable user notification', () => { + cy.getByTestSubj('malwareProtectionSwitch').click(); + cy.getByTestSubj('malwareProtectionSwitch').should('have.attr', 'aria-checked', 'true'); + + // Default: Prevent + Notify user enabled + cy.getByTestSubj('malwareProtectionMode_prevent').find('input').should('be.checked'); + cy.getByTestSubj('malwareUserNotificationCheckbox').should('be.checked'); + + // Changing to Detect -> Notify user disabled + cy.getByTestSubj('malwareProtectionMode_detect').find('label').click(); + cy.getByTestSubj('malwareUserNotificationCheckbox').should('not.be.checked'); + + // Changing back to Prevent -> Notify user enabled + cy.getByTestSubj('malwareProtectionMode_prevent').find('label').click(); + cy.getByTestSubj('malwareUserNotificationCheckbox').should('be.checked'); + }); + + it('disabling protection should disable notification in yaml for every OS', () => { + // Enable malware protection and user notification + cy.getByTestSubj('malwareProtectionSwitch').click(); + cy.getByTestSubj('malwareProtectionSwitch').should('have.attr', 'aria-checked', 'true'); + savePolicyForm(); + + yieldPolicyConfig().then((policyConfig) => { + expect(policyConfig.mac.popup.malware.enabled).to.equal(true); + expect(policyConfig.windows.popup.malware.enabled).to.equal(true); + expect(policyConfig.linux.popup.malware.enabled).to.equal(true); + }); + + // disable malware protection + cy.getByTestSubj('malwareProtectionSwitch').click(); + cy.getByTestSubj('malwareProtectionSwitch').should('have.attr', 'aria-checked', 'false'); + savePolicyForm(); + + yieldPolicyConfig().then((policyConfig) => { + expect(policyConfig.mac.popup.malware.enabled).to.equal(false); + expect(policyConfig.windows.popup.malware.enabled).to.equal(false); + expect(policyConfig.linux.popup.malware.enabled).to.equal(false); + }); + }); + + it('user should be able to enable Malware protection for every OS in yaml', () => { + yieldPolicyConfig().then((policyConfig) => { + expect(policyConfig.linux.malware.mode).to.equal(ProtectionModes.off); + expect(policyConfig.mac.malware.mode).to.equal(ProtectionModes.off); + expect(policyConfig.windows.malware.mode).to.equal(ProtectionModes.off); + }); + + cy.getByTestSubj('malwareProtectionsForm').should('contain.text', 'Linux'); + cy.getByTestSubj('malwareProtectionsForm').should('contain.text', 'Windows'); + cy.getByTestSubj('malwareProtectionsForm').should('contain.text', 'Mac'); + + cy.getByTestSubj('malwareProtectionSwitch').click(); + savePolicyForm(); + + yieldPolicyConfig().then((policyConfig) => { + expect(policyConfig.linux.malware.mode).to.equal(ProtectionModes.prevent); + expect(policyConfig.mac.malware.mode).to.equal(ProtectionModes.prevent); + expect(policyConfig.windows.malware.mode).to.equal(ProtectionModes.prevent); + }); + }); + }); + + describe('Ransomware Protection card', () => { + it('user should be able to see related rules', () => { + cy.getByTestSubj('ransomwareProtectionsForm').contains('related detection rules').click(); + + cy.url().should('contain', 'app/security/rules/management'); + }); + + it('changing protection level should enable or disable user notification', () => { + cy.getByTestSubj('ransomwareProtectionSwitch').click(); + cy.getByTestSubj('ransomwareProtectionSwitch').should('have.attr', 'aria-checked', 'true'); + + // Default: Prevent + Notify user enabled + cy.getByTestSubj('ransomwareProtectionMode_prevent').find('input').should('be.checked'); + cy.getByTestSubj('ransomwareUserNotificationCheckbox').should('be.checked'); + + // Changing to Detect -> Notify user disabled + cy.getByTestSubj('ransomwareProtectionMode_detect').find('label').click(); + cy.getByTestSubj('ransomwareUserNotificationCheckbox').should('not.be.checked'); + + // Changing back to Prevent -> Notify user enabled + cy.getByTestSubj('ransomwareProtectionMode_prevent').find('label').click(); + cy.getByTestSubj('ransomwareUserNotificationCheckbox').should('be.checked'); + }); + }); + + describe('Advanced settings', () => { + it('should show empty text inputs except for some settings', () => { + const settingsWithDefaultValues = [ + 'mac.advanced.capture_env_vars', + 'linux.advanced.capture_env_vars', + ]; + + cy.getByTestSubj('advancedPolicyButton').click(); + + cy.getByTestSubj('advancedPolicyPanel') + .children() + .each(($child) => { + const settingName = $child.find('label').text(); + + if (settingsWithDefaultValues.includes(settingName)) { + cy.wrap($child).find('input').should('not.have.value', ''); + } else { + cy.wrap($child).find('input').should('have.value', ''); + } + }); + }); + + it('should add advanced settings to policy yaml only when they are set', () => { + // Initially config should only contain the two default entries + yieldPolicyConfig().then((policyConfig) => { + expect(policyConfig.linux.advanced).to.have.keys(['capture_env_vars']); + expect(policyConfig.mac.advanced).to.have.keys(['capture_env_vars']); + expect(policyConfig.windows.advanced).to.equal(undefined); + }); + + // Set agent.connection_delay entry for every OS + cy.getByTestSubj('advancedPolicyButton').click(); + cy.getByTestSubj('advancedPolicyPanel') + .children() + .each(($child) => { + const settingName = $child.find('label').text(); + + if (settingName.includes('.agent.connection_delay')) { + cy.wrap($child).find('input').type('66'); + } + }); + savePolicyForm(); + + // Validate yaml + yieldPolicyConfig().then((policyConfig) => { + expect(policyConfig.linux.advanced).to.have.keys(['capture_env_vars', 'agent']); + expect(policyConfig.linux.advanced).to.have.deep.property('agent', { + connection_delay: '66', + }); + expect(policyConfig.mac.advanced).to.have.keys(['capture_env_vars', 'agent']); + expect(policyConfig.mac.advanced).to.have.deep.property('agent', { + connection_delay: '66', + }); + expect(policyConfig.windows.advanced).to.have.keys(['agent']); + expect(policyConfig.windows.advanced).to.have.deep.property('agent', { + connection_delay: '66', + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/responder.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/responder.cy.ts index 3ded1ec2520f5..881d1ec449eec 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/responder.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/responder.cy.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { closeAllToasts } from '../../tasks/close_all_toasts'; +import { closeAllToasts } from '../../tasks/toasts'; import type { ReturnTypeFromChainable } from '../../types'; import { addAlertsToCase } from '../../tasks/add_alerts_to_case'; import { APP_CASES_PATH } from '../../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/management/cypress/screens/policy_details.ts b/x-pack/plugins/security_solution/public/management/cypress/screens/policy_details.ts new file mode 100644 index 0000000000000..f9b84d4cc6e3a --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/cypress/screens/policy_details.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + GetOnePackagePolicyResponse, + GetPackagePoliciesResponse, + PackagePolicy, + UpdatePackagePolicy, + UpdatePackagePolicyResponse, +} from '@kbn/fleet-plugin/common'; +import { packagePolicyRouteService } from '@kbn/fleet-plugin/common'; +import { APP_POLICIES_PATH } from '../../../../common/constants'; +import type { PolicyConfig } from '../../../../common/endpoint/types'; +import { request } from '../tasks/common'; +import { expectAndCloseSuccessToast } from '../tasks/toasts'; + +export const visitPolicyDetailsPage = () => { + cy.visit(APP_POLICIES_PATH); + + cy.getByTestSubj('policyNameCellLink').eq(0).click({ force: true }); + cy.getByTestSubj('policyDetailsPage').should('exist'); + cy.get('#settings').should('exist'); // waiting for Policy Settings tab +}; + +export const savePolicyForm = () => { + cy.getByTestSubj('policyDetailsSaveButton').click(); + cy.getByTestSubj('confirmModalConfirmButton').click(); + expectAndCloseSuccessToast(); +}; + +export const yieldPolicyConfig = (): Cypress.Chainable => { + return cy + .url() + .then((url) => { + const policyId = url.match(/security\/administration\/policy\/([a-z0-9-]+)/)?.[1]; + expect(policyId).to.not.equal(undefined); + + return policyId; + }) + .then((policyId: string) => { + return request({ + url: `/api/fleet/package_policies/${policyId}`, + }); + }) + .then((res) => { + const firstPackagePolicyConfig = res.body.item.inputs[0].config; + expect(firstPackagePolicyConfig).to.not.equal(undefined); + + const policyConfig: PolicyConfig = firstPackagePolicyConfig?.policy.value; + + return policyConfig; + }); +}; + +export class PackagePolicyBackupHelper { + originalPackagePolicy!: PackagePolicy; + + backup() { + request({ + url: packagePolicyRouteService.getListPath(), + qs: { + kuery: 'ingest-package-policies.package.name: endpoint', + }, + }).then((res) => { + this.originalPackagePolicy = res.body.items[0]; + }); + } + + restore() { + const body: UpdatePackagePolicy = { + name: this.originalPackagePolicy.name, + namespace: this.originalPackagePolicy.namespace, + enabled: this.originalPackagePolicy.enabled, + inputs: this.originalPackagePolicy.inputs, + policy_id: this.originalPackagePolicy.policy_id, + }; + + request({ + method: 'PUT', + url: packagePolicyRouteService.getUpdatePath(this.originalPackagePolicy.id), + body, + }); + } +} diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_console.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_console.ts index ffde3e0fbc3ab..54ec6c08009f9 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_console.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_console.ts @@ -6,7 +6,7 @@ */ import type { ConsoleResponseActionCommands } from '../../../../common/endpoint/service/response_actions/constants'; -import { closeAllToasts } from './close_all_toasts'; +import { closeAllToasts } from './toasts'; import { APP_ENDPOINTS_PATH } from '../../../../common/constants'; import Chainable = Cypress.Chainable; diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/close_all_toasts.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/toasts.ts similarity index 87% rename from x-pack/plugins/security_solution/public/management/cypress/tasks/close_all_toasts.ts rename to x-pack/plugins/security_solution/public/management/cypress/tasks/toasts.ts index e1a64bd81d198..af759a297931e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/close_all_toasts.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/toasts.ts @@ -40,3 +40,9 @@ export const closeAllToasts = (): Cypress.Chainable> => }); }); }; + +export const expectAndCloseSuccessToast = () => { + cy.contains('Success'); + cy.getByTestSubj('toastCloseButton').click(); + cy.contains('Success').should('not.exist'); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx index 4921353317a64..7d28619e17e6e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/components/antivirus_registration_form/index.tsx @@ -58,6 +58,7 @@ export const AntivirusRegistrationForm = memo(() => { { return ( <> - +

{warningMessage}

diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx index 4ed6af2634c63..4e03e20f05f44 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/policy_form_layout.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import type { ReactWrapper } from 'enzyme'; import { mount } from 'enzyme'; import { PolicyFormLayout } from './policy_form_layout'; @@ -63,7 +64,7 @@ describe('Policy Form Layout', () => { describe('when displayed with valid id', () => { let asyncActions: Promise = Promise.resolve(); - beforeEach(() => { + beforeEach(async () => { policyPackagePolicy = generator.generatePolicyPackagePolicy(); policyPackagePolicy.id = '1'; @@ -102,6 +103,9 @@ describe('Policy Form Layout', () => { }); history.push(policyDetailsPathUrl); policyFormLayoutView = render(); + + await asyncActions; + policyFormLayoutView.update(); }); it('should NOT display timeline', async () => { @@ -109,8 +113,6 @@ describe('Policy Form Layout', () => { }); it('should display cancel button', async () => { - await asyncActions; - policyFormLayoutView.update(); const cancelbutton = policyFormLayoutView.find( 'EuiButtonEmpty[data-test-subj="policyDetailsCancelButton"]' ); @@ -118,8 +120,6 @@ describe('Policy Form Layout', () => { expect(cancelbutton.text()).toEqual('Cancel'); }); it('should redirect to policy list when cancel button is clicked', async () => { - await asyncActions; - policyFormLayoutView.update(); const cancelbutton = policyFormLayoutView.find( 'EuiButtonEmpty[data-test-subj="policyDetailsCancelButton"]' ); @@ -132,8 +132,6 @@ describe('Policy Form Layout', () => { ]); }); it('should display save button', async () => { - await asyncActions; - policyFormLayoutView.update(); const saveButton = policyFormLayoutView.find( 'EuiButton[data-test-subj="policyDetailsSaveButton"]' ); @@ -141,13 +139,98 @@ describe('Policy Form Layout', () => { expect(saveButton.text()).toEqual('Save'); }); it('should display beta badge', async () => { - await asyncActions; - policyFormLayoutView.update(); const saveButton = policyFormLayoutView.find('EuiBetaBadge'); expect(saveButton).toHaveLength(1); expect(saveButton.text()).toEqual('beta'); }); + it('should display minimum Agent version number for User Notification', async () => { + const minVersionsMap = [ + ['malware', '7.11'], + ['ransomware', '7.12'], + ['behavior', '7.15'], + ['memory', '7.15'], + ]; + + for (const [protection, minVersion] of minVersionsMap) { + expect( + policyFormLayoutView + .find(`EuiPanel[data-test-subj="${protection}ProtectionsForm"]`) + .find('EuiText[data-test-subj="policySupportedVersions"]') + .text() + ).toEqual(`Agent version ${minVersion}+`); + } + }); + + it('"Register as antivirus" should be only available for Windows', () => { + const antivirusRegistrationFormTextContent = policyFormLayoutView + .find('EuiPanel[data-test-subj="antivirusRegistrationForm"]') + .text(); + + expect(antivirusRegistrationFormTextContent).toContain('Windows'); + expect(antivirusRegistrationFormTextContent).not.toContain('Linux'); + expect(antivirusRegistrationFormTextContent).not.toContain('Mac'); + + expect(antivirusRegistrationFormTextContent).toContain( + 'Toggle on to register Elastic as an official Antivirus solution for Windows OS. This will also disable Windows Defender.' + ); + }); + + describe('Advanced settings', () => { + let showHideAdvancedSettingsButton: ReactWrapper; + + beforeEach(() => { + showHideAdvancedSettingsButton = policyFormLayoutView.find( + 'EuiButtonEmpty[data-test-subj="advancedPolicyButton"]' + ); + }); + + it('should display "Show advanced settings" button, and hide advanced options on default', () => { + expect(showHideAdvancedSettingsButton.text()).toEqual('Show advanced settings'); + expect( + policyFormLayoutView.find('EuiPanel[data-test-subj="advancedPolicyPanel"]').length + ).toEqual(0); + }); + + it('clicking on "Show/Hide advanced settings" should show/hide advanced settings', () => { + showHideAdvancedSettingsButton.simulate('click'); + + expect(showHideAdvancedSettingsButton.text()).toEqual('Hide advanced settings'); + expect( + policyFormLayoutView.find('EuiPanel[data-test-subj="advancedPolicyPanel"]').length + ).toEqual(1); + + showHideAdvancedSettingsButton.simulate('click'); + + expect( + policyFormLayoutView.find('EuiPanel[data-test-subj="advancedPolicyPanel"]').length + ).toEqual(0); + }); + + it('should display a warning message', () => { + showHideAdvancedSettingsButton.simulate('click'); + + expect( + policyFormLayoutView.find('div[data-test-subj="policyAdvancedSettingsWarning"]').text() + ).toContain( + `This section contains policy values that support advanced use cases. If not configured + properly, these values can cause unpredictable behavior. Please consult documentation + carefully or contact support before editing these values.` + ); + }); + + it('every row should contain a tooltip', () => { + showHideAdvancedSettingsButton.simulate('click'); + + policyFormLayoutView + .find('EuiPanel[data-test-subj="advancedPolicyPanel"]') + .find('EuiFormRow') + .forEach((row) => { + expect(row.find('EuiIconTip').length).toEqual(1); + }); + }); + }); + describe('when the save button is clicked', () => { let saveButton: FindReactWrapperResponse; let confirmModal: FindReactWrapperResponse; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_radio.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_radio.tsx index dd725257ee920..ec69dc8115b02 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_radio.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_radio.tsx @@ -89,6 +89,7 @@ export const ProtectionRadio = React.memo( checked={selected === protectionMode} onChange={handleRadioChange} disabled={!showEditableFormFields || selected === ProtectionModes.off} + data-test-subj={`${protection}ProtectionMode_${protectionMode}`} /> ); } diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_switch.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_switch.tsx index 3b25693410aff..20536a1905382 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_switch.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/protection_switch.tsx @@ -125,6 +125,7 @@ export const ProtectionSwitch = React.memo( checked={selected !== ProtectionModes.off} onChange={handleSwitchChange} disabled={!showEditableFormFields} + data-test-subj={`${protection}ProtectionSwitch`} /> ); } diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/user_notification.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/user_notification.tsx index 4b6a2077f835e..baecfef415a02 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/user_notification.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_forms/components/user_notification.tsx @@ -159,7 +159,7 @@ export const UserNotification = React.memo( - + ({ + useKibana: jest.fn(), +})); + +jest.mock('../../common/components/landing_page', () => ({ + LandingPageComponent: jest + .fn() + .mockReturnValue(
), +})); + +describe('LandingPage', () => { + const mockGetStartedComponent = jest.fn(); + const history = createBrowserHistory(); + const mockSecuritySolutionTemplateWrapper = jest + .fn() + .mockImplementation(({ children }) =>
{children}
); + + const renderPage = () => + render( + + + , + { wrapper: TestProviders } + ); + + beforeAll(() => { + (useKibana as jest.Mock).mockReturnValue({ + services: { + securityLayout: { + getPluginWrapper: jest.fn().mockReturnValue(mockSecuritySolutionTemplateWrapper), + }, + getStartedComponent: mockGetStartedComponent, + }, + }); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + it('renders the default component', () => { + const { queryByTestId } = renderPage(); + expect(queryByTestId('default-get-started-page')).toBeInTheDocument(); + }); + + it('renders the get started component', () => { + mockGetStartedComponent.mockReturnValue(
); + const { queryByTestId } = renderPage(); + + expect(queryByTestId('default-get-started-page')).not.toBeInTheDocument(); + expect(queryByTestId('get-started')).toBeInTheDocument(); + }); +}); 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 0b9760d2a8db4..cb0565b9bc5fa 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/landing.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/landing.tsx @@ -5,15 +5,23 @@ * 2.0. */ -import React, { memo } from 'react'; +import React, { memo, useMemo } from 'react'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { SecurityPageName } from '../../../common/constants'; import { LandingPageComponent } from '../../common/components/landing_page'; +import { useKibana } from '../../common/lib/kibana'; +import { PluginTemplateWrapper } from '../../common/components/plugin_template_wrapper'; export const LandingPage = memo(() => { + const { getStartedComponent } = useKibana().services; + const GetStartedComponent = useMemo(() => getStartedComponent?.(), [getStartedComponent]); return ( <> - + {GetStartedComponent ?? ( + + + + )} ); diff --git a/x-pack/plugins/security_solution/public/overview/routes.tsx b/x-pack/plugins/security_solution/public/overview/routes.tsx index b5ff8ba4807ec..301490de42848 100644 --- a/x-pack/plugins/security_solution/public/overview/routes.tsx +++ b/x-pack/plugins/security_solution/public/overview/routes.tsx @@ -41,11 +41,9 @@ const DetectionResponseRoutes = () => ( ); const LandingRoutes = () => ( - - - - - + + + ); const EntityAnalyticsRoutes = () => ( diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index a12bb7108b4af..7116b278f81ff 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -29,6 +29,7 @@ import type { SubPlugins, StartedSubPlugins, StartPluginsDependencies, + GetStartedComponent, } from './types'; import { initTelemetry, TelemetryService } from './common/lib/telemetry'; import { KibanaServices } from './common/lib/kibana/services'; @@ -88,6 +89,7 @@ export class Plugin implements IPlugin; + private getStartedComponent?: GetStartedComponent; constructor(private readonly initializerContext: PluginInitializerContext) { this.config = this.initializerContext.config.get(); @@ -171,6 +173,7 @@ export class Plugin implements IPlugin navLinks$, setIsSidebarEnabled: (isSidebarEnabled: boolean) => this.isSidebarEnabled$.next(isSidebarEnabled), + setGetStartedPage: (getStartedComponent: GetStartedComponent) => { + this.getStartedComponent = getStartedComponent; + }, }; } diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx index bf4cfbb98e00f..31491730adc83 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/helpers.tsx @@ -12,16 +12,18 @@ import { getFieldValue } from '../../../../detections/components/host_isolation/ import { DEFAULT_ALERTS_INDEX, DEFAULT_PREVIEW_INDEX } from '../../../../../common/constants'; export interface GetBasicDataFromDetailsData { - alertId: string; agentId?: string; - isAlert: boolean; - hostName: string; - userName: string; - ruleName: string; - timestamp: string; + alertId: string; + alertUrl?: string; data: TimelineEventsDetailsItem[] | null; + hostName: string; + indexName?: string; + isAlert: boolean; ruleDescription: string; ruleId: string; + ruleName: string; + timestamp: string; + userName: string; } export const useBasicDataFromDetailsData = ( @@ -49,6 +51,16 @@ export const useBasicDataFromDetailsData = ( const alertId = useMemo(() => getFieldValue({ category: '_id', field: '_id' }, data), [data]); + const indexName = useMemo( + () => getFieldValue({ category: '_index', field: '_index' }, data), + [data] + ); + + const alertUrl = useMemo( + () => getFieldValue({ category: 'kibana', field: 'kibana.alert.url' }, data), + [data] + ); + const agentId = useMemo( () => getFieldValue({ category: 'agent', field: 'agent.id' }, data), [data] @@ -71,28 +83,32 @@ export const useBasicDataFromDetailsData = ( return useMemo( () => ({ - alertId, agentId, - isAlert, - hostName, - userName, - ruleName, - timestamp, + alertId, + alertUrl, data, + hostName, + indexName, + isAlert, ruleDescription, ruleId, + ruleName, + timestamp, + userName, }), [ agentId, alertId, + alertUrl, + data, hostName, + indexName, isAlert, + ruleDescription, + ruleId, ruleName, timestamp, userName, - data, - ruleDescription, - ruleId, ] ); }; diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index 6c923500889d8..c474d802e94e4 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -132,6 +132,7 @@ export type StartServices = CoreStart & }; savedObjectsManagement: SavedObjectsManagementPluginStart; isSidebarEnabled$: BehaviorSubject; + getStartedComponent: GetStartedComponent | undefined; telemetry: TelemetryClientStart; }; @@ -139,9 +140,15 @@ export interface PluginSetup { resolver: () => Promise; } +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type GetStartedComponentProps = {}; + +export type GetStartedComponent = (props?: GetStartedComponentProps) => JSX.Element; + export interface PluginStart { getNavLinks$: () => Observable; setIsSidebarEnabled: (isSidebarEnabled: boolean) => void; + setGetStartedPage: (getStartedComponent: GetStartedComponent) => void; } export interface AppObservableLibs { diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts index 7823309aa0059..58180795032ca 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/endpoint_metadata_services.ts @@ -152,7 +152,7 @@ export const waitForEndpointToStreamData = async ( let found: HostInfo | undefined; while (!found && !hasTimedOut()) { - found = await fetchEndpointMetadata(kbnClient, 'invalid-id-test').catch((error) => { + found = await fetchEndpointMetadata(kbnClient, endpointAgentId).catch((error) => { // Ignore `not found` (404) responses. Endpoint could be new and thus documents might not have // been streamed yet. if (error?.response?.status === 404) { diff --git a/x-pack/plugins/serverless_observability/kibana.jsonc b/x-pack/plugins/serverless_observability/kibana.jsonc index 1ce64fcee8f02..3c493b23f5155 100644 --- a/x-pack/plugins/serverless_observability/kibana.jsonc +++ b/x-pack/plugins/serverless_observability/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/serverless-observability", - "owner": "@elastic/appex-sharedux", + "owner": ["@elastic/appex-sharedux", "@elastic/apm-ui"], "description": "Serverless customizations for observability.", "plugin": { "id": "serverlessObservability", diff --git a/x-pack/plugins/serverless_security/public/components/get_started/get_started.tsx b/x-pack/plugins/serverless_security/public/components/get_started/get_started.tsx new file mode 100644 index 0000000000000..8a0b7965b8d50 --- /dev/null +++ b/x-pack/plugins/serverless_security/public/components/get_started/get_started.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface Props {} + +const icons = ['Kibana', 'Kibana', 'Kibana']; + +export const GetStartedComponent: React.FC = ({}) => { + const cardNodes = useMemo( + () => + icons.map(function (item, index) { + return ( + + } title={`Elastic ${item}`} /> + + ); + }), + [] + ); + return ( + + + +

+ {i18n.translate('xpack.serverlessSecurity.getStarted.subTitle', { + defaultMessage: `Let’s get started`, + })} +

+
+ + {i18n.translate('xpack.serverlessSecurity.getStarted.description', { + defaultMessage: `Set up your Elastic Security workspace. Use the toggles below to curate a list of tasks that best fits your environment`, + })} + + + } + > + {cardNodes} +
+ + + +
+ ); +}; + +export const GetStarted = React.memo(GetStartedComponent); diff --git a/x-pack/plugins/serverless_security/public/components/get_started/index.tsx b/x-pack/plugins/serverless_security/public/components/get_started/index.tsx new file mode 100644 index 0000000000000..ed01714aa78a3 --- /dev/null +++ b/x-pack/plugins/serverless_security/public/components/get_started/index.tsx @@ -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 React from 'react'; + +import { CoreStart } from '@kbn/core/public'; +import type { GetStartedComponentProps, GetStartedComponent } from './types'; +import { GetStarted } from './get_started'; +import { KibanaServicesProvider } from '../../services'; +import { ServerlessSecurityPluginStartDependencies } from '../../types'; + +export const getSecurityGetStartedComponent = ( + core: CoreStart, + pluginsStart: ServerlessSecurityPluginStartDependencies +): GetStartedComponent => { + return (_props?: GetStartedComponentProps) => ( + + + + ); +}; diff --git a/x-pack/plugins/serverless_security/public/components/get_started/types.ts b/x-pack/plugins/serverless_security/public/components/get_started/types.ts new file mode 100644 index 0000000000000..ed37f49d4241d --- /dev/null +++ b/x-pack/plugins/serverless_security/public/components/get_started/types.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type GetStartedComponentProps = {}; + +export type GetStartedComponent = (props?: GetStartedComponentProps) => JSX.Element; diff --git a/x-pack/plugins/serverless_security/public/plugin.ts b/x-pack/plugins/serverless_security/public/plugin.ts index bc867cbcc9a04..a8204ef634933 100644 --- a/x-pack/plugins/serverless_security/public/plugin.ts +++ b/x-pack/plugins/serverless_security/public/plugin.ts @@ -6,6 +6,7 @@ */ import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { getSecurityGetStartedComponent } from './components/get_started'; import { getSecuritySideNavComponent } from './components/side_navigation'; import { ServerlessSecurityPluginSetup, @@ -37,6 +38,7 @@ export class ServerlessSecurityPlugin const { securitySolution, serverless } = startDeps; securitySolution.setIsSidebarEnabled(false); + securitySolution.setGetStartedPage(getSecurityGetStartedComponent(core, startDeps)); serverless.setSideNavComponent(getSecuritySideNavComponent(core, startDeps)); return {}; diff --git a/x-pack/plugins/serverless_security/tsconfig.json b/x-pack/plugins/serverless_security/tsconfig.json index 75252c18a0cfa..3defb708db429 100644 --- a/x-pack/plugins/serverless_security/tsconfig.json +++ b/x-pack/plugins/serverless_security/tsconfig.json @@ -25,5 +25,7 @@ "@kbn/kibana-react-plugin", "@kbn/core-chrome-browser", "@kbn/i18n-react", + "@kbn/i18n", + "@kbn/shared-ux-page-kibana-template", ] } diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/app.ts b/x-pack/plugins/snapshot_restore/server/routes/api/app.ts index 702a7633f7cc7..2df8f314a5f99 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/app.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/app.ts @@ -52,7 +52,6 @@ export function registerAppRoutes({ const { has_all_requested: hasAllPrivileges, cluster } = await clusterClient.asCurrentUser.security.hasPrivileges({ body: { - // @ts-expect-error @elastic/elasticsearch doesn't declare all possible values in SecurityClusterPrivilege cluster: [...APP_REQUIRED_CLUSTER_PRIVILEGES, ...APP_SLM_CLUSTER_PRIVILEGES], }, }); @@ -71,7 +70,6 @@ export function registerAppRoutes({ } const indexHasAllPrivileges = APP_RESTORE_INDEX_PRIVILEGES.every((privilege) => - // @ts-expect-error SecurityClusterPrivilege doesn’t list all the possible privileges. privileges.includes(privilege) ); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx index 85e0f5e9e31b5..f27ad80ae942c 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/auth.tsx @@ -21,9 +21,8 @@ import { useFormContext, useFormData, } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { Field, TextField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { Field, TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from '../translations'; const { emptyField } = fieldValidators; @@ -85,11 +84,20 @@ export const AuthStep: FunctionComponent = ({ display, readOnly }) => { /> - diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts index 1ef221566352d..bbe7b09bd4509 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts @@ -119,6 +119,13 @@ export const USERNAME_REQUIRED = i18n.translate( } ); +export const PASSWORD_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.casesWebhook.error.requiredAuthPasswordText', + { + defaultMessage: 'Password is required.', + } +); + export const SUMMARY_REQUIRED = i18n.translate( 'xpack.stackConnectors.components.casesWebhook.error.requiredWebhookSummaryText', { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/email/email_connector.tsx b/x-pack/plugins/stack_connectors/public/connector_types/email/email_connector.tsx index fcb4fc57ee43d..bfff63877679a 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/email/email_connector.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/email/email_connector.tsx @@ -24,13 +24,10 @@ import { SelectField, TextField, ToggleField, + PasswordField, } from '@kbn/es-ui-shared-plugin/static/forms/components'; import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; -import { - PasswordField, - useConnectorContext, - useKibana, -} from '@kbn/triggers-actions-ui-plugin/public'; +import { useConnectorContext, useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import { AdditionalEmailServices } from '../../../common'; import { getEmailServices } from './email'; import { useEmailConfig } from './use_email_config'; @@ -297,11 +294,20 @@ export const EmailActionConnectorFields: React.FunctionComponent - diff --git a/x-pack/plugins/stack_connectors/public/connector_types/email/exchange_form.tsx b/x-pack/plugins/stack_connectors/public/connector_types/email/exchange_form.tsx index c38eebcf44fc1..e78d4abec18b1 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/email/exchange_form.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/email/exchange_form.tsx @@ -10,8 +10,8 @@ import { EuiFlexItem, EuiFlexGroup, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components'; -import { PasswordField, useKibana } from '@kbn/triggers-actions-ui-plugin/public'; +import { TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from './translations'; const { emptyField } = fieldValidators; @@ -83,22 +83,31 @@ const ExchangeFormFields: React.FC = ({ readOnly }) => - - - - } - data-test-subj="emailClientSecret" + config={{ + label: i18n.CLIENT_SECRET_LABEL, + validations: [ + { + validator: emptyField(i18n.CLIENT_SECRET_REQUIRED), + }, + ], + helpText: ( + + + + ), + }} + component={PasswordField} + componentProps={{ + euiFieldProps: { readOnly, 'data-test-subj': 'emailClientSecret' }, + }} /> diff --git a/x-pack/plugins/stack_connectors/public/connector_types/email/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/email/translations.ts index c21418f349096..71d8cafc7400b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/email/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/email/translations.ts @@ -161,6 +161,20 @@ export const SUBJECT_REQUIRED = i18n.translate( } ); +export const PASSWORD_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.email.error.requiredPasswordText', + { + defaultMessage: 'Password is required.', + } +); + +export const CLIENT_SECRET_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.email.requiredClientSecretText', + { + defaultMessage: 'Client Secret is required.', + } +); + export function getInvalidEmailAddress(email: string) { return i18n.translate('xpack.stackConnectors.components.email.error.invalidEmail', { defaultMessage: 'Email address {email} is not valid.', diff --git a/x-pack/plugins/stack_connectors/public/connector_types/es_index/es_index_connector.tsx b/x-pack/plugins/stack_connectors/public/connector_types/es_index/es_index_connector.tsx index 54912f7bd9492..fd5e31dfaafc7 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/es_index/es_index_connector.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/es_index/es_index_connector.tsx @@ -25,14 +25,15 @@ import { VALIDATION_TYPES, } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { ToggleField, SelectField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { + ToggleField, + SelectField, + HiddenField, +} from '@kbn/es-ui-shared-plugin/static/forms/components'; import { DocLinksStart } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { - type ActionConnectorFieldsProps, - HiddenField, -} from '@kbn/triggers-actions-ui-plugin/public'; +import { type ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; import { firstFieldOption, getFields, @@ -134,7 +135,7 @@ const IndexActionConnectorFields: React.FunctionComponent - + {(field) => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/credentials_auth.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/credentials_auth.tsx index 46b509e22d6fc..7ca2e0487f5dc 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/credentials_auth.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/credentials_auth.tsx @@ -8,8 +8,7 @@ import React, { memo } from 'react'; import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components'; -import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public'; +import { TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import * as i18n from '../translations'; interface Props { @@ -43,13 +42,25 @@ const CredentialsAuthComponent: React.FC = ({ isLoading, readOnly, pathPr }, }} /> - ); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/oauth.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/oauth.tsx index febcb6c498307..d6fbfee7fd74a 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/oauth.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/auth_types/oauth.tsx @@ -8,8 +8,11 @@ import React, { memo } from 'react'; import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { TextAreaField, TextField } from '@kbn/es-ui-shared-plugin/static/forms/components'; -import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public'; +import { + TextAreaField, + TextField, + PasswordField, +} from '@kbn/es-ui-shared-plugin/static/forms/components'; import * as i18n from '../translations'; interface Props { @@ -83,13 +86,25 @@ const OAuthComponent: React.FC = ({ isLoading, readOnly, pathPrefix = '' }, }} /> - = ({ isLoading, readOnly, pathPrefix = '' }, }} /> - ); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/servicenow_connectors.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/servicenow_connectors.tsx index b9aeca98b6cde..f667847f6dd29 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/servicenow_connectors.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/servicenow_connectors.tsx @@ -8,13 +8,14 @@ import React, { useCallback, useEffect, useState, useMemo } from 'react'; import { EuiSpacer } from '@elastic/eui'; -import { useFormContext, useFormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; import { - HiddenField, - updateActionConnector, - useKibana, -} from '@kbn/triggers-actions-ui-plugin/public'; + UseField, + useFormContext, + useFormData, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { HiddenField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; +import { updateActionConnector, useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import type { ConnectorFormSchema } from '@kbn/triggers-actions-ui-plugin/public'; import { snExternalServiceConfig } from '../../../../common/servicenow_config'; import { DeprecatedCallout } from './deprecated_callout'; @@ -174,7 +175,12 @@ const ServiceNowConnectorFields: React.FC = ({ )} {!requiresNewApplication && } - + + ); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts index 191fc001d7e80..f55a82b4ce00c 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/translations.ts @@ -360,6 +360,20 @@ export const USER_IDENTIFIER_REQUIRED = i18n.translate( } ); +export const PASSWORD_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.serviceNow.requiredPasswordTextField', + { + defaultMessage: 'Password is required.', + } +); + +export const CLIENTSECRET_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.serviceNow.requiredClientSecretTextField', + { + defaultMessage: 'Client Secret is required.', + } +); + export const IS_OAUTH = i18n.translate('xpack.stackConnectors.components.serviceNow.useOAuth', { defaultMessage: 'Use OAuth authentication', }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_connection.tsx b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_connection.tsx index 2a32a7cace748..f4b63b567a710 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_connection.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_connection.tsx @@ -8,10 +8,10 @@ import React from 'react'; import { EuiLink } from '@elastic/eui'; import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { TextField, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; import { FormattedMessage } from '@kbn/i18n-react'; -import { PasswordField, useKibana } from '@kbn/triggers-actions-ui-plugin/public'; +import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from '../translations'; interface Props { @@ -62,22 +62,34 @@ const SwimlaneConnectionComponent: React.FunctionComponent = ({ readOnly }, }} /> - - - - } - data-test-subj="swimlaneApiTokenInput" + config={{ + label: i18n.SW_API_TOKEN_TEXT_FIELD_LABEL, + validations: [ + { + validator: emptyField(i18n.SW_REQUIRED_API_TOKEN), + }, + ], + helpText: ( + + + + ), + }} + component={PasswordField} + componentProps={{ + euiFieldProps: { + 'data-test-subj': 'swimlaneApiTokenInput', + readOnly, + }, + }} /> ); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_fields.tsx b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_fields.tsx index 4afb2eacc8918..9a4f45eaa1ce5 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_fields.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/steps/swimlane_fields.tsx @@ -14,9 +14,9 @@ import { useFormData, VALIDATION_TYPES, } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { ComboBoxField } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; +import { ComboBoxField, ButtonGroupField } from '@kbn/es-ui-shared-plugin/static/forms/components'; -import { ButtonGroupField } from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from '../translations'; import { MappingConfigurationKeys, @@ -25,6 +25,8 @@ import { } from '../types'; import { isRequiredField, isValidFieldForConnector } from '../helpers'; +const { emptyField } = fieldValidators; + const SINGLE_SELECTION = { asPlainText: true }; const EMPTY_COMBO_BOX_ARRAY: Array> | undefined = []; @@ -176,12 +178,26 @@ const SwimlaneFieldsComponent: React.FC = ({ fields, readOnly }) => { return ( <> - {isValidFieldForConnector(connectorType as SwimlaneConnectorType.All, 'alertIdConfig') && ( = ({ title, dataTestSubj }) => { return ( @@ -78,12 +78,24 @@ const TorqActionConnectorFields: React.FunctionComponent - diff --git a/x-pack/plugins/stack_connectors/public/connector_types/torq/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/torq/translations.ts index 6985e6dd01ce3..b86d4cf86960c 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/torq/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/torq/translations.ts @@ -40,6 +40,13 @@ export const TORQ_TOKEN_LABEL = i18n.translate('xpack.stackConnectors.torqAction defaultMessage: 'Torq integration token', }); +export const TORQ_TOKEN_REQUIRED = i18n.translate( + 'xpack.stackConnectors.error.requiredWebhookTorqTokenText', + { + defaultMessage: 'Torq integration token is required.', + } +); + export const BODY_REQUIRED = i18n.translate('xpack.stackConnectors.error.requiredWebhookBodyText', { defaultMessage: 'Body is required.', }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts index 7095c91729f91..d8ab4bbbfcaea 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/webhook/translations.ts @@ -104,3 +104,10 @@ export const BODY_REQUIRED = i18n.translate( defaultMessage: 'Body is required.', } ); + +export const PASSWORD_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.webhook.error.requiredWebhookPasswordText', + { + defaultMessage: 'Password is required.', + } +); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx b/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx index 233d2eea4b117..e81931486383f 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx @@ -27,10 +27,10 @@ import { SelectField, TextField, ToggleField, + PasswordField, } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; -import { PasswordField } from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from './translations'; const HTTP_VERBS = ['post', 'put']; @@ -138,11 +138,23 @@ const WebhookActionConnectorFields: React.FunctionComponent - diff --git a/x-pack/plugins/stack_connectors/public/connector_types/xmatters/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/xmatters/translations.ts index 7a6dffe657e20..84ab48b84b908 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/xmatters/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/xmatters/translations.ts @@ -14,6 +14,13 @@ export const BASIC_AUTH_LABEL = i18n.translate( } ); +export const BASIC_AUTH_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.xmatters.error.requiredConnectorSettingsText', + { + defaultMessage: 'Authentication method is required.', + } +); + export const BASIC_AUTH_BUTTON_GROUP_LEGEND = i18n.translate( 'xpack.stackConnectors.components.xmatters.basicAuthButtonGroupLegend', { @@ -39,6 +46,13 @@ export const PASSWORD_LABEL = i18n.translate( } ); +export const PASSWORD_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.xmatters.error.requiredPasswordText', + { + defaultMessage: 'Password is required.', + } +); + export const BASIC_AUTH_BUTTON_LABEL = i18n.translate( 'xpack.stackConnectors.components.xmatters.basicAuthLabel', { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/xmatters/xmatters_connectors.tsx b/x-pack/plugins/stack_connectors/public/connector_types/xmatters/xmatters_connectors.tsx index ee4aab8839e48..5e5c924646f4b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/xmatters/xmatters_connectors.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/xmatters/xmatters_connectors.tsx @@ -15,13 +15,13 @@ import { useFormContext, useFormData, } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { TextField } from '@kbn/es-ui-shared-plugin/static/forms/components'; -import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; import { - ButtonGroupField, - HiddenField, + TextField, PasswordField, -} from '@kbn/triggers-actions-ui-plugin/public'; + HiddenField, + ButtonGroupField, +} from '@kbn/es-ui-shared-plugin/static/forms/components'; +import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; import { XmattersAuthenticationType } from '../types'; import * as i18n from './translations'; @@ -107,14 +107,28 @@ const XmattersActionConnectorFields: React.FunctionComponent - - + {selectedAuth === XmattersAuthenticationType.URL ? ( @@ -167,11 +181,23 @@ const XmattersActionConnectorFields: React.FunctionComponent - diff --git a/x-pack/plugins/transform/server/routes/api/privileges.ts b/x-pack/plugins/transform/server/routes/api/privileges.ts index 20c4515cd97b9..cd6817f8be63c 100644 --- a/x-pack/plugins/transform/server/routes/api/privileges.ts +++ b/x-pack/plugins/transform/server/routes/api/privileges.ts @@ -47,7 +47,6 @@ export function registerPrivilegesRoute({ router, license }: RouteDependencies) const esClusterPrivilegesReq: Promise = esClient.asCurrentUser.security.hasPrivileges({ body: { - // @ts-expect-error SecurityClusterPrivilege doesn’t contain all the priviledges cluster: APP_CLUSTER_PRIVILEGES, }, }); diff --git a/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts b/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts index 04f3f4898b79f..5f9b51d0fa433 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms_nodes.ts @@ -59,7 +59,6 @@ export function registerTransformNodesRoutes({ router, license }: RouteDependenc const { has_all_requested: hasAllPrivileges } = await esClient.asCurrentUser.security.hasPrivileges({ body: { - // @ts-expect-error SecurityClusterPrivilege doesn’t contain all the priviledges cluster: NODES_INFO_PRIVILEGES, }, }); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 9046cccb857b4..f38e6310626eb 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -5748,48 +5748,9 @@ "unifiedSearch.query.queryBar.KQLNestedQuerySyntaxInfoText": "Il semblerait que votre requête porte sur un champ imbriqué. Selon le résultat visé, il existe plusieurs façons de construire une syntaxe KQL pour des requêtes imbriquées. Apprenez-en plus dans notre {link}.", "unifiedSearch.query.queryBar.searchInputAriaLabel": "Commencer à taper pour rechercher et filtrer la page {pageType}", "unifiedSearch.query.queryBar.searchInputPlaceholder": "Filtrer vos données à l'aide de la syntaxe {language}", - "textBasedEditor.query.textBasedLanguagesEditor.errorCount": "{count} {count, plural, one {erreur} other {erreurs}}", - "textBasedEditor.query.textBasedLanguagesEditor.lineCount": "{count} {count, plural, one {ligne} other {lignes}}", - "textBasedEditor.query.textBasedLanguagesEditor.lineNumber": "Ligne {lineNumber}", "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionTitle": "Supprimer \"{savedQueryName}\" ?", "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonAriaLabel": "Enregistrer les modifications apportées à {title}", "unifiedSearch.search.unableToGetSavedQueryToastTitle": "Impossible de charger la requête enregistrée {savedQueryId}", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.addOperator.markdown": "### Add (+)\n```\nSELECT 1 + 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.andOperator.markdown": "### AND\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no > 10000 AND emp_no < 10005 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.averageFunction.markdown": "### AVG\nRetourne la moyenne (moyenne arithmétique) des valeurs entrées.\n```\nAVG(numeric_field)\n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n```\nSELECT AVG(salary) AS avg FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.between.markdown": "### Between\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no BETWEEN 9990 AND 10003 ORDER BY emp_no\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.comparison.markdown": "### Comparison (<, <=, >, >=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countAllFunction.markdown": "### Count (All)\nRenvoie le nombre total de toutes les valeurs non nulles en entrée. COUNT() et COUNT(ALL ) sont équivalents.\n\n```\nCOUNT(ALL field_name) \n```\n- nom du champ. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n```\nSELECT COUNT(ALL last_name) AS count_all, COUNT(DISTINCT last_name) count_distinct FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countDistinctFunction.markdown": "### Count (Distinct)\nRenvoie le nombre total de valeurs non nulles distinctes dans les valeurs en entrée.\n\n```\nCOUNT(DISTINCT field_name)\n```\n- Entrée : un nom de champ.\n- Sortie : une valeur numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n```\nSELECT COUNT(DISTINCT hire_date) unique_hires, COUNT(hire_date) AS hires FROM emp\n\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countFunction.markdown": "### Count\nRenvoie le nombre total de valeurs en entrée.\n\n\n```\nCOUNT(expression)\n```\n- expression. Nom de champ, caractère générique (*) ou n'importe quelle valeur numérique. Pour COUNT(*) ou COUNT(), toutes les valeurs sont prises en compte, même celles manquantes ou nulles. Pour COUNT(), les valeurs nulles ne sont pas prises en compte.\n```\nSELECT COUNT(*) AS count FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.divideOperator.markdown": "### Divide (/)\n```\nSELECT 6 / 3 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.equality.markdown": "### Equality (=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no = 10000 LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.firstFunction.markdown": "### FIRST / FIRST_VALUE\nRenvoie la première valeur non nulle (si elle existe) de la colonne d'entrée field_name triée selon la colonne ordering_field_name. Si la valeur ordering_field_name n'est pas fournie, seule la colonne field_name est utilisée pour le tri. \n\n```\nFIRST(\n field_name \n [, ordering_field_name])\n```\n- Nom du champ : champ cible de l'agrégation\n- ordering_field_name : champ facultatif utilisé pour le tri.\n\n```\nSELECT gender, FIRST(first_name, birth_date) FROM emp GROUP BY gender ORDER BY gender\n```\n\n- FIRST ne peut pas être utilisé dans une clause HAVING.\n- FIRST ne peut pas être utilisé avec des colonnes de type texte, sauf si le champ est aussi enregistré comme mot-clé.\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.inequality.markdown": "### Inequality (<> or !=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no <> 10000 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.inOperator.markdown": "### IN (, , ...)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IN (10000, 10001, 10002, 999) ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.kurtosisFunction.markdown": "### KURTOSIS\nQuantifier la forme de la distribution des valeurs en entrée dans le champ field_name.\n\n```\nKURTOSIS(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, KURTOSIS(salary) AS k FROM emp\n```\n\n- KURTOSIS ne peut pas être utilisé en plus des fonctions ou des opérateurs scalaires, uniquement sur un champ. \n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.lastFunction.markdown": "### LAST / LAST_VALUE\nInverse de FIRST/FIRST_VALUE. Renvoie la dernière valeur non nulle (si elle existe) de la colonne d'entrée field_name triée par ordre croissant selon la colonne ordering_field_name. Si la valeur ordering_field_name n'est pas fournie, seule la colonne field_name est utilisée pour le tri. \n\n```\nLAST(\n field_name \n [, ordering_field_name])\n```\n- Nom du champ : champ cible de l'agrégation\n- ordering_field_name : champ facultatif utilisé pour le tri.\n```\nSELECT gender, LAST(first_name) FROM emp GROUP BY gender ORDER BY gender\n```\n- LAST ne peut pas être utilisé dans une clause HAVING.\n- LAST ne peut pas être utilisé avec des colonnes de type texte, sauf si le champ est aussi enregistré comme mot-clé.\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.madFunction.markdown": "### MAD\nMesure la variabilité des valeurs d'entrée dans le champ field_name.\n\n```\nMAD(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, AVG(salary) AS avg, MAD(salary) AS mad FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.markdown": "## À propos d'Elasticsearch SQL\n\nUtilisez Elasticsearch SQL pour rechercher et agréger les données dans Elasticsearch. Ce langage de requête fournit une recherche full text avec une syntaxe connue. Voici un exemple de requête :\n \n```\nSELECT * FROM library \nORDER BY page_count DESC LIMIT 5\n```\n \nElasticsearch SQL :\n\n- Fournit un jeu complet d'opérateurs et de fonctions intégrés.\n- Suit la terminologie et les conventions SQL.\n- Accepte une commande par ligne. Une commande est une séquence de jetons terminée par la fin du flux d'entrée\n \n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.maxFunction.markdown": "### MAX\nRetourne la valeur maximale de toutes les valeurs en entrée dans le champ field_name.\n\n```\nMAX(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MAX(salary) AS max FROM emp\n```\n\n- MAX sur un champ de type texte ou mot-clé est traduit en FIRST/FIRST_VALUE et ne peut donc pas être utilisé dans la clause HAVING.\n\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.minFunction.markdown": "### MIN\nRetourne la valeur minimale de toutes les valeurs en entrée dans le champ field_name.\n\n```\nMIN(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min FROM emp\n```\n\n- MIN sur un champ de type texte ou mot-clé est traduit en FIRST/FIRST_VALUE et ne peut donc pas être utilisé dans la clause HAVING.\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.moduloOperator.markdown": "### Modulo or remainder(%)\n```\nSELECT 5 % 2 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.multiplyOperator.markdown": "### Multiply (*)\n```\nSELECT 2 * 3 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.negateOperator.markdown": "### Negate (unary -)\n```\nSELECT - 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.notOperator.markdown": "### NOT\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE NOT emp_no = 10000 LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullNotNull.markdown": "### IS NULL/IS NOT NULL\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IS NOT NULL AND gender IS NULL\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullSafeEquality.markdown": "### Null safe equality:\n```\nSELECT 'elastic' <=> null AS \"equals\"\n\n égal\n---------------\nfaux\n```\n```\nSELECT null <=> null AS \"equals\"\n\n égal\n---------------\nvrai\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.orOperator.markdown": "### OR\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 OR emp_no = 10005 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileFunction.markdown": "### PERCENTILE\nRetourne le centile n (représenté par le paramètre numeric_exp) des valeurs en entrée dans le champ field_name.\n\n```\nPERCENTILE(\n field_name, \n percentile[, \n method[, \n method_parameter]])\n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n- centile : expression numérique (doit être une constante et ne doit pas être basé sur un champ). Si la valeur est nulle, la fonction renvoie une valeur nulle.\n- method : chaîne littérale facultative pour l'algorithme de centile. Valeurs possibles : tdigest ou hdr. La valeur par défaut est tdigest.\n- method_parameter : numérique littéral facultatif qui configure l'algorithme de centile. Configure la compression pour tdigest ou number_of_significant_value_digits pour hdr. La valeur par défaut est la même que celle de l'algorithme de sauvegarde.\n\n```\nSELECT\n languages,\n PERCENTILE(salary, 97.3, 'tdigest', 100.0) AS \"97.3_TDigest\",\n PERCENTILE(salary, 97.3, 'hdr', 3) AS \"97.3_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileRankFunction.markdown": "### PERCENTILE_RANK\nRetourne le rang centile n (représenté par le paramètre numeric_exp) des valeurs en entrée dans le champ field_name.\n\n```\nPERCENTILE_RANK(\n field_name, \n value[, \n method[, \n method_parameter]]) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n- centile : expression numérique (doit être une constante et ne doit pas être basé sur un champ). Si la valeur est nulle, la fonction renvoie une valeur nulle.\n- method : chaîne littérale facultative pour l'algorithme de centile. Valeurs possibles : tdigest ou hdr. La valeur par défaut est tdigest.\n- method_parameter : numérique littéral facultatif qui configure l'algorithme de centile. Configure la compression pour tdigest ou number_of_significant_value_digits pour hdr. La valeur par défaut est la même que celle de l'algorithme de sauvegarde.\n\n```\nSELECT\n languages,\n ROUND(PERCENTILE_RANK(salary, 65000, 'tdigest', 100.0), 2) AS \"rank_TDigest\",\n ROUND(PERCENTILE_RANK(salary, 65000, 'hdr', 3), 2) AS \"rank_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.skewnessFunction.markdown": "### SKEWNESS\nQuantifier la distribution asymétrique des valeurs en entrée dans le champ field_name.\n\n```\nSKEWNESS(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SKEWNESS(salary) AS s FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevpopFunction.markdown": "### STDDEV_POP\nRetourne l'écart type de population des valeurs en entrée dans le champ field_name.\n\n```\nSTDDEV_POP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_POP(salary) AS stddev FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevsampFunction.markdown": "### STDDEV_SAMP\nRetourne l'écart type de l'échantillon des valeurs en entrée dans le champ field_name.\n\n```\nSTDDEV_SAMP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_SAMP(salary) AS stddev FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.subtractOperator.markdown": "### Subtract (infix -)\n```\nSELECT 1 - 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumFunction.markdown": "### SUM\nRetourne la somme des valeurs en entrée dans le champ field_name.\n\n```\nSUM(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT SUM(salary) AS sum FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumofsquaresFunction.markdown": "### SUM_OF_SQUARES\nRetourne la somme des carrés des valeurs en entrée dans le champ field_name.\n\n```\nSUM_OF_SQUARES(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SUM_OF_SQUARES(salary) AS sumsq\n FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.varpopFunction.markdown": "### VAR_POP\nRetourne la variance de population des valeurs en entrée dans le champ field_name.\n\n```\nVAR_POP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_POP(salary) AS varpop FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.varsampFunction.markdown": "### VAR_SAMP\nRetourne la variance de l'échantillon de valeurs en entrée dans le champ field_name.\n\n```\nVAR_SAMP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_SAMP(salary) AS varsamp FROM emp\n```\n ", "unifiedSearch.filter.applyFilterActionTitle": "Appliquer le filtre à la vue en cours", "unifiedSearch.filter.applyFilters.popupHeader": "Sélectionner les filtres à appliquer", "unifiedSearch.filter.applyFiltersPopup.cancelButtonLabel": "Annuler", @@ -5912,6 +5873,67 @@ "unifiedSearch.query.queryBar.searchInputPlaceholderForText": "Filtrer vos données", "unifiedSearch.query.queryBar.syntaxOptionsTitle": "Options de syntaxe", "unifiedSearch.query.queryBar.textBasedLanguagesTechPreviewLabel": "Version d'évaluation technique", + "unifiedSearch.queryBarTopRow.submitButton.refresh": "Actualiser la requête", + "unifiedSearch.queryBarTopRow.submitButton.run": "Exécuter la requête", + "unifiedSearch.queryBarTopRow.submitButton.update": "Nécessite une mise à jour", + "unifiedSearch.search.searchBar.savedQueryDescriptionText": "Enregistrez le texte et les filtres de la requête que vous souhaitez réutiliser.", + "unifiedSearch.search.searchBar.savedQueryForm.titleConflictText": "Ce nom est en conflit avec une requête existante", + "unifiedSearch.search.searchBar.savedQueryForm.titleExistsText": "Un nom est requis.", + "unifiedSearch.search.searchBar.savedQueryFormSaveButtonText": "Enregistrer la requête", + "unifiedSearch.search.searchBar.savedQueryIncludeFiltersLabelText": "Inclure les filtres", + "unifiedSearch.search.searchBar.savedQueryIncludeTimeFilterLabelText": "Inclure le filtre temporel", + "unifiedSearch.search.searchBar.savedQueryNameHelpText": "Le nom ne peut pas contenir d'espace au début ni à la fin, et il doit être unique.", + "unifiedSearch.search.searchBar.savedQueryNameLabelText": "Nom", + "unifiedSearch.search.searchBar.savedQueryNoSavedQueriesText": "Aucune requête enregistrée.", + "unifiedSearch.search.searchBar.savedQueryPopoverApplyFilterSetLabel": "Charger la requête", + "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "Annuler", + "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "Supprimer", + "unifiedSearch.search.searchBar.savedQueryPopoverManageLabel": "Gérer les objets enregistrés", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "Enregistrer en tant que nouvelle requête", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "Enregistrer en tant que nouvelle", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonText": "Mettre à jour la recherche", + "unifiedSearch.switchLanguage.buttonText": "Bouton de changement de langue.", + "unifiedSearch.triggers.updateFilterReferencesTrigger": "Mettre à jour les références de filtre", + "unifiedSearch.triggers.updateFilterReferencesTriggerDescription": "Mettre à jour les références de filtre", + "textBasedEditor.query.textBasedLanguagesEditor.errorCount": "{count} {count, plural, one {erreur} other {erreurs}}", + "textBasedEditor.query.textBasedLanguagesEditor.lineCount": "{count} {count, plural, one {ligne} other {lignes}}", + "textBasedEditor.query.textBasedLanguagesEditor.lineNumber": "Ligne {lineNumber}", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.addOperator.markdown": "### Add (+)\n```\nSELECT 1 + 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.andOperator.markdown": "### AND\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no > 10000 AND emp_no < 10005 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.averageFunction.markdown": "### AVG\nRetourne la moyenne (moyenne arithmétique) des valeurs entrées.\n```\nAVG(numeric_field)\n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n```\nSELECT AVG(salary) AS avg FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.between.markdown": "### Between\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no BETWEEN 9990 AND 10003 ORDER BY emp_no\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.comparison.markdown": "### Comparison (<, <=, >, >=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countAllFunction.markdown": "### Count (All)\nRenvoie le nombre total de toutes les valeurs non nulles en entrée. COUNT() et COUNT(ALL ) sont équivalents.\n\n```\nCOUNT(ALL field_name) \n```\n- nom du champ. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n```\nSELECT COUNT(ALL last_name) AS count_all, COUNT(DISTINCT last_name) count_distinct FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countDistinctFunction.markdown": "### Count (Distinct)\nRenvoie le nombre total de valeurs non nulles distinctes dans les valeurs en entrée.\n\n```\nCOUNT(DISTINCT field_name)\n```\n- Entrée : un nom de champ.\n- Sortie : une valeur numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n```\nSELECT COUNT(DISTINCT hire_date) unique_hires, COUNT(hire_date) AS hires FROM emp\n\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countFunction.markdown": "### Count\nRenvoie le nombre total de valeurs en entrée.\n\n\n```\nCOUNT(expression)\n```\n- expression. Nom de champ, caractère générique (*) ou n'importe quelle valeur numérique. Pour COUNT(*) ou COUNT(), toutes les valeurs sont prises en compte, même celles manquantes ou nulles. Pour COUNT(), les valeurs nulles ne sont pas prises en compte.\n```\nSELECT COUNT(*) AS count FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.divideOperator.markdown": "### Divide (/)\n```\nSELECT 6 / 3 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.equality.markdown": "### Equality (=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no = 10000 LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.firstFunction.markdown": "### FIRST / FIRST_VALUE\nRenvoie la première valeur non nulle (si elle existe) de la colonne d'entrée field_name triée selon la colonne ordering_field_name. Si la valeur ordering_field_name n'est pas fournie, seule la colonne field_name est utilisée pour le tri. \n\n```\nFIRST(\n field_name \n [, ordering_field_name])\n```\n- Nom du champ : champ cible de l'agrégation\n- ordering_field_name : champ facultatif utilisé pour le tri.\n\n```\nSELECT gender, FIRST(first_name, birth_date) FROM emp GROUP BY gender ORDER BY gender\n```\n\n- FIRST ne peut pas être utilisé dans une clause HAVING.\n- FIRST ne peut pas être utilisé avec des colonnes de type texte, sauf si le champ est aussi enregistré comme mot-clé.\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.inequality.markdown": "### Inequality (<> or !=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no <> 10000 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.inOperator.markdown": "### IN (, , ...)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IN (10000, 10001, 10002, 999) ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.kurtosisFunction.markdown": "### KURTOSIS\nQuantifier la forme de la distribution des valeurs en entrée dans le champ field_name.\n\n```\nKURTOSIS(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, KURTOSIS(salary) AS k FROM emp\n```\n\n- KURTOSIS ne peut pas être utilisé en plus des fonctions ou des opérateurs scalaires, uniquement sur un champ. \n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.lastFunction.markdown": "### LAST / LAST_VALUE\nInverse de FIRST/FIRST_VALUE. Renvoie la dernière valeur non nulle (si elle existe) de la colonne d'entrée field_name triée par ordre croissant selon la colonne ordering_field_name. Si la valeur ordering_field_name n'est pas fournie, seule la colonne field_name est utilisée pour le tri. \n\n```\nLAST(\n field_name \n [, ordering_field_name])\n```\n- Nom du champ : champ cible de l'agrégation\n- ordering_field_name : champ facultatif utilisé pour le tri.\n```\nSELECT gender, LAST(first_name) FROM emp GROUP BY gender ORDER BY gender\n```\n- LAST ne peut pas être utilisé dans une clause HAVING.\n- LAST ne peut pas être utilisé avec des colonnes de type texte, sauf si le champ est aussi enregistré comme mot-clé.\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.madFunction.markdown": "### MAD\nMesure la variabilité des valeurs d'entrée dans le champ field_name.\n\n```\nMAD(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, AVG(salary) AS avg, MAD(salary) AS mad FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.markdown": "## À propos d'Elasticsearch SQL\n\nUtilisez Elasticsearch SQL pour rechercher et agréger les données dans Elasticsearch. Ce langage de requête fournit une recherche full text avec une syntaxe connue. Voici un exemple de requête :\n \n```\nSELECT * FROM library \nORDER BY page_count DESC LIMIT 5\n```\n \nElasticsearch SQL :\n\n- Fournit un jeu complet d'opérateurs et de fonctions intégrés.\n- Suit la terminologie et les conventions SQL.\n- Accepte une commande par ligne. Une commande est une séquence de jetons terminée par la fin du flux d'entrée\n \n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.maxFunction.markdown": "### MAX\nRetourne la valeur maximale de toutes les valeurs en entrée dans le champ field_name.\n\n```\nMAX(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MAX(salary) AS max FROM emp\n```\n\n- MAX sur un champ de type texte ou mot-clé est traduit en FIRST/FIRST_VALUE et ne peut donc pas être utilisé dans la clause HAVING.\n\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.minFunction.markdown": "### MIN\nRetourne la valeur minimale de toutes les valeurs en entrée dans le champ field_name.\n\n```\nMIN(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min FROM emp\n```\n\n- MIN sur un champ de type texte ou mot-clé est traduit en FIRST/FIRST_VALUE et ne peut donc pas être utilisé dans la clause HAVING.\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.moduloOperator.markdown": "### Modulo or remainder(%)\n```\nSELECT 5 % 2 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.multiplyOperator.markdown": "### Multiply (*)\n```\nSELECT 2 * 3 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.negateOperator.markdown": "### Negate (unary -)\n```\nSELECT - 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.notOperator.markdown": "### NOT\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE NOT emp_no = 10000 LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullNotNull.markdown": "### IS NULL/IS NOT NULL\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IS NOT NULL AND gender IS NULL\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullSafeEquality.markdown": "### Null safe equality:\n```\nSELECT 'elastic' <=> null AS \"equals\"\n\n égal\n---------------\nfaux\n```\n```\nSELECT null <=> null AS \"equals\"\n\n égal\n---------------\nvrai\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.orOperator.markdown": "### OR\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 OR emp_no = 10005 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileFunction.markdown": "### PERCENTILE\nRetourne le centile n (représenté par le paramètre numeric_exp) des valeurs en entrée dans le champ field_name.\n\n```\nPERCENTILE(\n field_name, \n percentile[, \n method[, \n method_parameter]])\n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n- centile : expression numérique (doit être une constante et ne doit pas être basé sur un champ). Si la valeur est nulle, la fonction renvoie une valeur nulle.\n- method : chaîne littérale facultative pour l'algorithme de centile. Valeurs possibles : tdigest ou hdr. La valeur par défaut est tdigest.\n- method_parameter : numérique littéral facultatif qui configure l'algorithme de centile. Configure la compression pour tdigest ou number_of_significant_value_digits pour hdr. La valeur par défaut est la même que celle de l'algorithme de sauvegarde.\n\n```\nSELECT\n languages,\n PERCENTILE(salary, 97.3, 'tdigest', 100.0) AS \"97.3_TDigest\",\n PERCENTILE(salary, 97.3, 'hdr', 3) AS \"97.3_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileRankFunction.markdown": "### PERCENTILE_RANK\nRetourne le rang centile n (représenté par le paramètre numeric_exp) des valeurs en entrée dans le champ field_name.\n\n```\nPERCENTILE_RANK(\n field_name, \n value[, \n method[, \n method_parameter]]) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n- centile : expression numérique (doit être une constante et ne doit pas être basé sur un champ). Si la valeur est nulle, la fonction renvoie une valeur nulle.\n- method : chaîne littérale facultative pour l'algorithme de centile. Valeurs possibles : tdigest ou hdr. La valeur par défaut est tdigest.\n- method_parameter : numérique littéral facultatif qui configure l'algorithme de centile. Configure la compression pour tdigest ou number_of_significant_value_digits pour hdr. La valeur par défaut est la même que celle de l'algorithme de sauvegarde.\n\n```\nSELECT\n languages,\n ROUND(PERCENTILE_RANK(salary, 65000, 'tdigest', 100.0), 2) AS \"rank_TDigest\",\n ROUND(PERCENTILE_RANK(salary, 65000, 'hdr', 3), 2) AS \"rank_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.skewnessFunction.markdown": "### SKEWNESS\nQuantifier la distribution asymétrique des valeurs en entrée dans le champ field_name.\n\n```\nSKEWNESS(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SKEWNESS(salary) AS s FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevpopFunction.markdown": "### STDDEV_POP\nRetourne l'écart type de population des valeurs en entrée dans le champ field_name.\n\n```\nSTDDEV_POP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_POP(salary) AS stddev FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevsampFunction.markdown": "### STDDEV_SAMP\nRetourne l'écart type de l'échantillon des valeurs en entrée dans le champ field_name.\n\n```\nSTDDEV_SAMP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_SAMP(salary) AS stddev FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.subtractOperator.markdown": "### Subtract (infix -)\n```\nSELECT 1 - 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumFunction.markdown": "### SUM\nRetourne la somme des valeurs en entrée dans le champ field_name.\n\n```\nSUM(field_name) \n```\n- champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT SUM(salary) AS sum FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumofsquaresFunction.markdown": "### SUM_OF_SQUARES\nRetourne la somme des carrés des valeurs en entrée dans le champ field_name.\n\n```\nSUM_OF_SQUARES(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SUM_OF_SQUARES(salary) AS sumsq\n FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.varpopFunction.markdown": "### VAR_POP\nRetourne la variance de population des valeurs en entrée dans le champ field_name.\n\n```\nVAR_POP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_POP(salary) AS varpop FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.varsampFunction.markdown": "### VAR_SAMP\nRetourne la variance de l'échantillon de valeurs en entrée dans le champ field_name.\n\n```\nVAR_SAMP(field_name) \n```\n- field_name : champ numérique. Si ce champ contient uniquement des valeurs nulles, la fonction renvoie zéro. Sinon, la fonction ignore les valeurs nulles dans ce champ.\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_SAMP(salary) AS varsamp FROM emp\n```\n ", "textBasedEditor.query.textBasedLanguagesEditor.aggregateFunctions": "Fonctions agrégées", "textBasedEditor.query.textBasedLanguagesEditor.aggregateFunctionsDocumentationDescription": "Fonctions permettant de calculer un résultat unique à partir d'un ensemble de valeurs d'entrée. Elasticsearch SQL ne prend en charge les fonctions agrégées que parallèlement au regroupement (implicite ou explicite).", "textBasedEditor.query.textBasedLanguagesEditor.comparisonOperators": "Opérateurs de comparaison", @@ -5964,28 +5986,6 @@ "textBasedEditor.query.textBasedLanguagesEditor.MinimizeEditor": "Réduire l'éditeur", "textBasedEditor.query.textBasedLanguagesEditor.minimizeTooltip": "Réduire l’éditeur de requête", "textBasedEditor.query.textBasedLanguagesEditor.runQuery": "Exécuter la requête", - "unifiedSearch.queryBarTopRow.submitButton.refresh": "Actualiser la requête", - "unifiedSearch.queryBarTopRow.submitButton.run": "Exécuter la requête", - "unifiedSearch.queryBarTopRow.submitButton.update": "Nécessite une mise à jour", - "unifiedSearch.search.searchBar.savedQueryDescriptionText": "Enregistrez le texte et les filtres de la requête que vous souhaitez réutiliser.", - "unifiedSearch.search.searchBar.savedQueryForm.titleConflictText": "Ce nom est en conflit avec une requête existante", - "unifiedSearch.search.searchBar.savedQueryForm.titleExistsText": "Un nom est requis.", - "unifiedSearch.search.searchBar.savedQueryFormSaveButtonText": "Enregistrer la requête", - "unifiedSearch.search.searchBar.savedQueryIncludeFiltersLabelText": "Inclure les filtres", - "unifiedSearch.search.searchBar.savedQueryIncludeTimeFilterLabelText": "Inclure le filtre temporel", - "unifiedSearch.search.searchBar.savedQueryNameHelpText": "Le nom ne peut pas contenir d'espace au début ni à la fin, et il doit être unique.", - "unifiedSearch.search.searchBar.savedQueryNameLabelText": "Nom", - "unifiedSearch.search.searchBar.savedQueryNoSavedQueriesText": "Aucune requête enregistrée.", - "unifiedSearch.search.searchBar.savedQueryPopoverApplyFilterSetLabel": "Charger la requête", - "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "Annuler", - "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "Supprimer", - "unifiedSearch.search.searchBar.savedQueryPopoverManageLabel": "Gérer les objets enregistrés", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "Enregistrer en tant que nouvelle requête", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "Enregistrer en tant que nouvelle", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonText": "Mettre à jour la recherche", - "unifiedSearch.switchLanguage.buttonText": "Bouton de changement de langue.", - "unifiedSearch.triggers.updateFilterReferencesTrigger": "Mettre à jour les références de filtre", - "unifiedSearch.triggers.updateFilterReferencesTriggerDescription": "Mettre à jour les références de filtre", "userProfileComponents.userProfilesSelectable.limitReachedMessage": "Vous avez sélectionné la limite maximale de {count, plural, one {# utilisateur} many {# utilisateurs} other {# utilisateurs}}", "userProfileComponents.userProfilesSelectable.selectedStatusMessage": "{count, plural, one {# utilisateur sélectionné} many {# utilisateurs sélectionnés} other {# utilisateurs sélectionnés}}", "userProfileComponents.userProfilesSelectable.clearButtonLabel": "Retirer tous les utilisateurs", @@ -8761,8 +8761,6 @@ "xpack.apm.storageExplorer.summary.dailyDataGeneration": "Génération quotidienne des données", "xpack.apm.storageExplorer.summary.diskSpaceUsedPct": "Espace disque utilisé", "xpack.apm.storageExplorer.summary.diskSpaceUsedPct.tooltip": "Le pourcentage de la capacité de stockage qui est actuellement utilisée par tous les indices APM par rapport à la capacité de stockage maximale actuellement configurée pour Elasticsearch.", - "xpack.apm.storageExplorer.summary.incrementalSize": "Taille APM incrémentielle", - "xpack.apm.storageExplorer.summary.incrementalSize.tooltip": "Taille de stockage estimée par les index APM en fonction des filtres sélectionnés.", "xpack.apm.storageExplorer.summary.indexManagementLink": "Accéder à la gestion des index", "xpack.apm.storageExplorer.summary.numberOfServices": "Nombre de services", "xpack.apm.storageExplorer.summary.serviceInventoryLink": "Accéder à l'inventaire des services", @@ -8780,7 +8778,6 @@ "xpack.apm.storageExplorer.table.samplingColumnDescription": "Nombre de transactions échantillonnées divisé par le rendement total. Cette valeur peut différer du taux d'échantillonnage des transactions configuré car elle peut être affectée par la décision du service initial lors de l'utilisation de l'échantillonnage basé sur la tête ou par un ensemble de politiques lors de l'utilisation de l'échantillonnage basé sur la queue.", "xpack.apm.storageExplorer.table.samplingColumnName": "Taux d'échantillonnage", "xpack.apm.storageExplorer.table.serviceColumnName": "Service", - "xpack.apm.storageExplorerLinkLabel": "Explorateur de stockage", "xpack.apm.technicalPreviewBadgeDescription": "Cette fonctionnalité est en version d'évaluation technique et pourra être modifiée ou retirée complètement dans une future version. Elastic s'efforcera au maximum de corriger tout problème, mais les fonctionnalités en version d'évaluation technique ne sont pas soumises aux accords de niveau de service d'assistance des fonctionnalités officielles en disponibilité générale.", "xpack.apm.technicalPreviewBadgeLabel": "Version d'évaluation technique", "xpack.apm.timeComparison.label": "Comparaison", @@ -11262,7 +11259,6 @@ "xpack.csp.findings.findingsFlyout.overviewTab.ruleTagsTitle": "Balises de règle", "xpack.csp.findings.findingsFlyout.overviewTabTitle": "Aperçu", "xpack.csp.findings.findingsFlyout.paginationLabel": "Navigation de recherche", - "xpack.csp.findings.findingsFlyout.resourceTabTitle": "Ressource", "xpack.csp.findings.findingsFlyout.ruleTab.auditTitle": "Audit", "xpack.csp.findings.findingsFlyout.ruleTab.benchmarkTitle": "Benchmark", "xpack.csp.findings.findingsFlyout.ruleTab.cisSectionTitle": "Section CIS", @@ -11309,8 +11305,6 @@ "xpack.csp.fleetIntegration.integrationNameLabel": "Nom", "xpack.csp.fleetIntegration.integrationSettingsTitle": "Paramètres de l'intégration", "xpack.csp.fleetIntegration.selectIntegrationTypeTitle": "Sélectionner le type d'intégration de gestion du niveau de sécurité du cloud que vous souhaitez configurer", - "xpack.csp.flyout.resource.fieldLabel": "Champ", - "xpack.csp.flyout.resource.fieldValueLabel": "Valeur", "xpack.csp.integrationDashboard.noFindings.promptTitle": "Statut d'évaluation des résultats", "xpack.csp.integrationDashboard.noFindingsPrompt.promptDescription": "En attente de la collecte et de l'indexation des données. Si ce processus prend plus de temps que prévu, veuillez contacter notre support technique", "xpack.csp.kspmIntegration.aksOption.benchmarkTitle": "CIS AKS", @@ -11372,7 +11366,6 @@ "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.dataSource": "Source de données", "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDate": "Date de publication", "xpack.csp.vulnerabilityTable.column.fixVersion": "Version du correctif", - "xpack.csp.vulnerabilityTable.column.packageAndVersion": "Package et version", "xpack.csp.vulnerabilityTable.column.resource": "Ressource", "xpack.csp.vulnerabilityTable.column.severity": "Sévérité", "xpack.csp.vulnerabilityTable.column.vulnerability": "Vulnérabilité", @@ -37723,7 +37716,6 @@ "xpack.triggersActionsUI.checkActionTypeEnabled.actionTypeDisabledByLicenseMessage": "Ce connecteur requiert une licence {minimumLicenseRequired}.", "xpack.triggersActionsUI.checkRuleTypeEnabled.ruleTypeDisabledByLicenseMessage": "Ce type de règle requiert une licence {minimumLicenseRequired}.", "xpack.triggersActionsUI.components.builtinActionTypes.missingSecretsValuesLabel": "Les informations sensibles ne sont pas importées. Veuillez saisir une/des valeur{encryptedFieldsLength, plural, one {} many {s} other {s}} pour le ou les champ{encryptedFieldsLength, plural, one {} many {s} other {s}} suivants {secretFieldsLabel}.", - "xpack.triggersActionsUI.components.buttonGroupField.error.requiredField": "{label} est requis.", "xpack.triggersActionsUI.components.deleteSelectedIdsErrorNotification.descriptionText": "Impossible de supprimer {numErrors, number} {numErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}", "xpack.triggersActionsUI.components.deleteSelectedIdsPartialSuccessNotification.descriptionText": "Suppression effectuée de {numberOfSuccess, number} {numberOfSuccess, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}, {numberOfErrors, number} {numberOfErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}} erreur(s) rencontrée(s)", "xpack.triggersActionsUI.components.deleteSelectedIdsSuccessNotification.descriptionText": "La suppression de {numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}} a été effectuée", @@ -37733,7 +37725,6 @@ "xpack.triggersActionsUI.components.enableSelectedIdsErrorNotification.descriptionText": "Impossible d'activer {numErrors, number} {numErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}", "xpack.triggersActionsUI.components.enableSelectedIdsPartialSuccessNotification.descriptionText": "Activation effectuée de {numberOfSuccess, number} {numberOfSuccess, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}, {numberOfErrors, number} {numberOfErrors, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}} erreur(s) rencontrée(s)", "xpack.triggersActionsUI.components.enableSelectedIdsSuccessNotification.descriptionText": "Activation effectuée de {numSuccesses, number} {numSuccesses, plural, one {{singleTitle}} many {{multipleTitle}} other {{multipleTitle}}}", - "xpack.triggersActionsUI.components.passwordField.error.requiredNameText": "{label} est requis.", "xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesLabel": "Mémorisez votre/vos {encryptedFieldsLength, plural, one {valeur} many {valeurs} other {valeurs}} {secretFieldsLabel}. Vous devrez {encryptedFieldsLength, plural, one {le} many {les} other {les}} entrer à nouveau chaque fois que vous modifierez le connecteur.", "xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesMessage": "La/les valeur{encryptedFieldsLength, plural, one {} many {s} other {s}} {secretFieldsLabel} {encryptedFieldsLength, plural, one {est} many {sont} other {sont}} chiffrée(s). Veuillez entrer à nouveau la/les valeur{encryptedFieldsLength, plural, one {} many {s} other {s}} pour {encryptedFieldsLength, plural, one {ce} many {ces} other {ces}} champ{encryptedFieldsLength, plural, one {} many {s} other {s}}.", "xpack.triggersActionsUI.data.coreQueryParams.aggTypeRequiredErrorMessage": "[aggField] : doit posséder une valeur lorsque [aggType] est \"{aggType}\"", @@ -39777,4 +39768,4 @@ "xpack.painlessLab.title": "Painless Lab", "xpack.painlessLab.walkthroughButtonLabel": "Présentation" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index c555139f778a4..82aebe0112589 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5749,48 +5749,9 @@ "unifiedSearch.query.queryBar.KQLNestedQuerySyntaxInfoText": "ネストされたフィールドをクエリされているようです。ネストされたクエリに対しては、ご希望の結果により異なる方法でKQL構文を構築することができます。{link}で詳細をご覧ください。", "unifiedSearch.query.queryBar.searchInputAriaLabel": "{pageType}ページの検索とフィルタリングを行うには入力を開始してください", "unifiedSearch.query.queryBar.searchInputPlaceholder": "{language}構文を使用してデータをフィルタリング", - "textBasedEditor.query.textBasedLanguagesEditor.errorCount": "{count} {count, plural, other {エラー}}", - "textBasedEditor.query.textBasedLanguagesEditor.lineCount": "{count} {count, plural, other {行}}", - "textBasedEditor.query.textBasedLanguagesEditor.lineNumber": "行{lineNumber}", "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionTitle": "\"{savedQueryName}\"を削除しますか?", "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonAriaLabel": "{title}への変更を保存", "unifiedSearch.search.unableToGetSavedQueryToastTitle": "保存したクエリ{savedQueryId}を読み込めません", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.addOperator.markdown": "### 加算(+)\n```\nSELECT 1 + 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.andOperator.markdown": "### AND\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no > 10000 AND emp_no < 10005 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.averageFunction.markdown": "### AVG\n入力値の平均(算術平均)が返されます。\n```\nAVG(numeric_field)\n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n```\nSELECT AVG(salary) AS avg FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.between.markdown": "### Between\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no BETWEEN 9990 AND 10003 ORDER BY emp_no\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.comparison.markdown": "### 比較(<、<=、>、>=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countAllFunction.markdown": "### Count (All)\nすべてのヌル以外の入力値の合計数(カウント)が返されます。COUNT() and COUNT(ALL ) are equivalent.\n\n```\nCOUNT(ALL field_name) \n```\n- フィールド名。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n```\nSELECT COUNT(ALL last_name) AS count_all, COUNT(DISTINCT last_name) count_distinct FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countDistinctFunction.markdown": "### Count (Distinct)\n入力値の重複しないヌル以外の値の合計数が返されます。\n\n```\nCOUNT(DISTINCT field_name)\n```\n- 入力:フィールド名。\n- 出力:数値。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n```\nSELECT COUNT(DISTINCT hire_date) unique_hires, COUNT(hire_date) AS hires FROM emp\n\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countFunction.markdown": "### Count\n入力値の合計数(カウント)が返されます。\n\n\n```\nCOUNT(式)\n```\n- 式。フィールド名、ワイルドカード(*)、または任意の数値。COUNT(*)またはCOUNT()の場合、ヌルや不足している値を含むすべての値が考慮されます。COUNT()の場合、ヌル値は考慮されません。\n```\nSELECT COUNT(*) AS count FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.divideOperator.markdown": "### 除算(/)\n```\nSELECT 6 / 3 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.equality.markdown": "### 等号(=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no = 10000 LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.firstFunction.markdown": "### FIRST / FIRST_VALUE\nfield_name入力列の最初のヌル以外の値(存在する場合)が、ordering_field_name列でソートされて返されます。ordering_field_nameが指定されていない場合は、field_name列のみがソートで使用されます。\n\n```\nFIRST(\n field_name \n [, ordering_field_name])\n```\n- フィールド名:集計の対象フィールド\n- ordering_field_name:並べ替えで使用される任意のフィールド。\n\n```\nSELECT gender, FIRST(first_name, birth_date) FROM emp GROUP BY gender ORDER BY gender\n```\n\n- FIRSTはHAVING句で使用できません。\n- フィールドがキーワードとして保存されていない場合、FIRSTはテキスト型の列で使用できません。\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.inequality.markdown": "### 不等号(<>または!=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no <> 10000 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.inOperator.markdown": "### IN (, , ...)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IN (10000, 10001, 10002, 999) ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.kurtosisFunction.markdown": "### KURTOSIS\nfield_nameフィールドの入力値の分布の形状を定量化します。\n\n```\nKURTOSIS(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, KURTOSIS(salary) AS k FROM emp\n```\n\n- KURTOSISは、スカラー関数または演算子に対して使用できません。直接フィールドに対してのみ使用できます。 \n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.lastFunction.markdown": "### LAST / LAST_VALUE\nFIRST/FIRST_VALUEの反転です。field_name入力列の最後のヌル以外の値(存在する場合)が、ordering_field_name列で降順にソートされて返されます。ordering_field_nameが指定されていない場合は、field_name列のみがソートで使用されます。 \n\n```\nLAST(\n field_name \n [, ordering_field_name])\n```\n- フィールド名:集計の対象フィールド\n- ordering_field_name:並べ替えで使用される任意のフィールド。\n```\nSELECT gender, LAST(first_name) FROM emp GROUP BY gender ORDER BY gender\n```\n- LASTはHAVING句で使用できません。\n- フィールドがキーワードとして保存されていない場合、LASTはテキスト型の列で使用できません。\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.madFunction.markdown": "### MAD\nfield_nameフィールドの入力値の変化を測定します。\n\n```\nMAD(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, AVG(salary) AS avg, MAD(salary) AS mad FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.markdown": "## Elasticsearch SQLについてさらに詳しく\n\nElasticsearch SQLを使用すると、Elasticsearch内部でデータの検索と集計ができます。このクエリ言語では、使い慣れた構文で全文検索が可能です。クエリの例は次のとおりです。\n \n```\nSELECT * FROM library \nORDER BY page_count DESC LIMIT 5\n```\n \nElasticsearch SQL | \n\n- 演算子と関数の包括的なセットが組み込まれています。\n- SQLの用語と規則に従います。\n- 各行に1つのコマンドを入力できます。コマンドは、入力ストリームの最後に終了する一連の文字です。\n \n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.maxFunction.markdown": "### MAX\nfield_nameフィールドの入力値の最大値が返されます。\n\n```\nMAX(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MAX(salary) AS max FROM emp\n```\n\nテキスト型やキーワード型のフィールドに対するMAXはFIRST/FIRST_VALUEに変換されるため、HAVING句では使用できません。\n\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.minFunction.markdown": "### MIN\nfield_nameフィールドの入力値の最小値が返されます。\n\n```\nMIN(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min FROM emp\n```\n\nテキスト型やキーワード型のフィールドに対するINはFIRST/FIRST_VALUEに変換されるため、HAVING句では使用できません。\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.moduloOperator.markdown": "### Moduloまたは剰余(%)\n```\nSELECT 5 % 2 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.multiplyOperator.markdown": "### 乗算(*)\n```\nSELECT 2 * 3 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.negateOperator.markdown": "### 否定(単項-)\n```\nSELECT - 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.notOperator.markdown": "### NOT\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE NOT emp_no = 10000 LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullNotNull.markdown": "### IS NULL/IS NOT NULL\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IS NOT NULL AND gender IS NULL\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullSafeEquality.markdown": "### Null宇宙船演算子\n```\nSELECT 'elastic' <=> null AS \"equals\"\n\n 一致する\n---------------\nfalse\n```\n```\nSELECT null <=> null AS \"equals\"\n\n 一致する\n---------------\ntrue\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.orOperator.markdown": "### OR\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 OR emp_no = 10005 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileFunction.markdown": "### PERCENTILE\nfield_nameフィールドの入力値の(numeric_expパラメーターで表現された)第nパーセンタイルが返されます。\n\n```\nPERCENTILE(\n field_name, \n percentile[, \n method[, \n method_parameter]])\n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n- percentile : 数式(フィールドに基づくのではなく、定数でなければなりません)。ヌルの場合、ヌルが返されます。\n- method : パーセンタイルアルゴリズムの任意の文字列リテラル。使用可能な値:tdigestまたはhdr。デフォルトはtdigestです。\n- method_parameter:パーセンタイルアルゴリズムを構成する任意の数値リテラル。tdigestの圧縮またはhdrのnumber_of_significant_value_digitsを構成します。デフォルトは、基本のアルゴリズムと同じです。\n\n```\nSELECT\n languages,\n PERCENTILE(salary, 97.3, 'tdigest', 100.0) AS \"97.3_TDigest\",\n PERCENTILE(salary, 97.3, 'hdr', 3) AS \"97.3_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileRankFunction.markdown": "### PERCENTILE_RANK\nfield_nameフィールドの入力値の(numeric_expパラメーターで表現された)第nパーセンタイルランクが返されます。\n\n```\nPERCENTILE_RANK(\n field_name, \n value[, \n method[, \n method_parameter]]) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n- percentile : 数式(フィールドに基づくのではなく、定数でなければなりません)。ヌルの場合、ヌルが返されます。\n- method : パーセンタイルアルゴリズムの任意の文字列リテラル。使用可能な値:tdigestまたはhdr。デフォルトはtdigestです。\n- method_parameter:パーセンタイルアルゴリズムを構成する任意の数値リテラル。tdigestの圧縮またはhdrのnumber_of_significant_value_digitsを構成します。デフォルトは、基本のアルゴリズムと同じです。\n\n```\nSELECT\n languages,\n ROUND(PERCENTILE_RANK(salary, 65000, 'tdigest', 100.0), 2) AS \"rank_TDigest\",\n ROUND(PERCENTILE_RANK(salary, 65000, 'hdr', 3), 2) AS \"rank_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.skewnessFunction.markdown": "### SKEWNESS\nfield_nameフィールドの入力値の非対称分布を定量化します。\n\n```\nSKEWNESS(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SKEWNESS(salary) AS s FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevpopFunction.markdown": "### STDDEV_POP\nfield_nameフィールドの入力値の母標準偏差が返されます。\n\n```\nSTDDEV_POP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_POP(salary) AS stddev FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevsampFunction.markdown": "### STDDEV_SAMP\nfield_nameフィールドの入力値の標本標準偏差が返されます。\n\n```\nSTDDEV_SAMP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_SAMP(salary) AS stddev FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.subtractOperator.markdown": "### 減算(infix -)\n```\nSELECT 1 - 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumFunction.markdown": "### SUM\nfield_nameフィールドの入力値の合計が返されます。\n\n```\nSUM(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT SUM(salary) AS sum FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumofsquaresFunction.markdown": "### SUM_OF_SQUARES\nfield_nameフィールドの入力値の平方根の合計が返されます。\n\n```\nSUM_OF_SQUARES(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SUM_OF_SQUARES(salary) AS sumsq\n FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.varpopFunction.markdown": "### VAR_POP\nfield_nameフィールドの入力値の母分散が返されます。\n\n```\nVAR_POP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_POP(salary) AS varpop FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.varsampFunction.markdown": "### VAR_SAMP\nfield_nameフィールドの入力値の標本分散が返されます。\n\n```\nVAR_SAMP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_SAMP(salary) AS varsamp FROM emp\n```\n ", "unifiedSearch.filter.applyFilterActionTitle": "現在のビューにフィルターを適用", "unifiedSearch.filter.applyFilters.popupHeader": "適用するフィルターの選択", "unifiedSearch.filter.applyFiltersPopup.cancelButtonLabel": "キャンセル", @@ -5913,6 +5874,67 @@ "unifiedSearch.query.queryBar.searchInputPlaceholderForText": "データのフィルタリング", "unifiedSearch.query.queryBar.syntaxOptionsTitle": "構文オプション", "unifiedSearch.query.queryBar.textBasedLanguagesTechPreviewLabel": "テクニカルプレビュー", + "unifiedSearch.queryBarTopRow.submitButton.refresh": "クエリの更新", + "unifiedSearch.queryBarTopRow.submitButton.run": "クエリを実行", + "unifiedSearch.queryBarTopRow.submitButton.update": "更新が必要です", + "unifiedSearch.search.searchBar.savedQueryDescriptionText": "再度使用するクエリテキストとフィルターを保存します。", + "unifiedSearch.search.searchBar.savedQueryForm.titleConflictText": "名前が既存のクエリと競合しています", + "unifiedSearch.search.searchBar.savedQueryForm.titleExistsText": "名前が必要です。", + "unifiedSearch.search.searchBar.savedQueryFormSaveButtonText": "クエリを保存", + "unifiedSearch.search.searchBar.savedQueryIncludeFiltersLabelText": "フィルターを含める", + "unifiedSearch.search.searchBar.savedQueryIncludeTimeFilterLabelText": "時間フィルターを含める", + "unifiedSearch.search.searchBar.savedQueryNameHelpText": "名前の始めと終わりにはスペースを使用できません。名前は一意でなければなりません。", + "unifiedSearch.search.searchBar.savedQueryNameLabelText": "名前", + "unifiedSearch.search.searchBar.savedQueryNoSavedQueriesText": "保存されたクエリがありません。", + "unifiedSearch.search.searchBar.savedQueryPopoverApplyFilterSetLabel": "クエリを読み込む", + "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "キャンセル", + "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "削除", + "unifiedSearch.search.searchBar.savedQueryPopoverManageLabel": "保存されたオブジェクトを管理", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "新しいクエリとして保存", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "新規保存", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonText": "クエリの更新", + "unifiedSearch.switchLanguage.buttonText": "言語の切り替えボタン。", + "unifiedSearch.triggers.updateFilterReferencesTrigger": "フィルター参照を更新", + "unifiedSearch.triggers.updateFilterReferencesTriggerDescription": "フィルター参照を更新", + "textBasedEditor.query.textBasedLanguagesEditor.errorCount": "{count} {count, plural, other {エラー}}", + "textBasedEditor.query.textBasedLanguagesEditor.lineCount": "{count} {count, plural, other {行}}", + "textBasedEditor.query.textBasedLanguagesEditor.lineNumber": "行{lineNumber}", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.addOperator.markdown": "### 加算(+)\n```\nSELECT 1 + 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.andOperator.markdown": "### AND\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no > 10000 AND emp_no < 10005 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.averageFunction.markdown": "### AVG\n入力値の平均(算術平均)が返されます。\n```\nAVG(numeric_field)\n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n```\nSELECT AVG(salary) AS avg FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.between.markdown": "### Between\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no BETWEEN 9990 AND 10003 ORDER BY emp_no\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.comparison.markdown": "### 比較(<、<=、>、>=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countAllFunction.markdown": "### Count (All)\nすべてのヌル以外の入力値の合計数(カウント)が返されます。COUNT() and COUNT(ALL ) are equivalent.\n\n```\nCOUNT(ALL field_name) \n```\n- フィールド名。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n```\nSELECT COUNT(ALL last_name) AS count_all, COUNT(DISTINCT last_name) count_distinct FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countDistinctFunction.markdown": "### Count (Distinct)\n入力値の重複しないヌル以外の値の合計数が返されます。\n\n```\nCOUNT(DISTINCT field_name)\n```\n- 入力:フィールド名。\n- 出力:数値。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n```\nSELECT COUNT(DISTINCT hire_date) unique_hires, COUNT(hire_date) AS hires FROM emp\n\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countFunction.markdown": "### Count\n入力値の合計数(カウント)が返されます。\n\n\n```\nCOUNT(式)\n```\n- 式。フィールド名、ワイルドカード(*)、または任意の数値。COUNT(*)またはCOUNT()の場合、ヌルや不足している値を含むすべての値が考慮されます。COUNT()の場合、ヌル値は考慮されません。\n```\nSELECT COUNT(*) AS count FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.divideOperator.markdown": "### 除算(/)\n```\nSELECT 6 / 3 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.equality.markdown": "### 等号(=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no = 10000 LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.firstFunction.markdown": "### FIRST / FIRST_VALUE\nfield_name入力列の最初のヌル以外の値(存在する場合)が、ordering_field_name列でソートされて返されます。ordering_field_nameが指定されていない場合は、field_name列のみがソートで使用されます。\n\n```\nFIRST(\n field_name \n [, ordering_field_name])\n```\n- フィールド名:集計の対象フィールド\n- ordering_field_name:並べ替えで使用される任意のフィールド。\n\n```\nSELECT gender, FIRST(first_name, birth_date) FROM emp GROUP BY gender ORDER BY gender\n```\n\n- FIRSTはHAVING句で使用できません。\n- フィールドがキーワードとして保存されていない場合、FIRSTはテキスト型の列で使用できません。\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.inequality.markdown": "### 不等号(<>または!=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no <> 10000 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.inOperator.markdown": "### IN (, , ...)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IN (10000, 10001, 10002, 999) ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.kurtosisFunction.markdown": "### KURTOSIS\nfield_nameフィールドの入力値の分布の形状を定量化します。\n\n```\nKURTOSIS(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, KURTOSIS(salary) AS k FROM emp\n```\n\n- KURTOSISは、スカラー関数または演算子に対して使用できません。直接フィールドに対してのみ使用できます。 \n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.lastFunction.markdown": "### LAST / LAST_VALUE\nFIRST/FIRST_VALUEの反転です。field_name入力列の最後のヌル以外の値(存在する場合)が、ordering_field_name列で降順にソートされて返されます。ordering_field_nameが指定されていない場合は、field_name列のみがソートで使用されます。 \n\n```\nLAST(\n field_name \n [, ordering_field_name])\n```\n- フィールド名:集計の対象フィールド\n- ordering_field_name:並べ替えで使用される任意のフィールド。\n```\nSELECT gender, LAST(first_name) FROM emp GROUP BY gender ORDER BY gender\n```\n- LASTはHAVING句で使用できません。\n- フィールドがキーワードとして保存されていない場合、LASTはテキスト型の列で使用できません。\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.madFunction.markdown": "### MAD\nfield_nameフィールドの入力値の変化を測定します。\n\n```\nMAD(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, AVG(salary) AS avg, MAD(salary) AS mad FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.markdown": "## Elasticsearch SQLについてさらに詳しく\n\nElasticsearch SQLを使用すると、Elasticsearch内部でデータの検索と集計ができます。このクエリ言語では、使い慣れた構文で全文検索が可能です。クエリの例は次のとおりです。\n \n```\nSELECT * FROM library \nORDER BY page_count DESC LIMIT 5\n```\n \nElasticsearch SQL | \n\n- 演算子と関数の包括的なセットが組み込まれています。\n- SQLの用語と規則に従います。\n- 各行に1つのコマンドを入力できます。コマンドは、入力ストリームの最後に終了する一連の文字です。\n \n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.maxFunction.markdown": "### MAX\nfield_nameフィールドの入力値の最大値が返されます。\n\n```\nMAX(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MAX(salary) AS max FROM emp\n```\n\nテキスト型やキーワード型のフィールドに対するMAXはFIRST/FIRST_VALUEに変換されるため、HAVING句では使用できません。\n\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.minFunction.markdown": "### MIN\nfield_nameフィールドの入力値の最小値が返されます。\n\n```\nMIN(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min FROM emp\n```\n\nテキスト型やキーワード型のフィールドに対するINはFIRST/FIRST_VALUEに変換されるため、HAVING句では使用できません。\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.moduloOperator.markdown": "### Moduloまたは剰余(%)\n```\nSELECT 5 % 2 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.multiplyOperator.markdown": "### 乗算(*)\n```\nSELECT 2 * 3 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.negateOperator.markdown": "### 否定(単項-)\n```\nSELECT - 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.notOperator.markdown": "### NOT\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE NOT emp_no = 10000 LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullNotNull.markdown": "### IS NULL/IS NOT NULL\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IS NOT NULL AND gender IS NULL\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullSafeEquality.markdown": "### Null宇宙船演算子\n```\nSELECT 'elastic' <=> null AS \"equals\"\n\n 一致する\n---------------\nfalse\n```\n```\nSELECT null <=> null AS \"equals\"\n\n 一致する\n---------------\ntrue\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.orOperator.markdown": "### OR\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 OR emp_no = 10005 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileFunction.markdown": "### PERCENTILE\nfield_nameフィールドの入力値の(numeric_expパラメーターで表現された)第nパーセンタイルが返されます。\n\n```\nPERCENTILE(\n field_name, \n percentile[, \n method[, \n method_parameter]])\n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n- percentile : 数式(フィールドに基づくのではなく、定数でなければなりません)。ヌルの場合、ヌルが返されます。\n- method : パーセンタイルアルゴリズムの任意の文字列リテラル。使用可能な値:tdigestまたはhdr。デフォルトはtdigestです。\n- method_parameter:パーセンタイルアルゴリズムを構成する任意の数値リテラル。tdigestの圧縮またはhdrのnumber_of_significant_value_digitsを構成します。デフォルトは、基本のアルゴリズムと同じです。\n\n```\nSELECT\n languages,\n PERCENTILE(salary, 97.3, 'tdigest', 100.0) AS \"97.3_TDigest\",\n PERCENTILE(salary, 97.3, 'hdr', 3) AS \"97.3_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileRankFunction.markdown": "### PERCENTILE_RANK\nfield_nameフィールドの入力値の(numeric_expパラメーターで表現された)第nパーセンタイルランクが返されます。\n\n```\nPERCENTILE_RANK(\n field_name, \n value[, \n method[, \n method_parameter]]) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n- percentile : 数式(フィールドに基づくのではなく、定数でなければなりません)。ヌルの場合、ヌルが返されます。\n- method : パーセンタイルアルゴリズムの任意の文字列リテラル。使用可能な値:tdigestまたはhdr。デフォルトはtdigestです。\n- method_parameter:パーセンタイルアルゴリズムを構成する任意の数値リテラル。tdigestの圧縮またはhdrのnumber_of_significant_value_digitsを構成します。デフォルトは、基本のアルゴリズムと同じです。\n\n```\nSELECT\n languages,\n ROUND(PERCENTILE_RANK(salary, 65000, 'tdigest', 100.0), 2) AS \"rank_TDigest\",\n ROUND(PERCENTILE_RANK(salary, 65000, 'hdr', 3), 2) AS \"rank_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.skewnessFunction.markdown": "### SKEWNESS\nfield_nameフィールドの入力値の非対称分布を定量化します。\n\n```\nSKEWNESS(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SKEWNESS(salary) AS s FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevpopFunction.markdown": "### STDDEV_POP\nfield_nameフィールドの入力値の母標準偏差が返されます。\n\n```\nSTDDEV_POP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_POP(salary) AS stddev FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevsampFunction.markdown": "### STDDEV_SAMP\nfield_nameフィールドの入力値の標本標準偏差が返されます。\n\n```\nSTDDEV_SAMP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_SAMP(salary) AS stddev FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.subtractOperator.markdown": "### 減算(infix -)\n```\nSELECT 1 - 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumFunction.markdown": "### SUM\nfield_nameフィールドの入力値の合計が返されます。\n\n```\nSUM(field_name) \n```\n- 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT SUM(salary) AS sum FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumofsquaresFunction.markdown": "### SUM_OF_SQUARES\nfield_nameフィールドの入力値の平方根の合計が返されます。\n\n```\nSUM_OF_SQUARES(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SUM_OF_SQUARES(salary) AS sumsq\n FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.varpopFunction.markdown": "### VAR_POP\nfield_nameフィールドの入力値の母分散が返されます。\n\n```\nVAR_POP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_POP(salary) AS varpop FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.varsampFunction.markdown": "### VAR_SAMP\nfield_nameフィールドの入力値の標本分散が返されます。\n\n```\nVAR_SAMP(field_name) \n```\n- field_name : 数値フィールド。このフィールドにヌル値のみが入力されている場合、関数によってヌルが返されます。そうでない場合は、このフィールドのヌル値は無視されます。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_SAMP(salary) AS varsamp FROM emp\n```\n ", "textBasedEditor.query.textBasedLanguagesEditor.aggregateFunctions": "集計関数", "textBasedEditor.query.textBasedLanguagesEditor.aggregateFunctionsDocumentationDescription": "複数の入力値のセットから単一の結果を計算するための関数。Elasticsearch SQLでは、集計関数は(明示的または暗黙的な)グループ化を行った場合にのみ使用できます。", "textBasedEditor.query.textBasedLanguagesEditor.comparisonOperators": "比較演算子", @@ -5965,28 +5987,6 @@ "textBasedEditor.query.textBasedLanguagesEditor.MinimizeEditor": "エディターを最小化", "textBasedEditor.query.textBasedLanguagesEditor.minimizeTooltip": "クエリエディターを縮小", "textBasedEditor.query.textBasedLanguagesEditor.runQuery": "クエリを実行", - "unifiedSearch.queryBarTopRow.submitButton.refresh": "クエリの更新", - "unifiedSearch.queryBarTopRow.submitButton.run": "クエリを実行", - "unifiedSearch.queryBarTopRow.submitButton.update": "更新が必要です", - "unifiedSearch.search.searchBar.savedQueryDescriptionText": "再度使用するクエリテキストとフィルターを保存します。", - "unifiedSearch.search.searchBar.savedQueryForm.titleConflictText": "名前が既存のクエリと競合しています", - "unifiedSearch.search.searchBar.savedQueryForm.titleExistsText": "名前が必要です。", - "unifiedSearch.search.searchBar.savedQueryFormSaveButtonText": "クエリを保存", - "unifiedSearch.search.searchBar.savedQueryIncludeFiltersLabelText": "フィルターを含める", - "unifiedSearch.search.searchBar.savedQueryIncludeTimeFilterLabelText": "時間フィルターを含める", - "unifiedSearch.search.searchBar.savedQueryNameHelpText": "名前の始めと終わりにはスペースを使用できません。名前は一意でなければなりません。", - "unifiedSearch.search.searchBar.savedQueryNameLabelText": "名前", - "unifiedSearch.search.searchBar.savedQueryNoSavedQueriesText": "保存されたクエリがありません。", - "unifiedSearch.search.searchBar.savedQueryPopoverApplyFilterSetLabel": "クエリを読み込む", - "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "キャンセル", - "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "削除", - "unifiedSearch.search.searchBar.savedQueryPopoverManageLabel": "保存されたオブジェクトを管理", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "新しいクエリとして保存", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "新規保存", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonText": "クエリの更新", - "unifiedSearch.switchLanguage.buttonText": "言語の切り替えボタン。", - "unifiedSearch.triggers.updateFilterReferencesTrigger": "フィルター参照を更新", - "unifiedSearch.triggers.updateFilterReferencesTriggerDescription": "フィルター参照を更新", "userProfileComponents.userProfilesSelectable.limitReachedMessage": "{count, plural, other {#人のユーザー}}の最大数を選択しました", "userProfileComponents.userProfilesSelectable.selectedStatusMessage": "{count, plural, other {#人のユーザーが選択されました}}", "userProfileComponents.userProfilesSelectable.clearButtonLabel": "すべてのユーザーを削除", @@ -8761,8 +8761,6 @@ "xpack.apm.storageExplorer.summary.dailyDataGeneration": "日次データ生成", "xpack.apm.storageExplorer.summary.diskSpaceUsedPct": "使用済みディスク容量", "xpack.apm.storageExplorer.summary.diskSpaceUsedPct.tooltip": "現在Elasticsearch用に構成されている最大ストレージ容量と比較した、現在すべてのAPMインデックスで使用されているストレージ容量の割合。", - "xpack.apm.storageExplorer.summary.incrementalSize": "増分APMサイズ", - "xpack.apm.storageExplorer.summary.incrementalSize.tooltip": "選択したフィルターに基づく、APMインデックスで使用されている推定ストレージサイズ。", "xpack.apm.storageExplorer.summary.indexManagementLink": "インデックス管理に移動", "xpack.apm.storageExplorer.summary.numberOfServices": "サービスの数", "xpack.apm.storageExplorer.summary.serviceInventoryLink": "サービスインベントリに移動", @@ -8780,7 +8778,6 @@ "xpack.apm.storageExplorer.table.samplingColumnDescription": "合計スループットで除算された、抽出されたトランザクションの数。この値は、ヘッドベースのサンプリングを使用するときの初期サービスの決定、またはテイルベースのサンプリングを使用するときのポリシー群によって影響を受ける可能性があるため、構成されたトランザクションサンプルレートとは異なる場合があります。", "xpack.apm.storageExplorer.table.samplingColumnName": "サンプルレート", "xpack.apm.storageExplorer.table.serviceColumnName": "サービス", - "xpack.apm.storageExplorerLinkLabel": "ストレージエクスプローラー", "xpack.apm.technicalPreviewBadgeDescription": "この機能はテクニカルプレビュー中であり、将来のリリースでは変更されたり完全に削除されたりする場合があります。Elasticは最善の努力を講じてすべての問題の修正に努めますが、テクニカルプレビュー中の機能には正式なGA機能のサポートSLAが適用されません。", "xpack.apm.technicalPreviewBadgeLabel": "テクニカルプレビュー", "xpack.apm.timeComparison.label": "比較", @@ -11262,7 +11259,6 @@ "xpack.csp.findings.findingsFlyout.overviewTab.ruleTagsTitle": "ルールタグ", "xpack.csp.findings.findingsFlyout.overviewTabTitle": "概要", "xpack.csp.findings.findingsFlyout.paginationLabel": "ナビゲーションを検索中", - "xpack.csp.findings.findingsFlyout.resourceTabTitle": "リソース", "xpack.csp.findings.findingsFlyout.ruleTab.auditTitle": "監査", "xpack.csp.findings.findingsFlyout.ruleTab.benchmarkTitle": "ベンチマーク", "xpack.csp.findings.findingsFlyout.ruleTab.cisSectionTitle": "CISセクション", @@ -11309,8 +11305,6 @@ "xpack.csp.fleetIntegration.integrationNameLabel": "名前", "xpack.csp.fleetIntegration.integrationSettingsTitle": "統合設定", "xpack.csp.fleetIntegration.selectIntegrationTypeTitle": "構成するセキュリティ態勢管理統合のタイプを選択", - "xpack.csp.flyout.resource.fieldLabel": "フィールド", - "xpack.csp.flyout.resource.fieldValueLabel": "値", "xpack.csp.integrationDashboard.noFindings.promptTitle": "調査結果評価ステータス", "xpack.csp.integrationDashboard.noFindingsPrompt.promptDescription": "データの収集とインデックス作成を待機しています。このプロセスに想定よりも時間がかかる場合は、サポートまでお問い合わせください", "xpack.csp.kspmIntegration.aksOption.benchmarkTitle": "CIS AKS", @@ -11372,7 +11366,6 @@ "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.dataSource": "データソース", "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDate": "公開日", "xpack.csp.vulnerabilityTable.column.fixVersion": "修正バージョン", - "xpack.csp.vulnerabilityTable.column.packageAndVersion": "パッケージとバージョン", "xpack.csp.vulnerabilityTable.column.resource": "リソース", "xpack.csp.vulnerabilityTable.column.severity": "深刻度", "xpack.csp.vulnerabilityTable.column.vulnerability": "脆弱性", @@ -37704,8 +37697,6 @@ "xpack.triggersActionsUI.checkActionTypeEnabled.actionTypeDisabledByLicenseMessage": "このコネクターには{minimumLicenseRequired}ライセンスが必要です。", "xpack.triggersActionsUI.checkRuleTypeEnabled.ruleTypeDisabledByLicenseMessage": "このルールタイプには{minimumLicenseRequired}ライセンスが必要です。", "xpack.triggersActionsUI.components.builtinActionTypes.missingSecretsValuesLabel": "機密情報はインポートされません。次のフィールド{encryptedFieldsLength, plural, other {s}}{secretFieldsLabel}の値{encryptedFieldsLength, plural, other {s}}を入力してください。", - "xpack.triggersActionsUI.components.buttonGroupField.error.requiredField": "{label}は必須です。", - "xpack.triggersActionsUI.components.passwordField.error.requiredNameText": "{label}は必須です。", "xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesLabel": "{secretFieldsLabel} {encryptedFieldsLength, plural, other {値}}を記憶しておいてください。コネクターを編集するたびに、{encryptedFieldsLength, plural, other {それらを}}再入力する必要があります。", "xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesMessage": "値{encryptedFieldsLength, plural, other {s}}{secretFieldsLabel}{encryptedFieldsLength, plural, other {あります}}暗号化されました。{encryptedFieldsLength, plural, other {これらの}}フィールド{encryptedFieldsLength, plural, other {s}}の値{encryptedFieldsLength, plural, other {s}}を再入力してください。", "xpack.triggersActionsUI.data.coreQueryParams.aggTypeRequiredErrorMessage": "[aggType]が\"{aggType}\"のときには[aggField]に値が必要です", @@ -39747,4 +39738,4 @@ "xpack.painlessLab.title": "Painless Lab", "xpack.painlessLab.walkthroughButtonLabel": "実地検証" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e60befbaed231..1e4bec4f2bdd9 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5748,48 +5748,9 @@ "unifiedSearch.query.queryBar.KQLNestedQuerySyntaxInfoText": "似乎您正在查询嵌套字段。您可以使用不同的方式构造嵌套查询的 KQL 语法,具体取决于您想要的结果。详细了解我们的 {link}。", "unifiedSearch.query.queryBar.searchInputAriaLabel": "开始键入内容,以搜索并筛选 {pageType} 页面", "unifiedSearch.query.queryBar.searchInputPlaceholder": "使用 {language} 语法筛选数据", - "textBasedEditor.query.textBasedLanguagesEditor.errorCount": "{count} 个{count, plural, other {错误}}", - "textBasedEditor.query.textBasedLanguagesEditor.lineCount": "{count} {count, plural, other {行}}", - "textBasedEditor.query.textBasedLanguagesEditor.lineNumber": "第 {lineNumber} 行", "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionTitle": "删除“{savedQueryName}”?", "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonAriaLabel": "将更改保存到 {title}", "unifiedSearch.search.unableToGetSavedQueryToastTitle": "无法加载已保存查询 {savedQueryId}", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.addOperator.markdown": "### Add (+)\n```\nSELECT 1 + 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.andOperator.markdown": "### AND\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no > 10000 AND emp_no < 10005 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.averageFunction.markdown": "### AVG\n返回输入值的算术平均值。\n```\nAVG(numeric_field)\n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n```\nSELECT AVG(salary) AS avg FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.between.markdown": "### Between\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no BETWEEN 9990 AND 10003 ORDER BY emp_no\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.comparison.markdown": "### Comparison (<, <=, >, >=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countAllFunction.markdown": "### Count (All)\n返回所有非 null 输入值的总数(计数)。COUNT() 与 COUNT(ALL ) 等价。\n\n```\nCOUNT(ALL field_name) \n```\n- 字段名称。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n```\nSELECT COUNT(ALL last_name) AS count_all, COUNT(DISTINCT last_name) count_distinct FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countDistinctFunction.markdown": "### Count (Distinct)\n返回输入值中的不同非 null 值的总数。\n\n```\nCOUNT(DISTINCT field_name)\n```\n- 输入:字段名称。\n- 输出:数字值。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n```\nSELECT COUNT(DISTINCT hire_date) unique_hires, COUNT(hire_date) AS hires FROM emp\n\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.countFunction.markdown": "### Count\n返回输入值的总数(计数)。\n\n\n```\nCOUNT(expression)\n```\n- 表达式为字段名称、通配符 (*) 或任何数字值。对于 COUNT(*) 或 COUNT(),将考虑所有值,包括 null 或缺失的值。对于 COUNT(),将不考虑 null 值。\n```\nSELECT COUNT(*) AS count FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.divideOperator.markdown": "### Divide (/)\n```\nSELECT 6 / 3 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.equality.markdown": "### Equality (=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no = 10000 LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.firstFunction.markdown": "### FIRST / FIRST_VALUE\n返回按 ordering_field_name 列排序的 field_name 输入列中的第一个非 null 值(如果存在)。如果未提供 ordering_field_name,则仅 field_name 列用于排序。\n\n```\nFIRST(\n field_name \n [, ordering_field_name])\n```\n- 字段名称:用于聚合的目标字段\n- ordering_field_name:用于排序的可选字段。\n\n```\nSELECT gender, FIRST(first_name, birth_date) FROM emp GROUP BY gender ORDER BY gender\n```\n\n- FIRST 不能用在 HAVING 子句中。\n- FIRST 不能用于文本类型的列,除非也将该字段另存为关键字。\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.inequality.markdown": "### Inequality (<> or !=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no <> 10000 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.inOperator.markdown": "### IN (, , ...)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IN (10000, 10001, 10002, 999) ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.kurtosisFunction.markdown": "### KURTOSIS\n量化字段 field_name 中输入值的分布形状。\n\n```\nKURTOSIS(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, KURTOSIS(salary) AS k FROM emp\n```\n\n- KURTOSIS 不能用于标量函数或运算符上面,而只能直接用于字段。 \n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.lastFunction.markdown": "### LAST / LAST_VALUE\n这是 FIRST/FIRST_VALUE 的反向函数。返回按 ordering_field_name 列降序排序的 field_name 输入列中的最后一个非 null 值(如果存在)。如果未提供 ordering_field_name,则仅 field_name 列用于排序。 \n\n```\nLAST(\n field_name \n [, ordering_field_name])\n```\n- 字段名称:用于聚合的目标字段\n- ordering_field_name:用于排序的可选字段。\n```\nSELECT gender, LAST(first_name) FROM emp GROUP BY gender ORDER BY gender\n```\n- LAST 不能用在 HAVING 子句中。\n- LAST 不能用于文本类型的列,除非也将该字段另存为关键字。\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.madFunction.markdown": "### MAD\n衡量字段 field_name 中输入值的可变性。\n\n```\nMAD(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, AVG(salary) AS avg, MAD(salary) AS mad FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.markdown": "## 关于 Elasticsearch SQL\n\n使用 Elasticsearch SQL 在 Elasticsearch 内部搜索并聚合数据。此查询语言通过熟悉的语法提供了全文本搜索。这里提供了一个查询示例:\n \n```\nSELECT * FROM library \nORDER BY page_count DESC LIMIT 5\n```\n \nElasticsearch SQL:\n\n- 提供了一组全面的内置运算符和函数。\n- 遵循 SQL 术语和约定。\n- 每行接受一个命令。命令指通过结束输入流终止的一连串令牌\n \n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.maxFunction.markdown": "### MAX\n返回字段 field_name 中所有输入值的最大值。\n\n```\nMAX(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MAX(salary) AS max FROM emp\n```\n\n- 类型为文本或关键字的字段的 MAX 将转换为 FIRST/FIRST_VALUE,因此不能用在 HAVING 子句中。\n\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.minFunction.markdown": "### MIN\n返回字段 field_name 中所有输入值的最小值。\n\n```\nMIN(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min FROM emp\n```\n\n- 类型为文本或关键字的字段的 MIN 将转换为 FIRST/FIRST_VALUE,因此不能用在 HAVING 子句中。\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.moduloOperator.markdown": "### Modulo or remainder(%)\n```\nSELECT 5 % 2 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.multiplyOperator.markdown": "### Multiply (*)\n```\nSELECT 2 * 3 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.negateOperator.markdown": "### Negate (unary -)\n```\nSELECT - 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.notOperator.markdown": "### NOT\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE NOT emp_no = 10000 LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullNotNull.markdown": "### IS NULL/IS NOT NULL\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IS NOT NULL AND gender IS NULL\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullSafeEquality.markdown": "### Null safe equality:\n```\nSELECT 'elastic' <=> null AS \"equals\"\n\n 等于\n---------------\nfalse\n```\n```\nSELECT null <=> null AS \"equals\"\n\n 等于\n---------------\ntrue\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.orOperator.markdown": "### OR\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 OR emp_no = 10005 ORDER BY emp_no LIMIT 5\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileFunction.markdown": "### PERCENTILE\n返回字段 field_name 中输入值的第 n 个百分位(用 numeric_exp 参数表示)。\n\n```\nPERCENTILE(\n field_name, \n percentile[, \n method[, \n method_parameter]])\n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n- 百分位数:数字表达式(必须为常数并且不得基于字段)。如果为 null,该函数将返回 null。\n- 方法:百分位数算法的可选字符串文本。可能的值:tdigest 或 hdr。默认值为 tdigest。\n- method_parameter:配置百分位数算法的可选数字文本。为 tdigest 配置表达式,或为 hdr 配置 number_of_significant_value_digits。默认值与后备算法的默认值相同。\n\n```\n精选\n languages,\n PERCENTILE(salary, 97.3, 'tdigest', 100.0) AS \"97.3_TDigest\",\n PERCENTILE(salary, 97.3, 'hdr', 3) AS \"97.3_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileRankFunction.markdown": "### PERCENTILE_RANK\n返回字段 field_name 中输入值的第 n 个百分位等级(用 numeric_exp 参数表示)。\n\n```\nPERCENTILE_RANK(\n field_name, \n value[, \n method[, \n method_parameter]]) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n- 百分位数:数字表达式(必须为常数并且不得基于字段)。如果为 null,该函数将返回 null。\n- 方法:百分位数算法的可选字符串文本。可能的值:tdigest 或 hdr。默认值为 tdigest。\n- method_parameter:配置百分位数算法的可选数字文本。为 tdigest 配置表达式,或为 hdr 配置 number_of_significant_value_digits。默认值与后备算法的默认值相同。\n\n```\n精选\n languages,\n ROUND(PERCENTILE_RANK(salary, 65000, 'tdigest', 100.0), 2) AS \"rank_TDigest\",\n ROUND(PERCENTILE_RANK(salary, 65000, 'hdr', 3), 2) AS \"rank_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.skewnessFunction.markdown": "### SKEWNESS\n量化字段 field_name 中输入值的非对称分布。\n\n```\nSKEWNESS(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SKEWNESS(salary) AS s FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevpopFunction.markdown": "### STDDEV_POP\n返回字段 field_name 中输入值的填充标准偏差。\n\n```\nSTDDEV_POP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_POP(salary) AS stddev FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevsampFunction.markdown": "### STDDEV_SAMP\n返回字段 field_name 中输入值的样例标准偏差。\n\n```\nSTDDEV_SAMP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_SAMP(salary) AS stddev FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.subtractOperator.markdown": "### Subtract (infix -)\n```\nSELECT 1 - 1 AS x\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumFunction.markdown": "### SUM\n返回字段 field_name 中所有输入值的总和。\n\n```\nSUM(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT SUM(salary) AS sum FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumofsquaresFunction.markdown": "### SUM_OF_SQUARES\n返回字段 field_name 中输入值的平方和。\n\n```\nSUM_OF_SQUARES(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SUM_OF_SQUARES(salary) AS sumsq\n FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.varpopFunction.markdown": "### VAR_POP\n返回字段 field_name 中输入值的总体方差。\n\n```\nVAR_POP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_POP(salary) AS varpop FROM emp\n```\n ", - "textBasedEditor.query.textBasedLanguagesEditor.documentation.varsampFunction.markdown": "### VAR_SAMP\n返回字段 field_name 中输入值的样例方差。\n\n```\nVAR_SAMP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_SAMP(salary) AS varsamp FROM emp\n```\n ", "unifiedSearch.filter.applyFilterActionTitle": "将筛选应用于当前视图", "unifiedSearch.filter.applyFilters.popupHeader": "选择要应用的筛选", "unifiedSearch.filter.applyFiltersPopup.cancelButtonLabel": "取消", @@ -5912,6 +5873,67 @@ "unifiedSearch.query.queryBar.searchInputPlaceholderForText": "筛选您的数据", "unifiedSearch.query.queryBar.syntaxOptionsTitle": "语法选项", "unifiedSearch.query.queryBar.textBasedLanguagesTechPreviewLabel": "技术预览", + "unifiedSearch.queryBarTopRow.submitButton.refresh": "刷新查询", + "unifiedSearch.queryBarTopRow.submitButton.run": "运行查询", + "unifiedSearch.queryBarTopRow.submitButton.update": "需要更新", + "unifiedSearch.search.searchBar.savedQueryDescriptionText": "保存想要再次使用的查询文本和筛选。", + "unifiedSearch.search.searchBar.savedQueryForm.titleConflictText": "名称与现有查询有冲突", + "unifiedSearch.search.searchBar.savedQueryForm.titleExistsText": "“名称”必填。", + "unifiedSearch.search.searchBar.savedQueryFormSaveButtonText": "保存查询", + "unifiedSearch.search.searchBar.savedQueryIncludeFiltersLabelText": "包括筛选", + "unifiedSearch.search.searchBar.savedQueryIncludeTimeFilterLabelText": "包括时间筛选", + "unifiedSearch.search.searchBar.savedQueryNameHelpText": "名称不能包含前导或尾随空格,并且必须唯一。", + "unifiedSearch.search.searchBar.savedQueryNameLabelText": "名称", + "unifiedSearch.search.searchBar.savedQueryNoSavedQueriesText": "无已保存查询。", + "unifiedSearch.search.searchBar.savedQueryPopoverApplyFilterSetLabel": "加载查询", + "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "取消", + "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "删除", + "unifiedSearch.search.searchBar.savedQueryPopoverManageLabel": "管理已保存对象", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "另存为新查询", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "另存为新的", + "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonText": "更新查询", + "unifiedSearch.switchLanguage.buttonText": "切换语言按钮。", + "unifiedSearch.triggers.updateFilterReferencesTrigger": "更新筛选参考", + "unifiedSearch.triggers.updateFilterReferencesTriggerDescription": "更新筛选参考", + "textBasedEditor.query.textBasedLanguagesEditor.errorCount": "{count} 个{count, plural, other {错误}}", + "textBasedEditor.query.textBasedLanguagesEditor.lineCount": "{count} {count, plural, other {行}}", + "textBasedEditor.query.textBasedLanguagesEditor.lineNumber": "第 {lineNumber} 行", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.addOperator.markdown": "### Add (+)\n```\nSELECT 1 + 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.andOperator.markdown": "### AND\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no > 10000 AND emp_no < 10005 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.averageFunction.markdown": "### AVG\n返回输入值的算术平均值。\n```\nAVG(numeric_field)\n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n```\nSELECT AVG(salary) AS avg FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.between.markdown": "### Between\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no BETWEEN 9990 AND 10003 ORDER BY emp_no\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.comparison.markdown": "### Comparison (<, <=, >, >=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countAllFunction.markdown": "### Count (All)\n返回所有非 null 输入值的总数(计数)。COUNT() 与 COUNT(ALL ) 等价。\n\n```\nCOUNT(ALL field_name) \n```\n- 字段名称。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n```\nSELECT COUNT(ALL last_name) AS count_all, COUNT(DISTINCT last_name) count_distinct FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countDistinctFunction.markdown": "### Count (Distinct)\n返回输入值中的不同非 null 值的总数。\n\n```\nCOUNT(DISTINCT field_name)\n```\n- 输入:字段名称。\n- 输出:数字值。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n```\nSELECT COUNT(DISTINCT hire_date) unique_hires, COUNT(hire_date) AS hires FROM emp\n\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.countFunction.markdown": "### Count\n返回输入值的总数(计数)。\n\n\n```\nCOUNT(expression)\n```\n- 表达式为字段名称、通配符 (*) 或任何数字值。对于 COUNT(*) 或 COUNT(),将考虑所有值,包括 null 或缺失的值。对于 COUNT(),将不考虑 null 值。\n```\nSELECT COUNT(*) AS count FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.divideOperator.markdown": "### Divide (/)\n```\nSELECT 6 / 3 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.equality.markdown": "### Equality (=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no = 10000 LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.firstFunction.markdown": "### FIRST / FIRST_VALUE\n返回按 ordering_field_name 列排序的 field_name 输入列中的第一个非 null 值(如果存在)。如果未提供 ordering_field_name,则仅 field_name 列用于排序。\n\n```\nFIRST(\n field_name \n [, ordering_field_name])\n```\n- 字段名称:用于聚合的目标字段\n- ordering_field_name:用于排序的可选字段。\n\n```\nSELECT gender, FIRST(first_name, birth_date) FROM emp GROUP BY gender ORDER BY gender\n```\n\n- FIRST 不能用在 HAVING 子句中。\n- FIRST 不能用于文本类型的列,除非也将该字段另存为关键字。\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.inequality.markdown": "### Inequality (<> or !=)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no <> 10000 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.inOperator.markdown": "### IN (, , ...)\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IN (10000, 10001, 10002, 999) ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.kurtosisFunction.markdown": "### KURTOSIS\n量化字段 field_name 中输入值的分布形状。\n\n```\nKURTOSIS(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, KURTOSIS(salary) AS k FROM emp\n```\n\n- KURTOSIS 不能用于标量函数或运算符上面,而只能直接用于字段。 \n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.lastFunction.markdown": "### LAST / LAST_VALUE\n这是 FIRST/FIRST_VALUE 的反向函数。返回按 ordering_field_name 列降序排序的 field_name 输入列中的最后一个非 null 值(如果存在)。如果未提供 ordering_field_name,则仅 field_name 列用于排序。 \n\n```\nLAST(\n field_name \n [, ordering_field_name])\n```\n- 字段名称:用于聚合的目标字段\n- ordering_field_name:用于排序的可选字段。\n```\nSELECT gender, LAST(first_name) FROM emp GROUP BY gender ORDER BY gender\n```\n- LAST 不能用在 HAVING 子句中。\n- LAST 不能用于文本类型的列,除非也将该字段另存为关键字。\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.madFunction.markdown": "### MAD\n衡量字段 field_name 中输入值的可变性。\n\n```\nMAD(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, AVG(salary) AS avg, MAD(salary) AS mad FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.markdown": "## 关于 Elasticsearch SQL\n\n使用 Elasticsearch SQL 在 Elasticsearch 内部搜索并聚合数据。此查询语言通过熟悉的语法提供了全文本搜索。这里提供了一个查询示例:\n \n```\nSELECT * FROM library \nORDER BY page_count DESC LIMIT 5\n```\n \nElasticsearch SQL:\n\n- 提供了一组全面的内置运算符和函数。\n- 遵循 SQL 术语和约定。\n- 每行接受一个命令。命令指通过结束输入流终止的一连串令牌\n \n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.maxFunction.markdown": "### MAX\n返回字段 field_name 中所有输入值的最大值。\n\n```\nMAX(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MAX(salary) AS max FROM emp\n```\n\n- 类型为文本或关键字的字段的 MAX 将转换为 FIRST/FIRST_VALUE,因此不能用在 HAVING 子句中。\n\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.minFunction.markdown": "### MIN\n返回字段 field_name 中所有输入值的最小值。\n\n```\nMIN(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min FROM emp\n```\n\n- 类型为文本或关键字的字段的 MIN 将转换为 FIRST/FIRST_VALUE,因此不能用在 HAVING 子句中。\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.moduloOperator.markdown": "### Modulo or remainder(%)\n```\nSELECT 5 % 2 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.multiplyOperator.markdown": "### Multiply (*)\n```\nSELECT 2 * 3 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.negateOperator.markdown": "### Negate (unary -)\n```\nSELECT - 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.notOperator.markdown": "### NOT\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE NOT emp_no = 10000 LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullNotNull.markdown": "### IS NULL/IS NOT NULL\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no IS NOT NULL AND gender IS NULL\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.nullSafeEquality.markdown": "### Null safe equality:\n```\nSELECT 'elastic' <=> null AS \"equals\"\n\n 等于\n---------------\nfalse\n```\n```\nSELECT null <=> null AS \"equals\"\n\n 等于\n---------------\ntrue\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.orOperator.markdown": "### OR\n```\nSELECT last_name l FROM \"test_emp\" \nWHERE emp_no < 10003 OR emp_no = 10005 ORDER BY emp_no LIMIT 5\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileFunction.markdown": "### PERCENTILE\n返回字段 field_name 中输入值的第 n 个百分位(用 numeric_exp 参数表示)。\n\n```\nPERCENTILE(\n field_name, \n percentile[, \n method[, \n method_parameter]])\n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n- 百分位数:数字表达式(必须为常数并且不得基于字段)。如果为 null,该函数将返回 null。\n- 方法:百分位数算法的可选字符串文本。可能的值:tdigest 或 hdr。默认值为 tdigest。\n- method_parameter:配置百分位数算法的可选数字文本。为 tdigest 配置表达式,或为 hdr 配置 number_of_significant_value_digits。默认值与后备算法的默认值相同。\n\n```\n精选\n languages,\n PERCENTILE(salary, 97.3, 'tdigest', 100.0) AS \"97.3_TDigest\",\n PERCENTILE(salary, 97.3, 'hdr', 3) AS \"97.3_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.percentileRankFunction.markdown": "### PERCENTILE_RANK\n返回字段 field_name 中输入值的第 n 个百分位等级(用 numeric_exp 参数表示)。\n\n```\nPERCENTILE_RANK(\n field_name, \n value[, \n method[, \n method_parameter]]) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n- 百分位数:数字表达式(必须为常数并且不得基于字段)。如果为 null,该函数将返回 null。\n- 方法:百分位数算法的可选字符串文本。可能的值:tdigest 或 hdr。默认值为 tdigest。\n- method_parameter:配置百分位数算法的可选数字文本。为 tdigest 配置表达式,或为 hdr 配置 number_of_significant_value_digits。默认值与后备算法的默认值相同。\n\n```\n精选\n languages,\n ROUND(PERCENTILE_RANK(salary, 65000, 'tdigest', 100.0), 2) AS \"rank_TDigest\",\n ROUND(PERCENTILE_RANK(salary, 65000, 'hdr', 3), 2) AS \"rank_HDR\"\nFROM emp\nGROUP BY languages\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.skewnessFunction.markdown": "### SKEWNESS\n量化字段 field_name 中输入值的非对称分布。\n\n```\nSKEWNESS(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SKEWNESS(salary) AS s FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevpopFunction.markdown": "### STDDEV_POP\n返回字段 field_name 中输入值的填充标准偏差。\n\n```\nSTDDEV_POP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_POP(salary) AS stddev FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.stsdevsampFunction.markdown": "### STDDEV_SAMP\n返回字段 field_name 中输入值的样例标准偏差。\n\n```\nSTDDEV_SAMP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, STDDEV_SAMP(salary) AS stddev FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.subtractOperator.markdown": "### Subtract (infix -)\n```\nSELECT 1 - 1 AS x\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumFunction.markdown": "### SUM\n返回字段 field_name 中所有输入值的总和。\n\n```\nSUM(field_name) \n```\n- 数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT SUM(salary) AS sum FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.sumofsquaresFunction.markdown": "### SUM_OF_SQUARES\n返回字段 field_name 中输入值的平方和。\n\n```\nSUM_OF_SQUARES(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, SUM_OF_SQUARES(salary) AS sumsq\n FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.varpopFunction.markdown": "### VAR_POP\n返回字段 field_name 中输入值的总体方差。\n\n```\nVAR_POP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_POP(salary) AS varpop FROM emp\n```\n ", + "textBasedEditor.query.textBasedLanguagesEditor.documentation.varsampFunction.markdown": "### VAR_SAMP\n返回字段 field_name 中输入值的样例方差。\n\n```\nVAR_SAMP(field_name) \n```\n- field_name:数字字段。如果此字段仅包含 null 值,此函数将返回 null。否则,该函数将忽略此字段中的 null 值。\n\n```\nSELECT MIN(salary) AS min, MAX(salary) AS max, VAR_SAMP(salary) AS varsamp FROM emp\n```\n ", "textBasedEditor.query.textBasedLanguagesEditor.aggregateFunctions": "聚合函数", "textBasedEditor.query.textBasedLanguagesEditor.aggregateFunctionsDocumentationDescription": "用于从一组输入值计算单一结果的函数。Elasticsearch SQL 仅在与分组(隐式或显式)一起时才支持聚合函数。", "textBasedEditor.query.textBasedLanguagesEditor.comparisonOperators": "比较运算符", @@ -5964,28 +5986,6 @@ "textBasedEditor.query.textBasedLanguagesEditor.MinimizeEditor": "最小化编辑器", "textBasedEditor.query.textBasedLanguagesEditor.minimizeTooltip": "压缩查询编辑器", "textBasedEditor.query.textBasedLanguagesEditor.runQuery": "运行查询", - "unifiedSearch.queryBarTopRow.submitButton.refresh": "刷新查询", - "unifiedSearch.queryBarTopRow.submitButton.run": "运行查询", - "unifiedSearch.queryBarTopRow.submitButton.update": "需要更新", - "unifiedSearch.search.searchBar.savedQueryDescriptionText": "保存想要再次使用的查询文本和筛选。", - "unifiedSearch.search.searchBar.savedQueryForm.titleConflictText": "名称与现有查询有冲突", - "unifiedSearch.search.searchBar.savedQueryForm.titleExistsText": "“名称”必填。", - "unifiedSearch.search.searchBar.savedQueryFormSaveButtonText": "保存查询", - "unifiedSearch.search.searchBar.savedQueryIncludeFiltersLabelText": "包括筛选", - "unifiedSearch.search.searchBar.savedQueryIncludeTimeFilterLabelText": "包括时间筛选", - "unifiedSearch.search.searchBar.savedQueryNameHelpText": "名称不能包含前导或尾随空格,并且必须唯一。", - "unifiedSearch.search.searchBar.savedQueryNameLabelText": "名称", - "unifiedSearch.search.searchBar.savedQueryNoSavedQueriesText": "无已保存查询。", - "unifiedSearch.search.searchBar.savedQueryPopoverApplyFilterSetLabel": "加载查询", - "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionCancelButtonText": "取消", - "unifiedSearch.search.searchBar.savedQueryPopoverConfirmDeletionConfirmButtonText": "删除", - "unifiedSearch.search.searchBar.savedQueryPopoverManageLabel": "管理已保存对象", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonAriaLabel": "另存为新查询", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveAsNewButtonText": "另存为新的", - "unifiedSearch.search.searchBar.savedQueryPopoverSaveChangesButtonText": "更新查询", - "unifiedSearch.switchLanguage.buttonText": "切换语言按钮。", - "unifiedSearch.triggers.updateFilterReferencesTrigger": "更新筛选参考", - "unifiedSearch.triggers.updateFilterReferencesTriggerDescription": "更新筛选参考", "userProfileComponents.userProfilesSelectable.limitReachedMessage": "您已最多选择 {count, plural, other {# 个用户}}", "userProfileComponents.userProfilesSelectable.selectedStatusMessage": "{count, plural, other {# 个用户已选择}}", "userProfileComponents.userProfilesSelectable.clearButtonLabel": "移除所有用户", @@ -8761,8 +8761,6 @@ "xpack.apm.storageExplorer.summary.dailyDataGeneration": "每日数据生成", "xpack.apm.storageExplorer.summary.diskSpaceUsedPct": "已用磁盘空间", "xpack.apm.storageExplorer.summary.diskSpaceUsedPct.tooltip": "所有 APM 索引当前使用的存储容量与当前为 Elasticsearch 配置的最大存储容量比较的百分比。", - "xpack.apm.storageExplorer.summary.incrementalSize": "增量 APM 大小", - "xpack.apm.storageExplorer.summary.incrementalSize.tooltip": "APM 索引使用的估计存储大小(基于选定筛选)。", "xpack.apm.storageExplorer.summary.indexManagementLink": "前往索引管理", "xpack.apm.storageExplorer.summary.numberOfServices": "服务数目", "xpack.apm.storageExplorer.summary.serviceInventoryLink": "前往服务库存", @@ -8780,7 +8778,6 @@ "xpack.apm.storageExplorer.table.samplingColumnDescription": "已采样事务数除入总吞吐量。此值可能与配置的事务采样率不同,因为使用基于头部的采样时初始服务的决定或使用基于尾部的采样时的一组策略可能会对它造成影响。", "xpack.apm.storageExplorer.table.samplingColumnName": "采样速率", "xpack.apm.storageExplorer.table.serviceColumnName": "服务", - "xpack.apm.storageExplorerLinkLabel": "Storage Explorer", "xpack.apm.technicalPreviewBadgeDescription": "此功能处于技术预览状态,在未来版本中可能会更改或完全移除。Elastic 将尽最大努力来修复任何问题,但处于技术预览状态的功能不受正式 GA 功能支持 SLA 的约束。", "xpack.apm.technicalPreviewBadgeLabel": "技术预览", "xpack.apm.timeComparison.label": "对比", @@ -11262,7 +11259,6 @@ "xpack.csp.findings.findingsFlyout.overviewTab.ruleTagsTitle": "规则标签", "xpack.csp.findings.findingsFlyout.overviewTabTitle": "概览", "xpack.csp.findings.findingsFlyout.paginationLabel": "正在查找导航", - "xpack.csp.findings.findingsFlyout.resourceTabTitle": "资源", "xpack.csp.findings.findingsFlyout.ruleTab.auditTitle": "审计", "xpack.csp.findings.findingsFlyout.ruleTab.benchmarkTitle": "基准", "xpack.csp.findings.findingsFlyout.ruleTab.cisSectionTitle": "CIS 部分", @@ -11309,8 +11305,6 @@ "xpack.csp.fleetIntegration.integrationNameLabel": "名称", "xpack.csp.fleetIntegration.integrationSettingsTitle": "集成设置", "xpack.csp.fleetIntegration.selectIntegrationTypeTitle": "选择您要配置的安全态势管理集成的类型", - "xpack.csp.flyout.resource.fieldLabel": "字段", - "xpack.csp.flyout.resource.fieldValueLabel": "值", "xpack.csp.integrationDashboard.noFindings.promptTitle": "结果评估状态", "xpack.csp.integrationDashboard.noFindingsPrompt.promptDescription": "正在等待要收集和索引的数据。如果此进程花费的时间长于预期,请联系我们的支持人员", "xpack.csp.kspmIntegration.aksOption.benchmarkTitle": "CIS AKS", @@ -11372,7 +11366,6 @@ "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.dataSource": "数据源", "xpack.csp.vulnerabilities.vulnerabilityOverviewTile.publishedDate": "发布日期", "xpack.csp.vulnerabilityTable.column.fixVersion": "修复版本", - "xpack.csp.vulnerabilityTable.column.packageAndVersion": "软件包和版本", "xpack.csp.vulnerabilityTable.column.resource": "资源", "xpack.csp.vulnerabilityTable.column.severity": "严重性", "xpack.csp.vulnerabilityTable.column.vulnerability": "漏洞", @@ -37698,8 +37691,6 @@ "xpack.triggersActionsUI.checkActionTypeEnabled.actionTypeDisabledByLicenseMessage": "此连接器需要{minimumLicenseRequired}许可证。", "xpack.triggersActionsUI.checkRuleTypeEnabled.ruleTypeDisabledByLicenseMessage": "此规则类型需要{minimumLicenseRequired}许可证。", "xpack.triggersActionsUI.components.builtinActionTypes.missingSecretsValuesLabel": "未导入敏感信息。请为以下字段{encryptedFieldsLength, plural, other {s}} {secretFieldsLabel} 输入值{encryptedFieldsLength, plural, other {s}}。", - "xpack.triggersActionsUI.components.buttonGroupField.error.requiredField": "{label} 必填。", - "xpack.triggersActionsUI.components.passwordField.error.requiredNameText": "{label} 必填。", "xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesLabel": "记住您的 {secretFieldsLabel} {encryptedFieldsLength, plural, other {值}}。每次编辑连接器时都必须重新输入{encryptedFieldsLength, plural, other {这些值}}。", "xpack.triggersActionsUI.components.simpleConnectorForm.secrets.reenterValuesMessage": "值{encryptedFieldsLength, plural, other {s}} {secretFieldsLabel}{encryptedFieldsLength, plural, other { }}已加密。请为{encryptedFieldsLength, plural, other {这些}}字段{encryptedFieldsLength, plural, other {s}}重新输入值{encryptedFieldsLength, plural, other {s}}。", "xpack.triggersActionsUI.data.coreQueryParams.aggTypeRequiredErrorMessage": "[aggField]:当 [aggType] 为“{aggType}”时必须具有值", @@ -39741,4 +39732,4 @@ "xpack.painlessLab.title": "Painless 实验室", "xpack.painlessLab.walkthroughButtonLabel": "指导" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/button_group_field.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/button_group_field.tsx deleted file mode 100644 index 475329049d782..0000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/button_group_field.tsx +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, ReactNode } from 'react'; -import { EuiButtonGroup, EuiFormRow } from '@elastic/eui'; -import { - getFieldValidityAndErrorMessage, - UseField, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { i18n } from '@kbn/i18n'; - -const { emptyField } = fieldValidators; - -const getFieldConfig = ({ label, defaultValue }: { label: string; defaultValue?: string }) => ({ - label, - defaultValue, - validations: [ - { - validator: emptyField( - i18n.translate('xpack.triggersActionsUI.components.buttonGroupField.error.requiredField', { - values: { label }, - defaultMessage: '{label} is required.', - }) - ), - }, - ], -}); - -interface Props { - path: string; - label: string; - defaultValue?: string; - helpText?: string | ReactNode; - [key: string]: any; -} - -const ButtonGroupFieldComponent: React.FC = ({ - path, - label, - helpText, - defaultValue, - ...rest -}) => { - return ( - path={path} config={getFieldConfig({ label, defaultValue })}> - {(field) => { - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - - return ( - - - - ); - }} - - ); -}; - -export const ButtonGroupField = memo(ButtonGroupFieldComponent); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/hidden_field.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/hidden_field.tsx deleted file mode 100644 index 89385be8e5e1c..0000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/hidden_field.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo } from 'react'; -import { UseField, UseFieldProps } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; - -const HiddenFieldComponent = (props: UseFieldProps) => { - return ( - {...props}> - {(field) => { - /** - * This is a hidden field. We return null so we do not render - * any field on the form - */ - return null; - }} - - ); -}; - -export const HiddenField = memo(HiddenFieldComponent); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/index.ts index 08f1a600c58a9..41ca1f51c735a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/index.ts @@ -6,13 +6,10 @@ */ export { JsonEditorWithMessageVariables } from './json_editor_with_message_variables'; -export { HiddenField } from './hidden_field'; -export { PasswordField } from './password_field'; export { TextFieldWithMessageVariables } from './text_field_with_message_variables'; export { TextAreaWithMessageVariables } from './text_area_with_message_variables'; export { SimpleConnectorForm } from './simple_connector_form'; export type { ConfigFieldSchema, SecretsFieldSchema } from './simple_connector_form'; -export { ButtonGroupField } from './button_group_field'; export { JsonFieldWrapper } from './json_field_wrapper'; export { MustacheTextFieldWrapper } from './mustache_text_field_wrapper'; export { SectionLoading } from './section_loading'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/password_field.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/password_field.tsx deleted file mode 100644 index 841e1fe7b40f5..0000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/password_field.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { memo, ReactNode } from 'react'; -import { EuiFieldPassword, EuiFormRow } from '@elastic/eui'; -import { - getFieldValidityAndErrorMessage, - UseField, -} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { i18n } from '@kbn/i18n'; - -const { emptyField } = fieldValidators; - -const getFieldConfig = ({ label, validate }: { label: string; validate: boolean }) => ({ - label, - validations: [ - ...(validate - ? [ - { - validator: emptyField( - i18n.translate( - 'xpack.triggersActionsUI.components.passwordField.error.requiredNameText', - { - values: { label }, - defaultMessage: '{label} is required.', - } - ) - ), - }, - ] - : []), - ], -}); - -interface PasswordFieldProps { - path: string; - label: string; - helpText?: string | ReactNode; - validate?: boolean; - isLoading?: boolean; - [key: string]: any; -} - -const PasswordFieldComponent: React.FC = ({ - path, - label, - helpText, - validate = true, - isLoading, - ...rest -}) => { - return ( - path={path} config={getFieldConfig({ label, validate })}> - {(field) => { - const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - - return ( - - - - ); - }} - - ); -}; - -export const PasswordField = memo(PasswordFieldComponent); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/simple_connector_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/simple_connector_form.tsx index 9b538cd801e15..d552babfcab8d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/simple_connector_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/simple_connector_form.tsx @@ -7,11 +7,10 @@ import React, { memo, ReactNode } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; -import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { Field, PasswordField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { getUseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; import { i18n } from '@kbn/i18n'; -import { PasswordField } from './password_field'; export interface CommonFieldSchema { id: string; @@ -104,12 +103,17 @@ const FormRow: React.FC = ({ }} /> ) : ( - )} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields_global.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields_global.tsx index 3e26897111358..db0a23e0efcf4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields_global.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_form_fields_global.tsx @@ -9,11 +9,9 @@ import React, { memo } from 'react'; import { FieldConfig, UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components'; +import { Field, HiddenField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { i18n } from '@kbn/i18n'; -import { HiddenField } from '../../components/hidden_field'; - interface ConnectorFormData { name: string; } @@ -43,9 +41,9 @@ const nameConfig: FieldConfig<{ name: string }, ConnectorFormData> = { const ConnectorFormFieldsGlobalComponent: React.FC = ({ canSave }) => { return ( <> - - - + + + { it('should create a new index and pattern but not clobber an existing one', async () => { const resp = await supertest - .post(`/api/maps/docSource`) + .post(`/internal/maps/docSource`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'testing123', mappings: { properties: { coordinates: { type: 'geo_point' } } }, @@ -25,8 +27,9 @@ export default function ({ getService }) { // Repeated index fails. We don't want the user clobbering indexes await supertest - .post(`/api/maps/docSource`) + .post(`/internal/maps/docSource`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'testing123', mappings: { properties: { coordinates: { type: 'geo_point' } } }, @@ -36,8 +39,9 @@ export default function ({ getService }) { it('should fail to create index and pattern with invalid index', async () => { await supertest - .post(`/api/maps/docSource`) + .post(`/internal/maps/docSource`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: '_testing456', mappings: { properties: { coordinates: { type: 'geo_point' } } }, diff --git a/x-pack/test/api_integration/apis/maps/delete_feature.js b/x-pack/test/api_integration/apis/maps/delete_feature.js index 0755b1a1f6b59..7a1c536c65b56 100644 --- a/x-pack/test/api_integration/apis/maps/delete_feature.js +++ b/x-pack/test/api_integration/apis/maps/delete_feature.js @@ -5,14 +5,17 @@ * 2.0. */ +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + export default function ({ getService }) { const supertest = getService('supertest'); describe('doc feature deletion', () => { it('should delete a valid feature document', async () => { await supertest - .delete(`/api/maps/feature/999`) + .delete(`/internal/maps/feature/999`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'drawing_data', }) @@ -21,8 +24,9 @@ export default function ({ getService }) { it('previously deleted document no longer exists in index', async () => { await supertest - .delete(`/api/maps/feature/999`) + .delete(`/internal/maps/feature/999`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'drawing_data', }) @@ -31,8 +35,9 @@ export default function ({ getService }) { it('should fail if not a valid document', async () => { await supertest - .delete(`/api/maps/feature/998`) + .delete(`/internal/maps/feature/998`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'drawing_data', }) diff --git a/x-pack/test/api_integration/apis/maps/fonts_api.js b/x-pack/test/api_integration/apis/maps/fonts_api.js index 35017e6e37db8..c8c636e8f6ddc 100644 --- a/x-pack/test/api_integration/apis/maps/fonts_api.js +++ b/x-pack/test/api_integration/apis/maps/fonts_api.js @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import path from 'path'; import { copyFile, rm } from 'fs/promises'; @@ -35,7 +36,8 @@ export default function ({ getService }) { it('should return fonts', async () => { const resp = await supertest - .get(`/api/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/0-255`) + .get(`/internal/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/0-255`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .expect(200); expect(resp.body.length).to.be(74696); @@ -43,16 +45,25 @@ export default function ({ getService }) { it('should return 404 when file not found', async () => { await supertest - .get(`/api/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/noGonaFindMe`) + .get( + `/internal/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/noGonaFindMe` + ) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .expect(404); }); it('should return 404 when file is not in font folder (..)', async () => { - await supertest.get(`/api/maps/fonts/open_sans/..%2f0-255`).expect(404); + await supertest + .get(`/internal/maps/fonts/open_sans/..%2f0-255`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .expect(404); }); it('should return 404 when file is not in font folder (./..)', async () => { - await supertest.get(`/api/maps/fonts/open_sans/.%2f..%2f0-255`).expect(404); + await supertest + .get(`/internal/maps/fonts/open_sans/.%2f..%2f0-255`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .expect(404); }); }); } diff --git a/x-pack/test/api_integration/apis/maps/get_grid_tile.js b/x-pack/test/api_integration/apis/maps/get_grid_tile.js index b03904204c194..5b44b43e50e43 100644 --- a/x-pack/test/api_integration/apis/maps/get_grid_tile.js +++ b/x-pack/test/api_integration/apis/maps/get_grid_tile.js @@ -9,6 +9,7 @@ import { VectorTile } from '@mapbox/vector-tile'; import Protobuf from 'pbf'; import expect from '@kbn/expect'; import { getTileUrlParams } from '@kbn/maps-vector-tile-utils'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; function findFeature(layer, callbackFn) { for (let i = 0; i < layer.length; i++) { @@ -71,8 +72,9 @@ export default function ({ getService }) { it('should return vector tile with expected headers', async () => { const resp = await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams)) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams)) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -84,8 +86,9 @@ export default function ({ getService }) { it('should return vector tile containing clusters when renderAs is "point"', async () => { const resp = await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams)) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams)) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -114,8 +117,9 @@ export default function ({ getService }) { renderAs: 'heatmap', }); const resp = await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -144,8 +148,9 @@ export default function ({ getService }) { renderAs: 'grid', }); const resp = await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -181,8 +186,9 @@ export default function ({ getService }) { renderAs: 'hex', }); const resp = await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -221,8 +227,9 @@ export default function ({ getService }) { renderAs: 'hex', }); const resp = await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -248,8 +255,9 @@ export default function ({ getService }) { it('should return vector tile with meta layer', async () => { const resp = await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams)) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams)) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -293,8 +301,9 @@ export default function ({ getService }) { index: 'notRealIndex', }); await supertest - .get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) + .get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(404); }); diff --git a/x-pack/test/api_integration/apis/maps/get_indexes_matching_pattern.js b/x-pack/test/api_integration/apis/maps/get_indexes_matching_pattern.js index 0ff491d8fd672..c9cb98389c9b7 100644 --- a/x-pack/test/api_integration/apis/maps/get_indexes_matching_pattern.js +++ b/x-pack/test/api_integration/apis/maps/get_indexes_matching_pattern.js @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -13,8 +14,9 @@ export default function ({ getService }) { describe('get matching index patterns', () => { it('should return an array containing indexes matching pattern', async () => { const resp = await supertest - .get(`/api/maps/getMatchingIndexes?indexPattern=geo_shapes`) + .get(`/internal/maps/getMatchingIndexes?indexPattern=geo_shapes`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send() .expect(200); @@ -24,8 +26,9 @@ export default function ({ getService }) { it('should return an empty array when no indexes match pattern', async () => { const resp = await supertest - .get(`/api/maps/getMatchingIndexes?indexPattern=notAnIndex`) + .get(`/internal/maps/getMatchingIndexes?indexPattern=notAnIndex`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send() .expect(200); diff --git a/x-pack/test/api_integration/apis/maps/get_tile.js b/x-pack/test/api_integration/apis/maps/get_tile.js index b7acb7f4932f2..8b466fe1554b5 100644 --- a/x-pack/test/api_integration/apis/maps/get_tile.js +++ b/x-pack/test/api_integration/apis/maps/get_tile.js @@ -8,6 +8,7 @@ import { VectorTile } from '@mapbox/vector-tile'; import Protobuf from 'pbf'; import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { getTileUrlParams } from '@kbn/maps-vector-tile-utils'; function findFeature(layer, callbackFn) { @@ -71,8 +72,9 @@ export default function ({ getService }) { it('should return ES vector tile containing documents and metadata', async () => { const resp = await supertest - .get(`/api/maps/mvt/getTile/2/1/1.pbf?${getTileUrlParams(defaultParams)}`) + .get(`/internal/maps/mvt/getTile/2/1/1.pbf?${getTileUrlParams(defaultParams)}`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -133,8 +135,9 @@ export default function ({ getService }) { hasLabels: true, }); const resp = await supertest - .get(`/api/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`) + .get(`/internal/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(200); @@ -176,8 +179,9 @@ export default function ({ getService }) { index: 'notRealIndex', }); await supertest - .get(`/api/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`) + .get(`/internal/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .responseType('blob') .expect(404); }); diff --git a/x-pack/test/api_integration/apis/maps/index_data.js b/x-pack/test/api_integration/apis/maps/index_data.js index f7c595537f612..987570dc1cb6c 100644 --- a/x-pack/test/api_integration/apis/maps/index_data.js +++ b/x-pack/test/api_integration/apis/maps/index_data.js @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -13,16 +14,18 @@ export default function ({ getService }) { describe('index feature data', () => { it('should add point data to an existing index', async () => { await supertest - .post(`/api/maps/docSource`) + .post(`/internal/maps/docSource`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'new-point-feature-index', mappings: { properties: { coordinates: { type: 'geo_point' } } }, }); const resp = await supertest - .post(`/api/maps/feature`) + .post(`/internal/maps/feature`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'new-point-feature-index', data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' }, @@ -34,16 +37,18 @@ export default function ({ getService }) { it('should add shape data to an existing index', async () => { await supertest - .post(`/api/maps/docSource`) + .post(`/internal/maps/docSource`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'new-shape-feature-index', mappings: { properties: { coordinates: { type: 'geo_shape' } } }, }); const resp = await supertest - .post(`/api/maps/feature`) + .post(`/internal/maps/feature`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'new-shape-feature-index', data: { @@ -68,15 +73,17 @@ export default function ({ getService }) { it('should fail if data is invalid', async () => { await supertest - .post(`/api/maps/docSource`) + .post(`/internal/maps/docSource`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'new-feature-index2', mappings: { properties: { coordinates: { type: 'geo_point' } } }, }); await supertest - .post(`/api/maps/feature`) + .post(`/internal/maps/feature`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'new-feature-index2', data: { coordinates: [600, 800], name: 'Never Gonna Happen Islands' }, @@ -86,8 +93,9 @@ export default function ({ getService }) { it('should fail if index does not exist', async () => { await supertest - .post(`/api/maps/feature`) + .post(`/internal/maps/feature`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'not-an-index', data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' }, diff --git a/x-pack/test/api_integration/apis/maps/index_settings.js b/x-pack/test/api_integration/apis/maps/index_settings.js index 375b2e7eb21a0..032f530226c37 100644 --- a/x-pack/test/api_integration/apis/maps/index_settings.js +++ b/x-pack/test/api_integration/apis/maps/index_settings.js @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -13,8 +14,9 @@ export default function ({ getService }) { describe('index settings', () => { it('should return default index settings when max_result_window and max_inner_result_window are not set', async () => { const resp = await supertest - .get(`/api/maps/indexSettings?indexPatternTitle=logstash*`) + .get(`/internal/maps/indexSettings?indexPatternTitle=logstash*`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .expect(200); expect(resp.body.maxResultWindow).to.be(10000); @@ -23,8 +25,9 @@ export default function ({ getService }) { it('should return index settings', async () => { const resp = await supertest - .get(`/api/maps/indexSettings?indexPatternTitle=geo_shape*`) + .get(`/internal/maps/indexSettings?indexPatternTitle=geo_shape*`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .expect(200); expect(resp.body.maxResultWindow).to.be(10001); diff --git a/x-pack/test/api_integration/apis/maps/validate_drawing_index.js b/x-pack/test/api_integration/apis/maps/validate_drawing_index.js index 491847c37be6d..37260ee6cb0f7 100644 --- a/x-pack/test/api_integration/apis/maps/validate_drawing_index.js +++ b/x-pack/test/api_integration/apis/maps/validate_drawing_index.js @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -13,16 +14,18 @@ export default function ({ getService }) { describe('validate drawing index', () => { it('confirm valid drawing index', async () => { await supertest - .post(`/api/maps/docSource`) + .post(`/internal/maps/docSource`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .send({ index: 'valid-drawing-index', mappings: { properties: { coordinates: { type: 'geo_point' } } }, }); const resp = await supertest - .get(`/api/maps/checkIsDrawingIndex?index=valid-drawing-index`) + .get(`/internal/maps/checkIsDrawingIndex?index=valid-drawing-index`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .expect(200); expect(resp.body.success).to.be(true); @@ -31,8 +34,9 @@ export default function ({ getService }) { it('confirm valid index that is not a drawing index', async () => { const resp = await supertest - .get(`/api/maps/checkIsDrawingIndex?index=geo_shapes`) + .get(`/internal/maps/checkIsDrawingIndex?index=geo_shapes`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .expect(200); expect(resp.body.success).to.be(true); @@ -41,8 +45,9 @@ export default function ({ getService }) { it('confirm invalid index', async () => { const resp = await supertest - .get(`/api/maps/checkIsDrawingIndex?index=not-an-index`) + .get(`/internal/maps/checkIsDrawingIndex?index=not-an-index`) .set('kbn-xsrf', 'kibana') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') .expect(200); expect(resp.body.success).to.be(false); diff --git a/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js b/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js index 42b49b059d9fb..081a1a41a93df 100644 --- a/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js +++ b/x-pack/test/functional/apps/maps/group4/mvt_geotile_grid.js @@ -37,7 +37,9 @@ export default function ({ getPageObjects, getService }) { ); const searchParams = Object.fromEntries(tileUrl.searchParams); - expect(tileUrl.pathname).to.equal('/api/maps/mvt/getGridTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf'); + expect(tileUrl.pathname).to.equal( + '/internal/maps/mvt/getGridTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf' + ); // token is an unique id that changes between runs expect(typeof searchParams.token).to.equal('string'); diff --git a/x-pack/test/functional/apps/maps/group4/mvt_scaling.js b/x-pack/test/functional/apps/maps/group4/mvt_scaling.js index 7bdcae9500b7e..cd779392ba821 100644 --- a/x-pack/test/functional/apps/maps/group4/mvt_scaling.js +++ b/x-pack/test/functional/apps/maps/group4/mvt_scaling.js @@ -35,14 +35,14 @@ export default function ({ getPageObjects, getService }) { mapboxStyle = await PageObjects.maps.getMapboxStyle(); }); - it('should request tiles from /api/maps/mvt/getTile', async () => { + it('should request tiles from /internal/maps/mvt/getTile', async () => { const tileUrl = new URL( mapboxStyle.sources[VECTOR_SOURCE_ID].tiles[0], 'http://absolute_path' ); const searchParams = Object.fromEntries(tileUrl.searchParams); - expect(tileUrl.pathname).to.equal('/api/maps/mvt/getTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf'); + expect(tileUrl.pathname).to.equal('/internal/maps/mvt/getTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf'); // token is an unique id that changes between runs expect(typeof searchParams.token).to.equal('string'); diff --git a/x-pack/test/functional/apps/spaces/spaces_selection.ts b/x-pack/test/functional/apps/spaces/spaces_selection.ts index df02411b2126e..f3932e9d48346 100644 --- a/x-pack/test/functional/apps/spaces/spaces_selection.ts +++ b/x-pack/test/functional/apps/spaces/spaces_selection.ts @@ -59,7 +59,8 @@ export default function spaceSelectorFunctionalTests({ }); }); - describe('Space Navigation Menu', () => { + // FLAKY: https://github.com/elastic/kibana/issues/157760 + describe.skip('Space Navigation Menu', () => { before(async () => { await PageObjects.security.forceLogout(); await PageObjects.security.login(undefined, undefined, { diff --git a/x-pack/test/observability_functional/apps/observability/feature_controls/observability_security.ts b/x-pack/test/observability_functional/apps/observability/feature_controls/observability_security.ts index 703a77c938839..6f6b02217e06c 100644 --- a/x-pack/test/observability_functional/apps/observability/feature_controls/observability_security.ts +++ b/x-pack/test/observability_functional/apps/observability/feature_controls/observability_security.ts @@ -36,7 +36,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await kibanaServer.uiSettings.update(config.get('uiSettings.defaults')); }); - describe('observability cases all privileges', () => { + // FLAKY: https://github.com/elastic/kibana/issues/155090 + // FLAKY: https://github.com/elastic/kibana/issues/155091 + describe.skip('observability cases all privileges', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); await observability.users.setTestUserRole( diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index 9c59aa319595b..d01f869e285e9 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -24,6 +24,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const policyTestResources = getService('policyTestResources'); const endpointTestResources = getService('endpointTestResources'); + const retry = getService('retry'); describe('When on the Endpoint Policy Details Page', function () { let indexedData: IndexedHostsAndAlertsResponse; @@ -47,8 +48,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/154182 - describe.skip('with a valid policy id', () => { + describe('with a valid policy id', () => { let policyInfo: PolicyTestResourceInfo; before(async () => { @@ -63,6 +63,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('should display policy view', async () => { + this.timeout(150_000); + await retry.waitForWithTimeout('policy title is not empty', 120_000, async () => { + return (await testSubjects.getVisibleText('header-page-title')) !== ''; + }); expect(await testSubjects.getVisibleText('header-page-title')).to.equal( policyInfo.packagePolicy.name ); @@ -81,47 +85,79 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('on the Malware protections section', () => { - let policyInfo: PolicyTestResourceInfo; + ['malware', 'ransomware'].forEach((protection) => { + describe(`on the ${protection} protections section`, () => { + let policyInfo: PolicyTestResourceInfo; - beforeEach(async () => { - policyInfo = await policyTestResources.createPolicy(); - await pageObjects.policy.navigateToPolicyDetails(policyInfo.packagePolicy.id); - await testSubjects.existOrFail('malwareProtectionsForm'); - }); + beforeEach(async () => { + policyInfo = await policyTestResources.createPolicy(); + await pageObjects.policy.navigateToPolicyDetails(policyInfo.packagePolicy.id); + await testSubjects.existOrFail(`${protection}ProtectionsForm`); + }); - afterEach(async () => { - if (policyInfo) { - await policyInfo.cleanup(); - } - }); + afterEach(async () => { + if (policyInfo) { + await policyInfo.cleanup(); + } + }); - it('should show the supported Endpoint version', async () => { - expect(await testSubjects.getVisibleText('policySupportedVersions')).to.equal( - 'Agent version ' + popupVersionsMap.get('malware') - ); - }); + it('should show the supported Endpoint version', async () => { + const supportedVersionElement = await testSubjects.findDescendant( + 'policySupportedVersions', + await testSubjects.find(`${protection}ProtectionsForm`) + ); - it('should show the custom message text area when the Notify User checkbox is checked', async () => { - expect(await testSubjects.isChecked('malwareUserNotificationCheckbox')).to.be(true); - await testSubjects.existOrFail('malwareUserNotificationCustomMessage'); - }); + expect(await supportedVersionElement.getVisibleText()).to.equal( + 'Agent version ' + popupVersionsMap.get(protection) + ); + }); - it('should not show the custom message text area when the Notify User checkbox is unchecked', async () => { - await pageObjects.endpointPageUtils.clickOnEuiCheckbox('malwareUserNotificationCheckbox'); - expect(await testSubjects.isChecked('malwareUserNotificationCheckbox')).to.be(false); - await testSubjects.missingOrFail('malwareUserNotificationCustomMessage'); - }); + it('should show the custom message text area when the Notify User checkbox is checked', async () => { + expect(await testSubjects.isChecked(`${protection}UserNotificationCheckbox`)).to.be(true); + await testSubjects.existOrFail(`${protection}UserNotificationCustomMessage`); + }); - it('should preserve a custom notification message upon saving', async () => { - const customMessage = await testSubjects.find('malwareUserNotificationCustomMessage'); - await customMessage.clearValue(); - await customMessage.type('a custom malware notification message'); - await pageObjects.policy.confirmAndSave(); - await testSubjects.existOrFail('policyDetailsSuccessMessage'); - expect(await testSubjects.getVisibleText('malwareUserNotificationCustomMessage')).to.equal( - 'a custom malware notification message' - ); + it('should not show the custom message text area when the Notify User checkbox is unchecked', async () => { + await pageObjects.endpointPageUtils.clickOnEuiCheckbox( + `${protection}UserNotificationCheckbox` + ); + expect(await testSubjects.isChecked(`${protection}UserNotificationCheckbox`)).to.be( + false + ); + await testSubjects.missingOrFail(`${protection}UserNotificationCustomMessage`); + }); + + it('should show a sample custom message', async () => { + const customMessageBox = await testSubjects.find( + `${protection}UserNotificationCustomMessage` + ); + expect(await customMessageBox.getVisibleText()).equal( + 'Elastic Security {action} {filename}' + ); + }); + + it('should show a tooltip ', async () => { + const malwareTooltipIcon = await testSubjects.find(`${protection}TooltipIcon`); + await malwareTooltipIcon.moveMouseTo(); + + const malwareTooltip = await testSubjects.find(`${protection}Tooltip`); + expect(await malwareTooltip.getVisibleText()).equal( + `Selecting the user notification option will display a notification to the host user when ${protection} is prevented or detected.\nThe user notification can be customized in the text box below. Bracketed tags can be used to dynamically populate the applicable action (such as prevented or detected) and the filename.` + ); + }); + + it('should preserve a custom notification message upon saving', async () => { + const customMessageBox = await testSubjects.find( + `${protection}UserNotificationCustomMessage` + ); + await customMessageBox.clearValue(); + await customMessageBox.type('a custom notification message @$% 123'); + await pageObjects.policy.confirmAndSave(); + await testSubjects.existOrFail('policyDetailsSuccessMessage'); + expect( + await testSubjects.getVisibleText(`${protection}UserNotificationCustomMessage`) + ).to.equal('a custom notification message @$% 123'); + }); }); }); diff --git a/x-pack/test_serverless/README.md b/x-pack/test_serverless/README.md index 9ee6ab373c573..43873a7d6e835 100644 --- a/x-pack/test_serverless/README.md +++ b/x-pack/test_serverless/README.md @@ -52,7 +52,7 @@ Serverless specific services and page objects are implemented in to or make modifications in `x-pack/test`. With this helper method reuse, we have to avoid name clashes and go with the -following namesapces: +following namespaces: | project | namespace for helper methods | | ------------- | ---------------------------- | @@ -64,9 +64,9 @@ following namesapces: ### Adding Serverless Tests As outlined above, serverless tests are separated from stateful tests (except -the reuse helper methods), which includes a separate base configuration. All -tests that should run in an serverless environment have to be added here in -`x-pack/test_serverless`. +the reuse of helper methods), which includes a new base configuration. All +tests that should run in a serverless environment have to be added to, in the +`x-pack/test_serverless` directory. Tests in this area should be clearly designed for the serverless environment, particularly when it comes to timing for API requests and UI interaction. @@ -79,4 +79,4 @@ directory, e.g. from the `x-pack` directory run: node scripts/functional_tests_server.js --config test_serverless/api_integration/test_suites/common/config.ts node scripts/functional_test_runner.js --config test_serverless/api_integration/test_suites/common/config.ts -``` \ No newline at end of file +``` diff --git a/yarn.lock b/yarn.lock index 7b1c44ecb0392..3e848adce6f8e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1515,10 +1515,10 @@ "@elastic/transport" "^8.3.1" tslib "^2.4.0" -"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@8.6.0-canary.3": - version "8.6.0-canary.3" - resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-8.6.0-canary.3.tgz#dc518f5ae4bb502b08ff70e4d86fa7b859b3cbe3" - integrity sha512-NvTZrRT/d5mJZ46pDlbgdKVIhA7ac504IGVaf7OV/7wHDmXjm8d/cG2UeQd8v37zMplGq2/853uFWGlXXjD0lQ== +"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@8.8.0-canary.2": + version "8.8.0-canary.2" + resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-8.8.0-canary.2.tgz#10b5699541d644797b33c7e24058d2e55367d88d" + integrity sha512-UxH8YUxcsqHXGh4t2PjuL0q03XunF9vCLHPAs9r+fQcaPXpNbEuv9jbNGXv/9TLyeAKYEgcq9Xm0p0Nk/Mh0lQ== dependencies: "@elastic/transport" "^8.3.1" tslib "^2.4.0"